--
-- @filename dict_tda.adb
-- @author Julien Burdy & Vincent Decorges
-- @date 22.4.02
-- @brief A dictionary abstract data type implemantation
--
-- History  :
-- Date     Modification               Author
--
with Ada.Unchecked_Deallocation;
package body Dict_TDA is

   procedure Deallocate is
                  new Ada.Unchecked_Deallocation(Attribut_Type ,Dict_Type);


   -- Name    : Empty
   -- Purpose : Empty the dictionary
   --
   -- in out  : L : A dictionary
   -- return  : Dict_Type
   --
   procedure Empty (L : in out Dict_Type) is
   begin
      if L /= null then
         Empty(L.Next);
         Deallocate(L);
      end if;

   end Empty;

   --
   -- Name    : Run_Through
   -- Purpose : Run through the dict and call treat for each Key
   --
   -- in      : L : A dictionary
   --
   procedure Run_Through ( L : in Dict_Type) is
      List_Tmp : Dict_Type := L;
   begin

      while List_Tmp /= null loop
         Treat(List_Tmp.Key.all, List_Tmp.Value.all);
         List_Tmp := List_Tmp.Next;
      end loop;

   end Run_Through;

   --
   -- Name    : Exist
   -- Purpose : Return true if a key exist in the dictionary
   --
   -- in      : L : A dictionary
   -- in      : Key : Name of a key
   -- return  : Boolean
   --
   function Exist (L : Dict_Type; Key : String) return Boolean is
      List_Tmp : Dict_Type := L;
   begin
      while List_Tmp /= null loop
         if List_Tmp.Key /= null and then List_Tmp.Key.all = Key then
            return True;
         else
            List_Tmp := List_Tmp.Next;
         end if;
      end loop;
      return False;
   end Exist;


   --
   -- Name    : Insert
   -- Purpose : Insert an entry in the dictonary
   --
   -- in out  : L : A dictionary
   -- in      : Key : Name of a key
   -- in      : Value : Value asociate with the key
   --
   procedure Insert (L : in out Dict_Type; Key, Value : in String) is
   begin
      if not Exist(L, Key) then
         L := new Attribut_Type'(new String'(Key), new String'(Value), L);
      else
         raise Key_Error;
      end if;
   end Insert;

   --
   -- Name    : Delete
   -- Purpose : Delete a key and its value of the dictionary
   --           Raise Key_Error, if the key does not exist
   --
   -- in  out : L : A dictionary
   -- in      : Key : Name of a key
   --
   procedure Delete ( L : in out Dict_Type; Key : in String) is
      Current : Dict_Type := L;
      Pred : Dict_Type := L;

   begin

      while Current /= null and then Current.Key.all /= Key loop
         Pred := Current;
         Current := Current.Next;
      end loop;

      --We have found the element
      if Current.Key.all = Key then
         --In the head
         if L = Current then
            L := Current.Next;
            Deallocate(Current);
         else
            Pred.Next := Current.Next;
            Deallocate(Current);
         end if;
      else
         raise Key_Error;
      end if;

   end Delete;

   --
   -- Name    : Update
   -- Purpose : Update the value of a key
   --           if the key does not exist, insert the key
   --           in the dictionary
   --
   -- in out  : L : A dictionary
   -- in      : Key : Name of a key
   -- in      : Value : A value
   --
   procedure Update ( L : in out Dict_Type; Key, Value : in String) is

      Tmp : Dict_Type := L;

   begin

      while Tmp /= null loop

         if Key = Tmp.Key.all then
            Tmp.Value := new String'(Value);
            return;
         end if;

         Tmp := Tmp.Next;
      end loop;
      --The key does not exist we made an insertion
      Insert(L, Key, Value);


   end Update;

   --
   -- Name    : Copy_Of
   -- Purpose : Return a copy of L
   --
   -- in      : L : A dictionary
   -- return  : Dict_Type
   --
   function Copy_Of (L : Dict_Type) return Dict_Type is
      New_Dict : Dict_Type := Empty_Dict;
      Tmp : Dict_Type := L;
   begin
      while Tmp /= null loop
         Insert(New_Dict, Tmp.Key.All, Tmp.Value.All);
         Tmp := Tmp.Next;
      end loop;
      return New_Dict;
   end Copy_Of;


   --
   -- Name    : Put
   -- Purpose : Put the dictionary
   --
   -- in      : L : A dictionary
   --
   procedure Put (L : in Dict_Type; Target : in File_Type := Standard_Output) is
   begin
      if L /= Null then
         Put(Target, L.Key.All);Put(Target, " = ");
         Put_Line(Target, L.Value.All&" \\");
         Put(L.Next, Target);
      else
         Put_Line(Target, "End\\");
      end if;
   end Put;


   --
   -- Name    : Exist
   -- Purpose : Return the value of a key
   --           If the key don't exist return a null string ("")
   --
   -- in      : L : A dictionary
   -- in      : Key : Name of a key
   -- return  : String
   --
   function Value_Of (L : Dict_Type; Key : String) return String is
      List_Tmp : Dict_Type := L;
   begin
      while List_Tmp /= Null loop
         if List_Tmp.Key.All = Key then
            return List_Tmp.Value.All;
         else
            List_Tmp := List_Tmp.Next;
         end if;
      end loop;
      return "";
   end Value_Of;

   --
   -- Name    : Is_Empty
   -- Purpose : Return true if the dictionary is empty
   --
   -- in out  : L : A dictionary
   -- return  : Boolean
   --
   function Is_Empty (L : in Dict_Type) return Boolean is

   begin

      return L = null;

   end Is_Empty;

end Dict_TDA;

