with Terminal_Interface, Machine_Dependencies, Equality_Operator,
     Text_Io, Run_Time_Statistics, Singly_Linked_List,
     Dictionary_Manager, Document_Handler, Help;
package body Corrector is


    type Token_Counter is
        record
            Token : Token_Definition.Token_Type;
            Corrected_Token : Token_Definition.Token_Type;
        end record;

    package Rts renames Run_Time_Statistics;

    package Singly_Linked_Word_List is new Singly_Linked_List (Token_Counter);
    use Singly_Linked_Word_List;

    Token_Counter_List : Singly_Linked_Word_List.List_Type;

    function "=" (Left, Right : Get_User_Info.Mode_Type) return Boolean
        renames Get_User_Info."=";

    function Equals (Left, Right : Token_Definition.Token_Type) return Boolean;

    package Token_Equality is new Equality_Operator
                                     (Token_Definition.Token_Type, Equals);

    function "=" (Left, Right : Token_Definition.Token_Type) return Boolean
        renames Token_Equality.Equals."=";

    function Equals (Left, Right : Token_Definition.Token_Type)
                    return Boolean is
        --------------------------------------------------------------------------
        -- Abstract   : This function defines equality for tokens.
        --------------------------------------------------------------------------
        -- Parameters : Left & Right -- are tokens to be compared for equality.
        --------------------------------------------------------------------------
    begin
        return Left.Word (Left.Word'First .. Left.Length) =
                  Right.Word (Right.Word'First .. Right.Length);
    end Equals;

    function ">" (Left, Right : Token_Definition.Token_Type) return Boolean is
        --------------------------------------------------------------------------
        -- Abstract   : This function defines the "greater than" relation for
        -- tokens.
        --------------------------------------------------------------------------
        -- Parameters : Left & Right -- are tokens to be compared
        --------------------------------------------------------------------------
    begin
        return Left.Word (Left.Word'First .. Left.Length) >
                  Right.Word (Right.Word'First .. Right.Length);
    end ">";


    --------------------------------------------------------------------------
    -- Abstract   : This operation will determine if a word has already been
    --            : corrected.
    --------------------------------------------------------------------------
    -- Parameters : WORD : in STRING is the string being check for.
    --            : LIST : in LIST_PTR is the access value to the list
    --            : of words which have already been corrected.
    --------------------------------------------------------------------------
    -- Algorithm  :
    --
    --------------------------------------------------------------------------
    function Was_Corrected
                (Token : Token_Definition.Token_Type) return Boolean is
        Corrected : Boolean := True;

    begin

        First (Token_Counter_List);

        while (not Null_Node (Token_Counter_List)) and then
                 (Token > Current_Element (Token_Counter_List).Token) loop
            Next (Token_Counter_List);
        end loop;

        if Null_Node (Token_Counter_List) then
            Corrected := False;

        elsif Token = Current_Element (Token_Counter_List).Token then
            begin

                Document_Handler.Restore_Word
                   (Current_Element (Token_Counter_List).Corrected_Token.Word
                       (Current_Element (Token_Counter_List).
                        Corrected_Token.Word'First ..
                           Current_Element (Token_Counter_List).
                              Corrected_Token.Length));

                if Token.Length /= Current_Element (Token_Counter_List).
                                      Corrected_Token.Length then
                    Rts.Increment_Counter (Rts.Words_Changing_Length);
                end if;

                Rts.Increment_Counter (Rts.Corrected_Words);

            exception
                when Document_Handler.Restore_Failed =>
                    Rts.Increment_Counter (Rts.Failed_Restores);

            end;
        else
            Corrected := False;
        end if;
        return Corrected;
    end Was_Corrected;

    --**************************************************************************
    --**************************************************************************



    --*************************************************************************
    --*************************************************************************


    procedure Correct (User_Info : Get_User_Info.User_Info_Type;
                       Word : Token_Definition.Token_Type) is


        Blank : constant Character := ' ';
        Context : Document_Handler.Context;
        Index : Natural;
        Length : Natural;
        Level_3 : Help.Level_Type renames Help.Spell_Help;

        User_Response : String (1 .. Machine_Dependencies.File_Line_Length);
        All_Occurrences : constant Boolean := True;
        Delete : constant Boolean := False;
        Word_Changed : Boolean;
        Characters_Read : Natural;
        type Menu_Type is array (Positive range 1 .. 11) of String (1 .. 68);

        Menu : constant Menu_Type :=

           ("********************************************************************",
            "CORRECTOR                                                           ",
            "                                                                    ",
            "    Replace this word                Accept this word               ",
            "       R>eplace all Occurrences          A>ccept all Occurrences    ",
            "       O>nly this Occurrence             T>his Occurrence only      ",
            "                                                                    ",
            "    L>ookup Possible Corrections     ?>Help                         ",
            "    U>pdate user Dictionary          Q>uit                          ",
            "    D>elete word from Dictionary                                    ",
            "********************************************************************");

        procedure Replace (Word : Token_Definition.Token_Type;
                           All_Occurrences : Boolean := False) is

            Corrected_Token : Token_Definition.Token_Type;
            Response : String (1 .. Token_Definition.Token_Length);
            Length : Natural;
            Abandon : exception;

        begin
            loop
                Terminal_Interface.Put
                   ("Replace <<" & Word.Word (Word.Word'First .. Word.Length) &
                    ">>  with =>");

                Terminal_Interface.Get_Line
                   (Corrected_Token.Word, Corrected_Token.Length);

                if Corrected_Token.Length < Corrected_Token.Word'First then
                    raise Abandon;
                else
                    Terminal_Interface.Put_Line
                       ("Replacing '" &
                        Word.Word (Word.Word'First .. Word.Length) &
                        "' with '" &
                        Corrected_Token.Word (Corrected_Token.Word'First ..
                                                 Corrected_Token.Length) &
                        "' OK (Y/N)");
                    Terminal_Interface.Get_Line (Response, Length);
                    if Response (Response'First) = 'Y' or
                       Response (Response'First) = 'y' then
                        exit;
                    end if;
                end if;
            end loop;
            if All_Occurrences then

                Insert_Word (Word, Corrected_Token);
            end if;

            Document_Handler.Restore_Word
               (Corrected_Token.Word (Corrected_Token.Word'First ..
                                         Corrected_Token.Length));
            Rts.Increment_Counter (Rts.Corrected_Words);

        exception
            when Abandon =>
                null;

            when Document_Handler.Restore_Failed =>
                Terminal_Interface.Put_Line
                   ("Restore failed..." & "operation ignored.");
                Rts.Increment_Counter (Rts.Failed_Restores);
                Terminal_Interface.Put_Line ("Hit return key to continue");
                Terminal_Interface.Get_Line (Response, Length);
        end Replace;



        procedure Modify_Dict (User_Info : Get_User_Info.User_Info_Type;
                               Token : Token_Definition.Token_Type;
                               Update : Boolean := True) is

            type Current_Dict_Type is
                record
                    Name : String
                              (1 .. Machine_Dependencies.Max_File_Name_Length);
                    Length : Natural;
                    Ptr : Dictionary_Manager.Dictionary_Ptr;
                end record;

            Current_Dict :
               array (Positive range 1 .. Get_User_Info.
                                             Number_Of_User_Dictionaries) of
                  Current_Dict_Type;

            User_Dict : Natural := 0;
            Index : Natural := 1;
            Response : String (1 .. Token_Definition.Token_Length);
            Number_Of_Characters : Natural;
            Word : Token_Definition.Token_Type := Token;

            package Int_Get is new Text_Io.Integer_Io (Natural);

        begin

            if User_Info.User_Dict.Mode = Get_User_Info.Enabled then

                for I in 1 .. Get_User_Info.Number_Of_User_Dictionaries loop

                    if User_Info.User_Dict.Names (I).Mode =
                       Get_User_Info.Enabled then

                        User_Dict := User_Dict + 1;

                        Current_Dict (User_Dict).Name :=
                           User_Info.User_Dict.Names (I).Name;

                        Current_Dict (User_Dict).Length :=
                           User_Info.User_Dict.Names (I).Length;

                        Current_Dict (User_Dict).Ptr :=
                           User_Info.User_Dict.Names (I).Ptr;
                    end if;
                end loop;

                for I in 1 .. User_Dict loop

                    Terminal_Interface.Put (Natural'Image (I));

                    Terminal_Interface.Set_Col (5);

                    Terminal_Interface.Put_Line
                       (Current_Dict (I).Name (Current_Dict (I).Name'First ..
                                                  Current_Dict (I).Length));
                end loop;

                Terminal_Interface.Put_Line
                   ("Enter the number of the dictionary" & " to be modified");

                Int_Get.Get (User_Dict, 1);

                if Update then
                    begin

                        Terminal_Interface.Put_Line
                           ("   Inserting <" &
                            Word.Word (Word.Word'First .. Word.Length) &
                            "> into dictionary <" &
                            Current_Dict (User_Dict).Name
                               (Current_Dict (User_Dict).Name'First ..
                                   Current_Dict (User_Dict).Length) &
                            "> OK (Y/N) ");

                        Terminal_Interface.Get_Line
                           (Response, Number_Of_Characters);

                        if Response (Response'First) = 'Y' or
                           Response (Response'First) = 'y' then
                            Dictionary_Manager.Insert_Word
                               (Word, Current_Dict (User_Dict).Ptr);
                        end if;
                    exception
                        when Dictionary_Manager.Bad_Word =>
                            Terminal_Interface.Put_Line
                               (" Tried to insert an illegal word");
                            Terminal_Interface.Put_Line
                               ("Hit return character to continue");
                            Terminal_Interface.Get_Line (Response, Length);

                        when Dictionary_Manager.Dictionary_Error =>
                            Terminal_Interface.Put_Line
                               ("Inserting word" & " into bad dictionary.");
                            Terminal_Interface.Put_Line
                               ("Hit return key to continue");
                            Terminal_Interface.Get_Line (Response, Length);
                        when others =>
                            null;
                    end;

                else
                    begin
                        Terminal_Interface.Put_Line
                           ("Enter the word to be deleted");

                        Terminal_Interface.Get_Line (Word.Word, Word.Length);

                        Terminal_Interface.Put_Line
                           ("Deleting <" &
                            Word.Word (Word.Word'First .. Word.Length) &
                            "> from dictionary <" &
                            Current_Dict (User_Dict).Name
                               (Current_Dict (User_Dict).Name'First ..
                                   Current_Dict (User_Dict).Length) &
                            "< OK (Y/N) ");

                        Terminal_Interface.Get_Line
                           (Response, Number_Of_Characters);

                        if Response (Response'First) = 'Y' or
                           Response (Response'First) = 'y' then

                            Dictionary_Manager.Delete_Word
                               (Word, Current_Dict (User_Dict).Ptr);
                        end if;
                    exception
                        when Dictionary_Manager.Word_Not_Valid |
                             Dictionary_Manager.Bad_Word =>
                            Terminal_Interface.Put_Line
                               ("Cannot delete word from dictionary.");
                            Terminal_Interface.Put_Line
                               ("Hit return key to continue");
                            Terminal_Interface.Get_Line (Response, Length);

                        when Dictionary_Manager.Dictionary_Error =>
                            Terminal_Interface.Put_Line
                               ("Dictionary specified is invalid");
                            Terminal_Interface.Put_Line
                               ("Hit return key to continue");
                            Terminal_Interface.Get_Line (Response, Length);

                        when others =>
                            null;


                    end;
                end if;
            else
                Terminal_Interface.Put_Line
                   ("There are no user dictionaries" & " currently enabled.");
                Terminal_Interface.Put_Line ("Hit return key to continue.");
                Terminal_Interface.Get_Line (Response, Number_Of_Characters);
            end if;
        exception
            when others =>
                null;
        end Modify_Dict;



        ----------------------------------------------------------------
        --
        -- Abstract     :  This procedure provides the user's option of
        --              :  choosing a correction from a list provided by
        --              :  the spelling corrector program.  A list is shown
        --              :  and the user prompted for his/her choice.
        --
        ----------------------------------------------------------------
        --
        -- Parameters   :  WORD_IN - A token record which will provide the
        --              :  word to key the correction search.
        --
        ----------------------------------------------------------------

        procedure Look_Up (Word_In : in Token_Definition.Token_Type;
                           Word_Changed : out Boolean) is


            Get_Word : Token_Definition.Token_Type;
            New_Word : Token_Definition.Token_Type;
            Num_Words : constant := 10;
            Word_Holder : array (1 .. Num_Words) of Token_Definition.Token_Type;
            Word_Blank : constant String (1 .. Token_Definition.Token_Length) :=
               (others => ' ');
            Choice : Natural;
            Word_Ct : Natural;
            Line_Ct : Natural;
            Off_Set : constant Natural := 5;
            Response : String (1 .. Token_Definition.Token_Length);

            ----------------------------------------------------------------
            --
            -- Abstract     :  A procedure containing a bubble sort algorithm
            --              :  which sorts on the word field of the token
            --              :  record.
            --
            ----------------------------------------------------------------
            --
            -- Parameters   :  This procedure is internal to procedure LOOK_UP
            --              :  and variables referenced within the procedure are
            --              :  within the scope of procedure LOOK_UP.
            --
            ----------------------------------------------------------------
            --
            -- Algorithm    :  The algorithm is a standard bubble sort.  The
            --              :  fields used for sorting are sliced using the
            --              :  shorter length, taking for granted that an equal
            --              :  compare denotes the longer actual length as being
            --              :  the greater value.
            --
            ----------------------------------------------------------------

            procedure Sort is

            begin
                for Outer in reverse 1 .. Word_Ct loop
                    Choice := Outer - 1;
                    for Inner in 1 .. Choice loop
                        if Word_Holder (Inner).Length <=
                           Word_Holder (Inner + 1).Length then
                            if Word_Holder (Inner).Word
                                  (1 .. Word_Holder (Inner).Length) >
                               Word_Holder (Inner + 1).Word
                                  (1 .. Word_Holder (Inner).Length) then
                                Get_Word := Word_Holder (Inner);
                                Word_Holder (Inner) := Word_Holder (Inner + 1);
                                Word_Holder (Inner + 1) := Get_Word;
                            end if;
                        else
                            if Word_Holder (Inner).Word
                                  (1 .. Word_Holder (Inner + 1).Length) >=
                               Word_Holder (Inner + 1).Word
                                  (1 .. Word_Holder (Inner + 1).Length) then
                                Get_Word := Word_Holder (Inner);
                                Word_Holder (Inner) := Word_Holder (Inner + 1);
                                Word_Holder (Inner + 1) := Get_Word;
                            end if;
                        end if;
                    end loop;
                end loop;
            end Sort;

        begin
            Word_Changed := False;
            --Blank out the storage structure

            for Index in 1 .. Num_Words loop
                Word_Holder (Index).Word := Word_Blank;
                Word_Holder (Index).Length := 1;
            end loop;

            --Get the words from the dictionary

            begin
                Dictionary_Manager.Initiator (Word_In, Num_Words);--initialize
                Word_Ct := 0;
                while Dictionary_Manager.More loop
                    --while more words are desired
                    Word_Ct := Word_Ct + 1;
                    Dictionary_Manager.Next_Word (Word_Holder (Word_Ct));
                end loop;
            exception
                when Dictionary_Manager.No_More_Words =>
                    Word_Holder (Word_Ct).Word := Word_Blank;
                    Word_Holder (Word_Ct).Length := 1;
                    Word_Ct := Word_Ct - 1;
            end;

            -- If there were word returned then sort otherwise terminate

            if Word_Holder (Word_Holder'First).Length > 1 then

                --Sort the words obtained in alphabetical order

                Sort;

                --Print the words to the terminal

                if (Word_Ct rem 2) = 0 then
                    Line_Ct := Word_Ct / 2;
                else
                    Line_Ct := (Word_Ct + 1) / 2;
                end if;
                for Index in 1 .. Line_Ct loop
                    Terminal_Interface.New_Line;
                    Terminal_Interface.Put (Natural'Image ((Index * 2) - 1));
                    Terminal_Interface.Put (". ");
                    Terminal_Interface.Put
                       (Word_Holder ((Index * 2) - 1).Word
                           (1 .. (Word_Holder ((Index * 2) - 1).Length)));
                    if Word_Holder (Index * 2).Length > 1 then
                        Terminal_Interface.Set_Col
                           (Text_Io.Positive_Count
                               (Token_Definition.Token_Length + Off_Set));
                        Terminal_Interface.Put (Natural'Image (Index * 2));
                        Terminal_Interface.Put (". ");
                        Terminal_Interface.Put_Line
                           (Word_Holder (Index * 2).Word
                               (1 .. (Word_Holder (Index * 2).Length)));
                    else
                        Terminal_Interface.New_Line;
                    end if;
                end loop;
                Terminal_Interface.New_Line;

                --Prompt for user choice, reprompt if response improper

                loop
                    Terminal_Interface.Put ("Enter your choice, CR to quit: ");
                    Terminal_Interface.Get_Line
                       (Get_Word.Word, Get_Word.Length);
                    exit when (Get_Word.Length = 0);
                    if (Get_Word.Word (1) < '1') or
                       (Get_Word.Word (1) > '9') then
                        null;
                    elsif (Get_Word.Length = 2) and
                          (Get_Word.Word (2) /= '0') then
                        null;
                    elsif Word_Ct <
                          (Natural'Value (Get_Word.Word
                                             (1 .. Get_Word.Length))) then
                        null;
                    else
                        Choice := Natural'Value (Get_Word.Word
                                                    (1 .. Get_Word.Length));
                        Terminal_Interface.New_Line;
                        exit;
                    end if;
                    Terminal_Interface.New_Line;
                end loop;

                --Perform the desired action

                if Get_Word.Length > 0 then
                    begin
                        case Choice is
                            when 1 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (1).Word
                                       (1 .. Word_Holder (1).Length));

                                Insert_Word (Word_In, Word_Holder (1));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (1).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);

                            when 2 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (2).Word
                                       (1 .. Word_Holder (2).Length));

                                Insert_Word (Word_In, Word_Holder (2));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (2).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 3 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (3).Word
                                       (1 .. Word_Holder (3).Length));

                                Insert_Word (Word_In, Word_Holder (3));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (3).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 4 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (4).Word
                                       (1 .. Word_Holder (4).Length));

                                Insert_Word (Word_In, Word_Holder (4));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (4).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 5 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (5).Word
                                       (1 .. Word_Holder (5).Length));

                                Insert_Word (Word_In, Word_Holder (5));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (5).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 6 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (6).Word
                                       (1 .. Word_Holder (6).Length));

                                Insert_Word (Word_In, Word_Holder (6));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (6).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 7 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (7).Word
                                       (1 .. Word_Holder (7).Length));

                                Insert_Word (Word_In, Word_Holder (7));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (7).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 8 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (8).Word
                                       (1 .. Word_Holder (8).Length));

                                Insert_Word (Word_In, Word_Holder (8));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (8).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 9 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (9).Word
                                       (1 .. Word_Holder (9).Length));

                                Insert_Word (Word_In, Word_Holder (9));

                                Word_Changed := True;

                                if Word_In.Length /= Word_Holder (9).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when 10 =>
                                Document_Handler.Restore_Word
                                   (Word_Holder (10).Word
                                       (1 .. Word_Holder (10).Length));

                                Insert_Word (Word_In, Word_Holder (10));

                                Word_Changed := True;

                                if Word_In.Length /=
                                   Word_Holder (10).Length then
                                    Rts.Increment_Counter
                                       (Rts.Words_Changing_Length);
                                end if;

                                Rts.Increment_Counter (Rts.Corrected_Words);
                            when others =>
                                Terminal_Interface.Put_Line
                                   ("Error in selection, aborting.");
                                Terminal_Interface.New_Line;
                                Word_Changed := False;
                        end case;
                    exception
                        when Document_Handler.Restore_Failed =>
                            Terminal_Interface.Put_Line
                               ("Restore failed .." & "operation ignored.");
                            Rts.Increment_Counter (Rts.Failed_Restores);
                            Terminal_Interface.Put_Line
                               ("Hit return key to continue");
                            Terminal_Interface.Get_Line (Response, Choice);

                    end;
                end if;
            else
                Terminal_Interface.Put_Line ("No similar words found");
                Terminal_Interface.Put_Line ("Hit return key to continue.");
                Terminal_Interface.Get_Line (Response, Choice);
            end if;
        end Look_Up;



    begin
        loop
            begin
                if not (Bad_Word_Flag) then
                    Terminal_Interface.New_Page;
                    Document_Handler.Context_Of_Last_Get_Word
                       (Context, Index, Length);
                    for I in Document_Handler.Context'Range loop
                        Terminal_Interface.Put_Line
                           (Context (I).Line (Context (I).Line'First ..
                                                 Context (I).Last));
                        if I = Positive (Document_Handler.
                                         Target_Line_In_Context) then
                            for J in 1 .. Index - 1 loop
                                Terminal_Interface.Put (" ");
                            end loop;
                            for J in 1 .. Length loop
                                Terminal_Interface.Put ("*");
                            end loop;
                        end if;

                        Terminal_Interface.New_Line;

                    end loop;

                    for I in Menu_Type'Range loop
                        Terminal_Interface.Put_Line (Menu (I));
                    end loop;

                    Terminal_Interface.Get_Line
                       (User_Response, Characters_Read);
                else
                    User_Response (User_Response'First) := 'T';
                end if;

                case User_Response (User_Response'First) is

                    when 'R' | 'r' =>
                        Replace (Word, All_Occurrences);
                        exit;

                    when 'O' | 'o' =>
                        Replace (Word);
                        exit;

                    when 'A' | 'a' =>
                        Insert_Word (Word, Word);
                        exit;

                    when 'T' | 't' =>
                        Bad_Word_Flag := False;
                        exit;

                    when 'L' | 'l' =>
                        Look_Up (Word, Word_Changed);
                        if Word_Changed then
                            exit;
                        end if;

                    when 'U' | 'u' =>
                        Modify_Dict (User_Info, Word);
                        exit;

                    when 'Q' | 'q' =>
                        raise Abandon_Operation;

                    when 'D' | 'd' =>
                        Modify_Dict (User_Info, Word, Delete);


                    when '?' =>
                        Help.Help_Screen (Level_3);

                    when others =>
                        Terminal_Interface.New_Line;
                        Terminal_Interface.Put_Line
                           ("<<" & User_Response
                                      (User_Response'First .. Characters_Read) &
                            ">>");
                        Terminal_Interface.Put_Line
                           (" is not one of your possible choices. ");
                        Terminal_Interface.Put_Line (" Reenter your choice.");
                        delay (Duration (2.0));
                end case;
            exception
                when Abandon_Operation =>
                    raise;
                when others =>
                    null;
            end;
            User_Response (User_Response'First) := Blank;
        end loop;
        User_Response (User_Response'First) := Blank;
    end Correct;


    --*************************************************************************
    --*************************************************************************




    procedure Initialize is
        --------------------------------------------------------------------------
        -- Abstract   : This procedure empties the misspelled word list.
        --------------------------------------------------------------------------
        -- Algorithm  : Go to the head of the list and delete the head element
        --              until the list is empty.
        --------------------------------------------------------------------------
    begin
        First (Token_Counter_List);
        while not Empty (Token_Counter_List) loop
            Delete_Element (Token_Counter_List);
        end loop;
    end Initialize;

    procedure Insert_Word (Token, Corrected_Token :
                              Token_Definition.Token_Type) is
        --------------------------------------------------------------------------
        -- Abstract   : This procedure inserts a token and the corrected token
        --              into the linked list in ascending order if the token is not
        --              already in the list.
        --------------------------------------------------------------------------
        -- Parameters : Token - is the original word from the document.
        --            : CORRECTED TOKEN is what the user wish the word to be
        --------------------------------------------------------------------------
        -- Algorithm  : (a) Go to the head of the list.
        --              (b) Traverse the list until the end of the list is
        --                  encountered or a token is found in the list that has
        --                  a value greater than or equal to the input
        --                    parameter.
        --              (c) select
        --                    end-of-list =>
        --                      insert input parameter at end of list
        --                    token in list is greater than input parameter =>
        --                      insert the input parameter in front of the
        --                      element
        --------------------------------------------------------------------------


    begin

        First (Token_Counter_List);

        while (not Null_Node (Token_Counter_List)) and then
                 (Token > Current_Element (Token_Counter_List).Token) loop
            Next (Token_Counter_List);
        end loop;

        if Null_Node (Token_Counter_List) then
            Insert_After (List => Token_Counter_List,
                          Element => Token_Counter'(Token, Corrected_Token));
        elsif Token = Current_Element (Token_Counter_List).Token then
            null;
        else
            Insert_Before (List => Token_Counter_List,
                           Element => Token_Counter'(Token, Corrected_Token));
        end if;

    end Insert_Word;


    --**********************************************************************
    --**********************************************************************

begin

    Initialize;

end Corrector;