with String_Utilities;
with Io;
package body Definitions is
    package Sio renames Io;

    type Possible_State is (Start, Found_Begin_Title_Delim,
                            Found_End_Title_Delim, Found_Title,
                            Found_Step_Delim, Found_Step_Text);

    function Transpose (Module_List : Module.List) return Module.List is
        Iter : Module.Iterator;
        Return_List : Module.List;
    begin
        Module.Init (Iter, Module_List);

        while not Module.Done (Iter) loop
            Return_List := Module.Make (Module.Value (Iter), Return_List);
            Module.Next (Iter);
        end loop;

        return Return_List;
    end Transpose;

    function Transpose (Lines_List : Lines.List) return Lines.List is
        Iter : Lines.Iterator;
        Return_List : Lines.List;
    begin
        Lines.Init (Iter, Lines_List);

        while not Lines.Done (Iter) loop
            Return_List := Lines.Make (Lines.Value (Iter), Return_List);
            Lines.Next (Iter);
        end loop;

        return Return_List;
    end Transpose;

    function Transpose (Step_List : Step.List) return Step.List is
        Iter : Step.Iterator;
        Return_List : Step.List;
    begin
        Step.Init (Iter, Step_List);

        while not Step.Done (Iter) loop
            Return_List := Step.Make (Step.Value (Iter), Return_List);
            Step.Next (Iter);
        end loop;

        return Return_List;
    end Transpose;

    procedure Initialize (File_Name : String) is
        File : Sio.File_Type;
        State : Possible_State := Start;
        L : Line;
        A_Step : Lines.List;
        This_Module : Module_Information;

    begin
        All_Modules := Module.Nil;

        loop
            begin
                Sio.Open (File, Sio.In_File, File_Name);
                exit;
            exception
                when Sio.Use_Error =>
                    delay 3.0;
            end;
        end loop;

        loop
            case State is
                when Found_Step_Delim | Found_Step_Text =>
                    Bounded_String.Copy (L, Sio.Get_Line (File));
                when others =>
                    Bounded_String.Copy (L, String_Utilities.Strip
                                               (Sio.Get_Line (File)));

            end case;

            case State is
                when Start =>
                    if Bounded_String.Image (L) = ".;." then
                        State := Found_Begin_Title_Delim;
                    end if;
                when Found_Begin_Title_Delim =>
                    if Bounded_String.Image (L) = "" then
                        null;
                    elsif Bounded_String.Image (L) = ".;." then
                        raise Unable_To_Parse;
                    elsif Bounded_String.Image (L) = ";.;" then
                        raise Unable_To_Parse;
                    else
                        This_Module.Name := L;
                        This_Module.Module := Step.Nil;
                        State := Found_Title;
                    end if;
                when Found_Title =>
                    if Bounded_String.Image (L) = "" then
                        null;
                    elsif Bounded_String.Image (L) = ".;." then
                        State := Found_End_Title_Delim;
                    elsif Bounded_String.Image (L) = ";.;" then
                        raise Unable_To_Parse;
                    else
                        raise Unable_To_Parse;
                    end if;

                when Found_End_Title_Delim =>
                    if Bounded_String.Image (L) = ";.;" then
                        State := Found_Step_Delim;
                    elsif Bounded_String.Image (L) = "" then
                        null;
                    else
                        raise Unable_To_Parse;
                    end if;
                when Found_Step_Delim =>
                    if Bounded_String.Image (L) = "" then
                        null;
                    elsif Bounded_String.Image (L) = ".;." then
                        This_Module.Module := Transpose (This_Module.Module);
                        All_Modules := Module.Make (This_Module, All_Modules);
                        State := Found_Begin_Title_Delim;
                    elsif Bounded_String.Image (L) = ";.;" then
                        null;
                    else
                        A_Step := Lines.Make (L, Lines.Nil);
                        State := Found_Step_Text;
                    end if;

                when Found_Step_Text =>
                    if Bounded_String.Image (L) = ".;." then
                        raise Unable_To_Parse;
                    elsif Bounded_String.Image (L) = ";.;" then
                        This_Module.Module :=
                           Step.Make (Transpose (A_Step), This_Module.Module);
                        State := Found_Step_Delim;
                    else
                        A_Step := Lines.Make (L, A_Step);
                    end if;
            end case;
        end loop;
    exception
        when Sio.End_Error =>
            This_Module.Module := Transpose (This_Module.Module);
            All_Modules := Transpose (Module.Make (This_Module, All_Modules));
            Sio.Close (File);
    end Initialize;
end Definitions;
