-- This Ada package body gives the implementation for the word abstract
-- data type.  A word is considered to be any consecutive sequence of
-- non-white-space characters.

with Ada.Text_IO; use Ada.Text_IO;
package body WordPkg is

   -- Creates a new word corresponding to the given string.
   function New_Word(Item : String) return Word is
      A_Word : word;
   begin
      A_Word.Letters(1..Item'Length) := Item;
      A_Word.Length := Item'Length;
      return A_Word;
   end New_Word;

    -- Turns a Word into a String
    -- Implemented as an expression function
    function To_String(Item : Word) return String is
       (Item.Letters(1 .. Item.length));
       --  Original stub:    ("");


   -- Indicates the number of characters in a word.
   function Length (Item : Word) return Natural is
   begin
      return Item.Length;
   end Length;

   -- Returns the maximum word size supported by this package.
   function Max_Word_Size return Positive is
   begin
      return MaxWordSize;
   end Max_Word_Size;

   -- Word comparison functions.  The dictionary lexiographic ordering
   -- is used to determine when one word is less than another.

   function "="  (X, Y : Word) return Boolean is
   begin
      return X.Length = Y.Length and then
         X.Letters(1..X.Length) = Y.Letters(1..Y.Length);
   end "=";

   function "<="  (X, Y : Word) return Boolean is
   begin
      For I in 1..Natural'Min (X.Length, Y.Length)  loop
         if X.Letters(I) < Y.Letters(I) then
            return True;
         elsif X.Letters(I) > Y.Letters(I) then
            return False;
         end if;
      end loop;
      return X.Length <= Y.Length;
   end "<=";

   function "<" (X, Y : Word) return Boolean is
   begin
      return X <= Y and not (X = Y);
   end "<";

   function ">=" (X, Y : Word) return Boolean is
   begin
      return not (X < Y);
   end ">=";

   function ">"  (X, Y : Word) return Boolean is
   begin
      return not (X <= Y);
   end ">";

   -- I/O routines

   -- Skip over any spaces, tabs, or end of line markers in the input to
   -- determine whether or not another word is present.  If another word
   -- is present, then return True, otherwise return False.
   function Another_Word (File : File_Type) return Boolean is
      C : Character;
      End_Line : Boolean;
   begin
      loop
         exit when End_Of_File (File);
         Look_Ahead (File, C, End_Line);
         if End_Line then
            Skip_Line (File);
         else
            if C /= ' ' and C /= ASCII.HT then
               return True;
            end if;
            Get (File, C);
         end if;
      end loop;
      return False;
   end Another_Word;

   -- Skip any white-space that may preceed the word in the input.
   -- If the word is too long to fit in the representation being
   -- used, then raise the WordTooLong exception after the characters
   -- of the word have been read (though not stored).
   procedure Get (File : File_Type; Item : out Word) is
      C : Character;
      End_Line : Boolean;
      TooLong : Boolean := False;
   begin
      Item.Length := 0;
      if Another_Word (File) then
         loop
            exit when End_Of_File (File);
            Look_Ahead (File, C, End_Line);

            exit when End_Line;
            exit when C = ' ' or else C = ASCII.HT;

            Get (File, C);

            -- Raise an exception if the word won't fit.
            if Item.Length = MaxWordSize then
               TooLong := True;
            end if;

            if not TooLong then
               Item.Length := Item.Length + 1;
               Item.Letters(Item.Length) := C;
            end if;
         end loop;
         if TooLong then
            raise WordTooLong;
         end if;
      end if;
   end Get;

   procedure Get (Item : out Word) is
   begin
      Get (Standard_Input, Item);
   end Get;

   -- Write only those characters that make up the word.
   procedure Put (File : File_Type; Item : Word) is
   begin
      For I in 1..Length(Item) loop
         Put (File, Item.Letters(I));
      end loop;
   end Put;

   procedure Put (Item : Word) is
   begin
      Put (Standard_Output, Item);
   end Put;

end WordPkg;