with Io;
with Directory_Tools;
package body Closure is
    package Traversal renames Directory_Tools.Traversal;
    package Naming renames Directory_Tools.Naming;
    package Ada_Object renames Directory_Tools.Ada_Object;

    type State is new Boolean;

    procedure Family_Op (S : in out State;
                         Obj : Object.Handle;
                         Iter : out Object.Iterator;
                         Status : out Object.Error_Code;
                         Control : in out Traversal.Control_Enumeration) is
        Local : Object.Iterator := Object.Create;
        The_Body : Object.Handle;
        Dup : Boolean;
    begin
        if Ada_Object.Is_Visible_Part (Obj) then
            The_Body := Ada_Object.Other_Part (Obj);
            if not Object.Is_Bad (The_Body) then
                Object.Add (Local, The_Body, Dup);
            end if;
        else
            Local := Ada_Object.Subunits (Obj);
        end if;
        Status := Object.Err_Code (Local);
        Iter := Local;
    end Family_Op;

    procedure Family_Closure is new Traversal.Closure (State, Family_Op);

    function Family (Obj : Object.Handle) return Object.Iterator is
        In_Iter : Object.Iterator := Object.Create;
        Closure : Object.Iterator;
        Dup : Boolean;
        Stat : State := True;
        Status : Object.Error_Code;
    begin
        Object.Add (In_Iter, Obj, Dup);
        Family_Closure (Stat, In_Iter, Closure, Status);
        return Closure;
    end Family;

    procedure Op (S : in out State;
                  Obj : Object.Handle;
                  Iter : out Object.Iterator;
                  Status : out Object.Error_Code;
                  Control : in out Traversal.Control_Enumeration) is
        Local : Object.Iterator := Object.Create;
        The_Body : Object.Handle;
        Dup : Boolean;
    begin
        if Ada_Object.Is_Visible_Part (Obj) then
            Local := Ada_Object.Depends_On (Obj);
            The_Body := Ada_Object.Other_Part (Obj);
            if not Object.Is_Bad (The_Body) then
                Object.Add (Local, The_Body, Dup);
            end if;
        else
            Local := Ada_Object.Subunits (Obj);
        end if;
        Status := Object.Err_Code (Local);
        Iter := Local;
    end Op;

    procedure Get_Closure is new Traversal.Closure (State, Op);

    function Dependency_Closure (Obj : Object.Handle) return Object.Iterator is
        In_Iter : Object.Iterator := Object.Create;
        Closure : Object.Iterator;
        Dup : Boolean;
        Stat : State := True;
        Status : Object.Error_Code;
    begin
        Object.Add (In_Iter, Obj, Dup);
        Get_Closure (Stat, In_Iter, Closure, Status);
        return Closure;
    end Dependency_Closure;

    procedure Print (Iter : in out Object.Iterator) is
    begin
        while not Object.Done (Iter) loop
            Io.Put_Line (Naming.Unique_Full_Name (Object.Value (Iter)));
            Object.Next (Iter);
        end loop;
    end Print;
end Closure;