with Text_Io;
use Text_Io;
with Type_Definitions;
use Type_Definitions;
with Command_Line_Interface;
use Command_Line_Interface;
with String_Pkg;
use String_Pkg;
with File_Manager;
with Adapathr;
with Source_Instrument;
with Smart_Pkg;
with Profile_Pkg;

procedure Test_Tools is

    package Int_Io is new Integer_Io (Integer);

    type Command_Type is (Path, Profile, Smart, Source_Instrument,
                          Autopath, Unknown, Help, Quit);
    Command : Command_Type := Unknown;
    Maxline : Integer := 80;
    Blanks : String (1 .. Maxline) := (others => ' ');
    Command_Line : String (1 .. Maxline);
    Command_Index : Positive;
    End_Index : Positive;
    Argument_String : String (1 .. Maxline);
    Line_Length : Integer := 80;
    Named_Count : Argument_Count := 0;
    Positional_Count : Argument_Count := 0;
    Log_File : Filename;
    Report_File : Filename;
    Source_File : Filename;
    Source_Listing : Filename;
    Instrumented_Source : Filename;
    Autopath_Log : String (1 .. 12) := "autopath.log";
    Autopath_Logfile : File_Type;

    function Convert_To_Upper_Case
                ( --| Change character to upper case
                 C : in Character) --| character to be converted
                return Character --| resulting character
                 is
    begin
        if C in 'a' .. 'z' then
            return Character'Val (Character'Pos (C) - 32);
        else
            return C;
        end if;
    end Convert_To_Upper_Case;

    function Convert_To_Upper_Case ( --| Change a string to upper case
                                    S : in String) --| string to be converted
                                   return String --| resulting string
                 is
        T : String (S'First .. S'Last);
    begin
        for I in S'Range loop
            T (I) := Convert_To_Upper_Case (S (I));
        end loop;

        return T;
    end Convert_To_Upper_Case;

    procedure Get_Command
                 ( --| Extract command from a string
                  Command_Line : in String;      --| input string
                  Line_Length : in Integer;      --| length of command_line
                  Command : out Command_Type;      --| returned command
                  Arg_Index : out Integer) --| end position of command
                  is
        I : Integer;
    begin
        I := 0;

        loop
            I := I + 1;

            if I > Line_Length then
                Command := Unknown;
                return;
            end if;

            if Command_Line (I) /= ' ' then

                -- clear blanks
                if Convert_To_Upper_Case (Command_Line (I)) = 'Q' then
                    Command := Quit;
                elsif Convert_To_Upper_Case (Command_Line (I)) = 'E' then
                    Command := Quit;
                elsif Convert_To_Upper_Case (Command_Line (I)) = '?' then
                    Command := Help;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "AU" then
                    Command := Autopath;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "PA" then
                    Command := Path;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "PR" then
                    Command := Profile;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "SM" then
                    Command := Smart;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "SO" then
                    Command := Source_Instrument;
                elsif Convert_To_Upper_Case (Command_Line (I .. I + 1)) =
                      "SI" then
                    Command := Source_Instrument;
                else
                    Command := Unknown;
                    Put ("unrecognized command");
                end if;

                exit;
            end if;
        end loop;

        while (Command_Line (I) /= ' ' and
               Command_Line (I) /= '(' and I /= Line_Length) loop
            I := I + 1;
        end loop;

        Arg_Index := I;
    exception
        when Constraint_Error =>
            Put ("unrecognized command");
            Command := Unknown;
    end Get_Command;


    procedure Get_Arguments ( --| get necessary file names for tool
                             Command : in Command_Type) --| tool selected
                  is
        Found : Boolean;
        Input_String : String (1 .. Maxline);
        Blanks : String (1 .. Maxline) := (others => ' ');
        Print_Buffer : String (1 .. 80);

        procedure Get_Log_File ( --| Gets log file name from terminal
                                Log_File : out Filename) --| log file name
                      is
            Input_String :
               String (1 .. Maxline);  --| string retreived from terminal
            Line_Length : Integer := Maxline;  --| length of input_string
            J : Integer := 1;  --| length of name
        begin
            Input_String := Blanks;

            while Input_String (1 .. Line_Length) =
                     Blanks (1 .. Line_Length) loop
                Put ("Enter Log_File_Name => ");
                Get_Line (Input_String, Line_Length);
            end loop;

            while (Input_String (J) /= ' ' and J < Maxline) loop
                J := J + 1;
            end loop;

            Log_File := Create (Input_String (1 .. J - 1));
        end Get_Log_File;

        procedure Get_Report_File
                     ( --| get report file name from user
                      Log_File : in Filename;
                      --| log file name for default
                      Report_File : out Filename) --| report file name
                      is
            Input_String :
               String (1 .. Maxline);  --| string retreived from terminal
            Line_Length : Integer := Maxline;  --| length of input_string
            K : Integer;  --| length of name
            End_Of_String : Integer;  --| last character in input string
        begin
            Input_String := Blanks;
            Put ("Enter Report_File_Name => ");
            Get_Line (Input_String, Line_Length);

            if Input_String (1 .. Line_Length) = Blanks (1 .. Line_Length) then
                Input_String (1 .. Length (Log_File)) := Value (Log_File);
                K := Maxline;

                while Input_String (K) = ' ' loop
                    K := K - 1;
                end loop;

                End_Of_String := K;

                while Input_String (K) /= '.' and
                         Input_String (K) /= ']' and K > 1 loop
                    K := K - 1;
                end loop;

                if Input_String (K) /= '.' then
                    K := End_Of_String + 1;
                    Input_String (K) := '.';
                end if;

                Input_String (K + 1 .. K + 3) := "RPT";
                Report_File := Create (Input_String (1 .. K + 3));
            else
                K := 1;

                while (Input_String (K) /= ' ' and K < Maxline) loop
                    K := K + 1;
                end loop;

                Report_File := Create (Input_String (1 .. K - 1));
            end if;
        end Get_Report_File;

        procedure Get_Source_File
                     ( --| get source file from user
                      Source_File : out Filename) --| source file name
                      is
            Input_String :
               String (1 .. Maxline);  --| string retreived from terminal
            Line_Length : Integer := Maxline;  --| length of input_String
            L : Integer := 1;  --| length of name
        begin
            Input_String := Blanks;

            while Input_String (1 .. Line_Length) =
                     Blanks (1 .. Line_Length) loop
                Put ("Enter Source_File => ");
                Get_Line (Input_String, Line_Length);
            end loop;

            while (Input_String (L) /= ' ' and L < Maxline) loop
                L := L + 1;
            end loop;

            Source_File := Create (Input_String (1 .. L - 1));
        end Get_Source_File;

        procedure Get_Source_Listing ( --| get listing file name from user
                                      Source_File : in Filename;
                                      --| source name for default
                                      Source_Listing : out Filename)
                     --| source listing file name
                      is
            Input_String : String (1 ..
                                      Maxline);  --| string retreived from user
            Line_Length : Integer := Maxline;  --| length of input_String
            M : Integer;  --| length of name
            End_Of_String : Integer;  --| last character of input string
        begin
            Input_String := Blanks;
            Put ("Enter Source_Listing_File => ");
            Get_Line (Input_String, Line_Length);

            if Input_String (1 .. Line_Length) = Blanks (1 .. Line_Length) then
                Input_String (1 .. Length (Source_File)) := Value (Source_File);
                M := Maxline;

                while Input_String (M) = ' ' loop
                    M := M - 1;
                end loop;

                End_Of_String := M;

                while Input_String (M) /= '.' and
                         Input_String (M) /= ']' and M > 1 loop
                    M := M - 1;
                end loop;

                if Input_String (M) /= '.' then
                    M := End_Of_String + 1;
                    Input_String (M) := '.';
                end if;

                Input_String (M + 1 .. M + 3) := "LST";
                Source_Listing := Create (Input_String (1 .. M + 3));
            else
                M := 1;

                while (Input_String (M) /= ' ' and M < Maxline) loop
                    M := M + 1;
                end loop;

                Source_Listing := Create (Input_String (1 .. M - 1));
            end if;
        end Get_Source_Listing;

        procedure Get_Instrumented_Source
                     (
                      --| get instrumented source file from user
                      Source_File : in Filename;
                      --| source name for default
                      Instrumented_Source : out Filename)
                     --| instrumented file name
                      is
            Input_String :
               String (1 .. Maxline);  --| string retreived from terminal
            Line_Length : Integer := Maxline;  --| length of input_String
            N : Integer;  --| length of name
            End_Of_String : Integer;  --| last character in input string
        begin
            Input_String := Blanks;
            Put ("Enter Instrumented_Source_File => ");
            Get_Line (Input_String, Line_Length);

            if Input_String (1 .. Line_Length) = Blanks (1 .. Line_Length) then
                Input_String (1 .. Length (Source_File)) := Value (Source_File);
                N := Maxline;

                while Input_String (N) = ' ' loop
                    N := N - 1;
                end loop;

                End_Of_String := N;

                while Input_String (N) /= '.' and
                         Input_String (N) /= ']' and N > 1 loop
                    N := N - 1;
                end loop;

                if Input_String (N) /= '.' then
                    N := End_Of_String + 1;
                    Input_String (N) := '.';
                end if;

                Input_String (N + 1 .. N + 3) := "INS";
                Instrumented_Source := Create (Input_String (1 .. N + 3));
            else
                N := 1;

                while (Input_String (N) /= ' ' and N < Maxline) loop
                    N := N + 1;
                end loop;

                Instrumented_Source := Create (Input_String (1 .. N - 1));
            end if;
        end Get_Instrumented_Source;

    begin
        if Command in Path .. Smart then
            if Positional_Count = 2 then
                Log_File := Positional_Arg_Value (1);
                Report_File := Positional_Arg_Value (2);
            elsif Positional_Count = 1 and Named_Count = 1 then
                Log_File := Positional_Arg_Value (1);
                Named_Arg_Value ("report_file_name", Found, Report_File);

                if Found = False then
                    Get_Report_File (Log_File, Report_File);
                end if;
            elsif Positional_Count = 1 and Named_Count = 0 then
                Log_File := Positional_Arg_Value (1);
                Get_Report_File (Log_File, Report_File);
            elsif Named_Count = 2 then
                Named_Arg_Value ("log_file_name", Found, Log_File);

                if Found = False then
                    Get_Log_File (Log_File);
                end if;

                Named_Arg_Value ("report_file_name", Found, Report_File);

                if Found = False then
                    Get_Report_File (Log_File, Report_File);
                end if;
            elsif Named_Count = 1 and Positional_Count = 0 then
                Named_Arg_Value ("log_file_name", Found, Log_File);

                if Found = False then
                    Get_Log_File (Log_File);
                    Named_Arg_Value ("report_file_name", Found, Report_File);

                    if Found = False then
                        Get_Report_File (Log_File, Report_File);
                    end if;
                else
                    Get_Report_File (Log_File, Report_File);
                end if;
            else
                Get_Log_File (Log_File);
                Get_Report_File (Log_File, Report_File);
            end if;

            Print_Buffer := Blanks;
            New_Line;
            New_Line;
            Print_Buffer (1 .. 16) := "log_file_name = ";
            Print_Buffer (17 .. Value (Log_File)'Length + 16) :=
               Value (Log_File);
            Put_Line (Print_Buffer);
            Print_Buffer := Blanks;
            Print_Buffer (1 .. 19) := "report_file_name = ";
            Print_Buffer (20 .. Value (Report_File)'Length + 19) :=
               Value (Report_File);
            Put_Line (Print_Buffer);
        elsif Command = Source_Instrument then
            if Positional_Count = 3 then
                Source_File := Positional_Arg_Value (1);
                Source_Listing := Positional_Arg_Value (2);
                Instrumented_Source := Positional_Arg_Value (3);
            elsif Positional_Count = 2 then
                Source_File := Positional_Arg_Value (1);
                Source_Listing := Positional_Arg_Value (2);
                Found := True;

                if Named_Count = 1 then
                    Named_Arg_Value ("instrumented_source",
                                     Found, Instrumented_Source);
                end if;

                if Found = False or Named_Count = 0 then
                    Get_Instrumented_Source (Source_File, Instrumented_Source);
                end if;
            elsif Positional_Count = 1 then
                Source_File := Positional_Arg_Value (1);
                Named_Arg_Value ("listing_file", Found, Source_Listing);

                if Found = False then
                    Get_Source_Listing (Source_File, Source_Listing);
                end if;

                Named_Arg_Value ("instrumented_source",
                                 Found, Instrumented_Source);

                if Found = False then
                    Get_Instrumented_Source (Source_File, Instrumented_Source);
                end if;
            else
                Named_Arg_Value ("source_file", Found, Source_File);

                if Found = False then
                    Get_Source_File (Source_File);
                end if;

                Named_Arg_Value ("source_listing", Found, Source_Listing);

                if Found = False then
                    Get_Source_Listing (Source_File, Source_Listing);
                end if;

                Named_Arg_Value ("instrumented_source",
                                 Found, Instrumented_Source);

                if Found = False then
                    Get_Instrumented_Source (Source_File, Instrumented_Source);
                end if;
            end if;

            New_Line;
            New_Line;
            Print_Buffer := Blanks;
            Print_Buffer (1 .. 14) := "source_file = ";
            Print_Buffer (15 .. Value (Source_File)'Length + 14) :=
               Value (Source_File);
            Put_Line (Print_Buffer);
            Print_Buffer := Blanks;
            Print_Buffer (1 .. 17) := "source_listing = ";
            Print_Buffer (18 .. Value (Source_Listing)'Length + 17) :=
               Value (Source_Listing);
            Put_Line (Print_Buffer);
            Print_Buffer := Blanks;
            Print_Buffer (1 .. 22) := "instrumented_source = ";
            Print_Buffer (23 .. Value (Instrumented_Source)'Length + 22) :=
               Value (Instrumented_Source);
            Put_Line (Print_Buffer);
        end if;

    end Get_Arguments;

    procedure Get_Autopath_Files
                 ( --| append multiple log files and get report file
                  Report_File : out Filename) --| report file name
                  is
        Input_String : String (1 .. Maxline);
        Line_Length : Integer := Maxline;
        P : Integer := 1;

    begin
        Input_String := Blanks;

        while Input_String (1 .. Line_Length) = Blanks (1 .. Line_Length) loop
            Put ("Enter Log_File_Name => ");
            Get_Line (Input_String, Line_Length);
        end loop;

        P := 1;

        while (Input_String (P) /= ' ' and P < Maxline) loop
            P := P + 1;
        end loop;

        File_Manager.Copy (Input_String (1 .. P - 1), Autopath_Log);
        Input_String := Blanks;
        Put ("Enter Log_File_Name => ");
        Get_Line (Input_String, Line_Length);

        while Input_String (1 .. Line_Length) /= Blanks (1 .. Line_Length) loop
            P := 1;

            while (Input_String (P) /= ' ' and P < Maxline) loop
                P := P + 1;
            end loop;

            File_Manager.Append (Input_String (1 .. P - 1), Autopath_Log);
            Input_String := Blanks;
            Put ("Enter Log_File_Name => ");
            Get_Line (Input_String, Line_Length);
        end loop;

        Input_String := Blanks;
        Put ("Enter Report_File_Name => ");
        Get_Line (Input_String, Line_Length);
        New_Line;
        Put ("Report_File_Name = ");

        if Input_String (1 .. Line_Length) = Blanks (1 .. Line_Length) then
            Report_File := Create ("autopath.rpt");
            Put_Line ("autopath.rpt");
        else
            P := 1;

            while (Input_String (P) /= ' ' and P < Maxline) loop
                P := P + 1;
            end loop;

            Report_File := Create (Input_String (1 .. P - 1));
            Put_Line (Input_String (1 .. P - 1));
        end if;

    end Get_Autopath_Files;

begin
    New_Line;
    Command_Line := Blanks;
    Put_Line ("Welcome to the Test Tools");
    Put_Line ("please enter desired tool");
    Put_Line ("enter ? for a list of tools available");
    Put_Line ("enter quit to exit");
    Get_Line (Command_Line, Line_Length);
    New_Line;
    Get_Command (Command_Line, Line_Length, Command, Command_Index);

    while Command /= Quit loop
        if Command in Path .. Source_Instrument then
            Positional_Count := 0;
            Named_Count := 0;

            if Command_Line (Command_Index) = '(' then
                End_Index := Command_Index + 1;

                while Command_Line (End_Index) /= ')' and
                         End_Index /= Line_Length loop
                    End_Index := End_Index + 1;
                end loop;

                Argument_String (1 .. End_Index - Command_Index - 1) :=
                   Command_Line (Command_Index + 1 .. End_Index - 1);
                Argument_String (End_Index - Command_Index .. Maxline) :=
                   Blanks (End_Index - Command_Index .. Maxline);
                Initialize (Argument_String);
                Named_Count := Named_Arg_Count;
                Positional_Count := Positional_Arg_Count;
            end if;

            Get_Arguments (Command);

            case Command is
                when Path =>
                    Adapathr.Path_Report_Writer (Log_File, Report_File);
                when Profile =>
                    Profile_Pkg.Profile (Log_File, Report_File);
                when Smart =>
                    Smart_Pkg.Smart (Log_File, Report_File);
                when Source_Instrument =>
                    Source_Instrument (Value (Source_File),
                                       Value (Source_Listing),
                                       Value (Instrumented_Source));
                when others =>
                    null;
            end case;
        elsif Command = Autopath then
            Get_Autopath_Files (Report_File);
            Log_File := Create (Autopath_Log);
            Adapathr.Path_Report_Writer (Log_File, Report_File);
            Open (Autopath_Logfile, In_File, Autopath_Log);
            Delete (Autopath_Logfile);
        elsif Command = Help then
            Put_Line ("The following tools may be executed:");
            Put_Line
               ("path -- the report generator for the path analysis tools");
            Put_Line ("profile -- the report generator for the timing tool");
            Put_Line ("smart -- the report generator for the self metric tool");
            Put_Line ("source_instrument -- instrument an Ada source file");
            Put_Line
               ("autopath -- the path analysis report generator for multiple log files");
        end if;

        New_Line;
        Command := Unknown;
        Command_Line := Blanks;
        Put_Line ("please enter desired tool");
        Get_Line (Command_Line, Line_Length);
        New_Line;
        Get_Command (Command_Line, Line_Length, Command, Command_Index);
    end loop;
end Test_Tools;

