with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash_Case_Insensitive;

package Log4ada.Loggers.Labels is

   package Threshold_Maps is new Ada.Containers.Indefinite_Hashed_Maps (Key_Type => String,
                                                                        Element_Type => Level_Type,
                                                                        Hash => Ada.Strings.Hash_Case_Insensitive,
                                                                        Equivalent_Keys => "=",
                                                                        "=" => "=");

   type Label_Logger_Type is new Logger_Type with private;
   type Label_Logger_Class_Access is access all Label_Logger_Type'Class;
   type Label_Logger_Access is access all Label_Logger_Type;

   procedure Debug_Out
     (Logger : not null access Label_Logger_Type;
      Label : String;
      Message : String;
      Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
   procedure Info_Out
     (Logger : not null access Label_Logger_Type;
      Label : String;
      Message : String;
      Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
   procedure Warn_Out
     (Logger : not null access Label_Logger_Type;
      Label : String;
      Message : String;
      Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
   procedure Error_Out
     (Logger : not null access Label_Logger_Type;
      Label : String;
      Message : String;
      Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
   procedure Fatal_Out
     (Logger : not null access Label_Logger_Type;
      Label : String;
      Message : String;
      Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);

   procedure Debug_Out (Logger : not null access Label_Logger_Type;
                        Label : String;
                        Message : String);
   procedure Info_Out (Logger : not null access Label_Logger_Type;
                       Label : String;
                       Message : String);
   procedure Warn_Out (Logger : not null access Label_Logger_Type;
                       Label : String;
                       Message : String);
   procedure Error_Out (Logger : not null access Label_Logger_Type;
                        Label : String;
                        Message : String);
   procedure Fatal_Out (Logger : not null access Label_Logger_Type;
                        Label : String;
                        Message : String);

   procedure Set_Threshold (Logger : not null access Label_Logger_Type;
                            Label : String;
                            Level : Level_Type);
   function Get_Threshold (Logger : not null access Label_Logger_Type;
                           Label : String)
                          return Level_Type;
   function Get_Thresholds (Logger : not null access Label_Logger_Type) return Threshold_Maps.Map;
   procedure Set_Default_Threshold (Logger : not null access Label_Logger_Type;
                                    Level : Level_Type);

   generic
      type Enum_Type is (<>);
      Logger : not null access Label_Logger_Type'Class;
   package Enum_Logger is
      procedure Debug_Out
        (Kind : Enum_Type;
         Message : String;
         Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
      procedure Info_Out
        (Kind : Enum_Type;
         Message : String;
         Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
      procedure Warn_Out
        (Kind : Enum_Type;
         Message : String;
         Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
      procedure Error_Out
        (Kind : Enum_Type;
         Message : String;
         Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);
      procedure Fatal_Out
        (Kind : Enum_Type;
         Message : String;
         Exception_To_Send : Ada.Exceptions.Exception_Occurrence;
      With_Traces : Boolean := True);

      procedure Debug_Out (Kind : Enum_Type;
                           Message : String);
      procedure Info_Out (Kind : Enum_Type;
                          Message : String);
      procedure Warn_Out (Kind : Enum_Type;
                          Message : String);
      procedure Error_Out (Kind : Enum_Type;
                           Message : String);
      procedure Fatal_Out (Kind : Enum_Type;
                           Message : String);

      procedure Set_Threshold (Kind : Enum_Type;
                               Level : Level_Type);
      function Get_Threshold (Kind : Enum_Type) return Level_Type;
   end Enum_Logger;

private

   type Label_Logger_Type is new Logger_Type with record
      Thresholds : Threshold_Maps.Map;
   end record;

   function Is_Right_Label (Logger : not null access Label_Logger_Type;
                            Label : String;
                            Level : Log4ada.Level_Type) return Boolean is
      (Logger.Get_Threshold (Label) <= Level);

end Log4ada.Loggers.Labels;
