with String_Utilities;
with Calendar;
with Time_Utilities;
with Io;
package body Changed_Units is

    package Naming renames Directory_Tools.Naming;
    package Traversal renames Directory_Tools.Traversal;
    package Statistics renames Directory_Tools.Statistics;
    package Sio renames Io;

    Is_In_Units : Boolean;

    procedure Is_In (Iter : in out Object.Iterator;
                     Obj : Object.Handle;
                     Has : out Boolean) is

    begin
        while not Object.Done (Iter) loop
            if String_Utilities.Equal
                  (Naming.Unique_Full_Name (Object.Value (Iter)),
                   Naming.Unique_Full_Name (Obj)) then
                Object.Reset (Iter);
                Has := True;
                return;
            end if;
            Object.Next (Iter);
        end loop;
        Object.Reset (Iter);
        Has := False;
        return;
    end Is_In;

    procedure Initialize (World : String := "$$") is
        File : Sio.File_Type;

        The_World : Object.Handle := Naming.Resolution (World);

        Units : Object.Iterator :=
           Naming.Resolution (Naming.Full_Name (The_World) & ".?'c(ada)");

        Change_Filename : constant String :=
           Naming.Full_Name (The_World) & ".changed_units";

    begin
        Sio.Create (File, Sio.Out_File, Change_Filename);

        Sio.Put_Line (File, Time_Utilities.Image
                               (Time_Utilities.Get_Time,
                                Date_Style => Time_Utilities.Month_Day_Year,
                                Time_Style => Time_Utilities.Military,
                                Contents => Time_Utilities.Both));

        while not Object.Done (Units) loop
            Sio.Put_Line (File, Naming.Unique_Full_Name (Object.Value (Units)));
            Object.Next (Units);
        end loop;

        Sio.Close (File);
    end Initialize;

    function New_Or_Changed_Units
                (In_World : String := "$$"; Update : Boolean := True)
                return Object.Iterator is

        File : Sio.File_Type;

        The_World : Object.Handle := Naming.Resolution (In_World);

        New_Units : Object.Iterator :=
           Naming.Resolution (Naming.Full_Name (The_World) & ".?'c(ada)");

        Change_Filename : constant String :=
           Naming.Full_Name (The_World) & ".changed_units";

        Last_File_Update : Calendar.Time;

        Old_Units : Object.Iterator := Object.Create;
        Out_Iter : Object.Iterator := Object.Create;

        This_Object : Object.Handle;
        Duplicate : Boolean;
    begin
        Sio.Open (File, Sio.In_File, Change_Filename);

        Last_File_Update := Time_Utilities.Convert_Time
                               (Time_Utilities.Value (Sio.Get_Line (File)));

        while not Sio.End_Of_File (File) loop
            This_Object := Naming.Resolution (Sio.Get_Line (File));

            if not Object.Is_Bad (This_Object) then
                Object.Add (Old_Units, This_Object, Duplicate);
            end if;

        end loop;

        Sio.Close (File);

        while not Object.Done (New_Units) loop

            This_Object := Object.Value (New_Units);

            Is_In (Old_Units, This_Object, Is_In_Units);
            if Is_In_Units then
                if Calendar.">" (Statistics.Time_Of_Last_Update (This_Object),
                                 Last_File_Update) then

                    Object.Add (Out_Iter, This_Object, Duplicate);
                end if;
            else
                Object.Add (Out_Iter, This_Object, Duplicate);
            end if;
            Object.Next (New_Units);
        end loop;

        if Update then
            Initialize (In_World);
        end if;

        return Out_Iter;

    end New_Or_Changed_Units;
end Changed_Units;