with Equality_Operator, Singly_Linked_List;
package body Misspelled_Word_List is
    --------------------------------------------------------------------------
    -- Abstract   : This package maintains a list of tokens with a frequency
    --              count and prints the list in ascending order on request.
    --------------------------------------------------------------------------

    type Token_Counter is
        record
            Token : Token_Definition.Token_Type;
            Count : Positive;
        end record;

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

    procedure Increment (Element : in out Token_Counter);

    procedure Increment_Counter is
       new Singly_Linked_Word_List.Modify (Increment);

    Token_Counter_List : Singly_Linked_Word_List.List_Type;

    procedure Increment (Element : in out Token_Counter) is
        --------------------------------------------------------------------------
        -- Abstract   : Increment the count field of an element
        --------------------------------------------------------------------------
        -- Parameters : Element - is the element to have its count field incremented
        --------------------------------------------------------------------------
    begin
        Element.Count := Element.Count + 1;
    end Increment;

    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 Add_Token (Token : Token_Definition.Token_Type) is
        --------------------------------------------------------------------------
        -- Abstract   : This procedure inserts a token into the linked list in
        --              ascending order (or if already in the list, increments
        --              its count).
        --------------------------------------------------------------------------
        -- Parameters : Token - is the token to be inserted into the list.
        --------------------------------------------------------------------------
        -- 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
        --                    input parameter found in list =>
        --                      increment counter
        --                    token in list is greater than input parameter =>
        --                      insert the input parameter in front of the element
        --------------------------------------------------------------------------
        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 ">";

    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, 1));
        elsif Token = Current_Element (Token_Counter_List).Token then
            Increment_Counter (Token_Counter_List);
        else
            Insert_Before (List => Token_Counter_List,
                           Element => Token_Counter'(Token, 1));
        end if;
    end Add_Token;

    procedure Print (File : Text_Io.File_Type) is
        --------------------------------------------------------------------------
        -- Abstract   : Print the list (token and count) from head to tail, one
        --              element per line.  The count is printed in columns beyond
        --              the maximum length of a token so that the file may be used
        --              as a dictionary.
        --------------------------------------------------------------------------
        -- Parameters : File - is the file to which the list is to be written.
        --------------------------------------------------------------------------

        package Integer_Io is new Text_Io.Integer_Io (Positive);

        function "+" (L, R : Text_Io.Count) return Text_Io.Count
            renames Text_Io."+";

        Max_Token_Width : constant Natural := Token_Definition.Token_Length;
        Counter_Width : constant := 5;

    begin
        First (Token_Counter_List);

        while not Null_Node (Token_Counter_List) loop
            Text_Io.Put (File, Current_Element (Token_Counter_List).Token.Word
                                  (1 .. Current_Element (Token_Counter_List).
                                           Token.Length));

            Next (Token_Counter_List);
            Text_Io.New_Line (File);
        end loop;

    end Print;

begin
    Initialize;
end Misspelled_Word_List;