with Display_Tools;
with Editor;
with Io;
with Job;
with Lost_Key_Name;
with New_Keys;
with Pipe;
with Step_Tools;
with Training_Names;
with Window_Io;

procedure Process_Keys (Course_Name : String; Release_Name : String) is

    package Sio renames Io;
    package Raw renames Window_Io.Raw;

    procedure Step (Num : Integer := 1) renames Step_Tools.Display_Manager.Step;
    procedure Select_Module renames Step_Tools.Display_Manager.Select_Module;
    procedure Stop renames Step_Tools.Display_Manager.Stop;
    procedure Start (Course_Name : String; Release_Name : String)
        renames Step_Tools.Display_Manager.Start;
    Retries : Natural := 0;

    package Key_Ops is new Pipe.Type_Specific_Operations (Raw.Key);

    function "=" (K1, K2 : Raw.Key) return Boolean renames Raw."=";

    Key_Pipe : Pipe.Handle;
    K : Raw.Key;
    Live_File : Sio.File_Type;
    Maximum_Idle_Time : Duration := 7200.0; -- 2 hours

    task Coupler is
        entry Start;
        entry Read (The_Key : out Raw.Key);
    end Coupler;

    task body Coupler is
        K : Raw.Key;
    begin
        select
            accept Start;
        or
            terminate;
        end select;

        loop
            Key_Ops.Read (Key_Pipe, K);

            select
                accept Read (The_Key : out Raw.Key) do
                    The_Key := K;
                end Read;
            or
                terminate;
            end select;
        end loop;
    end Coupler;

begin
    begin
        Sio.Open (Live_File, Sio.In_File,
                  Training_Names.Live_Job_File_Pathname);
        Sio.Close (Live_File);
        Editor.Alert;
        Sio.Put_Line
           (Sio.Standard_Error,
            "You already have a running script session.  Check your Window Directory.");
        Step_Tools.Display_Manager.Stop;
        return;
    exception
        when Sio.Name_Error =>
            loop
                begin
                    Sio.Create (Live_File, Sio.Out_File,
                                Training_Names.Live_Job_File_Pathname);  
                    exit;
                exception
                    when Sio.Use_Error =>
                        if Retries < 10 then
                            delay 0.5;
                            Retries := Retries + 1;
                        else
                            Editor.Alert;
                            Sio.Put_Line
                               (Sio.Standard_Error,
                                "Use error on use of Live_Job_Files (LOCKS or ACL).  " &
                                   "Please call proctor");
                            Step_Tools.Display_Manager.Stop;
                            return;
                        end if;
                end;
            end loop;
        when others =>
            Editor.Alert;
            Sio.Put_Line
               (Sio.Standard_Error,
                "Other error on use of Live_Job_Files (LOCKS).  Please call proctor");
            Step_Tools.Display_Manager.Stop;
            return;
    end;

    begin
        Pipe.Open (Key_Pipe, Pipe.Shared_Read, Lost_Key_Name);
    exception
        when others =>
            Sio.Delete (Live_File);
            Editor.Alert;
            Sio.Put_Line
               (Sio.Standard_Error,
                "Key pipe has not been created.  Please call proctor");
            Step_Tools.Display_Manager.Stop;
            return;
    end;

    Display_Tools.Open_Input;
    Display_Tools.Open_Output;

    Job.Disconnect;

    Start (Course_Name, Release_Name);

    -- Start the coupler task once the pipe has been opened

    Coupler.Start;

    loop

        -- Wait here for a key from the pipe; if nothing happens for
        -- a duration of max_idle_time, the job self destructs

        select

            Coupler.Read (K);


        or
            delay Maximum_Idle_Time;
            Sio.Delete (Live_File);
            abort Coupler;
            Stop;
            Display_Tools.Delete_Window;
            exit;
        end select;

        if K = New_Keys.Step_Forward then
            Step;
        elsif K = New_Keys.Step_Backward then
            Step (-1);
        elsif K = New_Keys.Step_Many then
            Window_Io.Bell (Display_Tools.Output_Window);
--                Display_Tools.Open_Input;
--                Locate (Integer'Value
--                     (Display_Tools.Query
--                           (Prompt =>
--                            "Enter Number of Steps , Negatives Accepted",
--                            Line => 15, Column => 1)));
--                Display_Tools.Close_Input;
        elsif K = New_Keys.Step_Exact then
            Window_Io.Bell (Display_Tools.Output_Window);

--                Display_Tools.Open_Input;
--                Locate (Integer'Value
--                     (Display_Tools.Query
--                           (Prompt => "Enter Entry Number",
--                            Line => 15, Column => 1)));
--                Display_Tools.Close_Input;
        elsif K = New_Keys.Menu_Select then
            Select_Module;

        elsif K = New_Keys.Quit then
            Sio.Delete (Live_File);
            Stop;
            Display_Tools.Delete_Window;
            exit;
        else
            Window_Io.Bell (Display_Tools.Output_Window);
        end if;
    end loop;

exception
    when Step_Tools.Terminate_Script | Step_Tools.Time_Out =>
        abort Coupler;
        Sio.Delete (Live_File);
        Display_Tools.Delete_Window;
    when others =>
        abort Coupler;
        Sio.Delete (Live_File);
        Editor.Alert;
        Sio.Put_Line
           (Sio.Standard_Error,
            "Unknown Error (Possibly a Lock on Script_Text File).  Please call Proctor.");
        Display_Tools.Delete_Window;
end Process_Keys;
