--  Copyright (2008-2013) Cédric Coussinet (cedric.coussinet@nomoseed.net)
--
--  This program is free software: you can redistribute it and/or modify
--  it under the terms of the GNU Affero General Public License as published
--  by the Free Software Foundation, either version 3 of the License, or
--  (at your option) any later version.
--
--  This program is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
--  GNU Affero General Public License for more details.

--  You should have received a copy of the GNU Affero General Public License
--  along with this program. If not, see <http://www.gnu.org/licenses/>

with Nomo.Numerics.Reals;

with Nomo.Interpreter.Premises_Index;

package Nomo.Interpreter.Internal_Events_Index.Matchmakers is

   use Numerics.Reals;
   use Internal_Events_Index;
   use Premises_Index.Premises_Index_Instance;

   type Matchmaker is tagged limited private;

   --  La recherche de la distance minimale s'effectue de la manière suivante:
   --             pour chaque prémisse [
   --                 "New_Table"
   --                  pour chaque événement [ "Put_Pair" ]
   --             ]
   --             "Match"
   --             pour chaque prémisse [ "Get_Optimum_Pair" ]

   procedure Get_Optimum_Pair (This     : in out Matchmaker;
                               Event    : out Internal_Event_Index;
                               Premise  : out Premise_Index;
                               Distance : out Positive_Real);
   pragma Postcondition (Premise > 0);
   --  Renvoie la prémise avec sa distance qui contribue le moins à la distance
   --  globale, puis supprime la table correspondante.
   --  Une assertion vérifie qu'il n'y a pas plus d'appel que de table créée.

   function Last_Table_Have_Minimum (This : in Matchmaker) return Boolean;
   --  Renvoi faux si la dernière table enregistrée ne contient que des distances
   --  maximales (Positive'Last).

   function Last_Table_Have_Zero (This : in Matchmaker) return Boolean;
     --  Renvoi vrai si la dernière table enregistrée contient au moins une distance
     --  nulle.

   procedure Match (This : in out Matchmaker);
   --  Ordonne les données de façon à rechercher la combinaison minimisant
   --  la somme des distances des prémisses avec les événements.

   procedure New_Table (This    : in out Matchmaker;
                        Premise : in Premise_Index);
   pragma Precondition (Premise > 0);
   --  Créer une nouvelle table pour noter les distances entre une prémisse
   --  tous les événements possibles.

   procedure Put_Pair (This     : in out Matchmaker;
                       Event    : in Internal_Event_Index;
                       Distance : in Positive_Real);
   --  Note dans la dernière table créée la "Distance" et l'évenement associé.

   procedure Reset (This : out Matchmaker);

private

   subtype Result_Index is Positive range 1 .. Positive(Internal_Event_Index'Last);

   type Result is record
      Event    : Internal_Event_Index;
      Distance : Positive_Real;
   end record;

   type Results is array (Result_Index'Range) of Result;

   type Results_Register is record
      Table       : Results;
      Last_Result : Natural range 0 .. Natural(Internal_Event_Index'Last) := 0;
      Reference   : Premise_Index range 1 .. Premise_Index'Last;
   end record;

   type Results_Registers is array (1..Premise_Index'Last) of Results_Register;

   type Matchmaker is tagged limited record
      Form       : Results_Registers;
      Last_Table : Premise_Index := 0;
   end record;

end Nomo.Interpreter.Internal_Events_Index.Matchmakers;
