with Ada.Containers.Ordered_Maps;
pragma Elaborate_All (Ada.Containers.Ordered_Maps);

with Ada.Containers.Indefinite_Ordered_Maps;
pragma Elaborate_All (Ada.Containers.Indefinite_Ordered_Maps);

with Ada.Containers.Indefinite_Ordered_Multisets;
pragma Elaborate_All (Ada.Containers.Indefinite_Ordered_Multisets);

with Ada.Strings.Equal_Case_Insensitive;
with Ada.Strings.Less_Case_Insensitive;

package Relation_Maps is
   pragma Elaborate_Body;

   type Map (<>) is limited private;
   type Set (<>) is limited private;

   type Set_Cursor is private;

   procedure Insert
     (Container : Map;
      Key       : String);  --make empty set for key

   function Insert
     (Container : Map;
      Key       : String) return Set;

   function Contains
     (Container : Map;
      Key       : String) return Boolean;

   function Element
     (Container : Map;
      Key       : String) return Set;

   procedure Iterate
     (Container : in Map;
      Process   : not null access procedure (Key : in String; Elements : in Set));

   procedure Iterate
     (Container : Map;
      Key       : String;
      Process   : not null access procedure (Name : in String));


   procedure Insert       --map[key].insert(new_name)
     (Container : Map;
      Key       : String;
      New_Name  : String);

   procedure Insert
     (Container : Set;
      New_Name  : String);

   function Contains
    (Container : Set;
     Name      : String) return Boolean;

   function First (Container : Set) return Set_Cursor;

   function First_Element (Container : Set) return String;

   procedure Next (Position : in out Set_Cursor);

   function Has_Element (Position : Set_Cursor) return Boolean;

   function Element (Position : Set_Cursor) return String;

   function Length (Container : Set) return Ada.Containers.Count_Type;

   procedure Iterate
     (Container : in Set;
      Process   : not null access procedure (Name : in String));


   function Students return Map;
   function Advisors return Map;

private

   function Compare_Dates (L_Name, R_Name : String) return Boolean;

   package String_Sets is
      new Ada.Containers.Indefinite_Ordered_Multisets
       (String,
        "<" => Compare_Dates,
        "=" => Ada.Strings.Equal_Case_Insensitive);

   use String_Sets;

   package Map_Types is
     new Ada.Containers.Indefinite_Ordered_Maps
       (String,
        String_Sets.Set,
        "<" => Ada.Strings.Less_Case_Insensitive);

   type Map is access all Map_Types.Map;
   for Map'Storage_Size use 0;

   type Set is new Map_Types.Cursor;
   type Set_Cursor is new String_Sets.Cursor;

end Relation_Maps;

