--  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.Conditions_Base.Evaluation;

with Nomo.Interpreter.Conditions_Base.Perceptive;

with Nomo.Interpreter.Event_Memory.External.Discernment;

package body Nomo.Interpreter.Perception_Conditions is

   use Numerics.Reals;

   procedure Discern (This                : in out Perception_Condition;
                      Excitatory_Distance : in out Positive_Real);
   pragma Inline(Discern);

   procedure Discern (This                : in out Perception_Condition;
                      Excitatory_Distance : in out Positive_Real) is
      use Event_Memory.External;
   begin
      This.Input_Premise.Note (Discernment.Get_Current_Event (This.Input_Type).all);
      Excitatory_Distance := Excitatory_Distance + This.Input_Premise.Measure_Distance (Discernment.Get_Current_Event (This.Input_Type).all);
   end Discern;

   procedure Evaluate (This  : in out Perception_Condition) is
      use Conditions_Base.Evaluation;
      Inhibitory_Score    : Positive_Real := 0.0;
      Excitatory_Distance : Positive_Real := 0.0;
   begin
      Reset_Score (Condition_Base (This));
      Evaluate_Internal_Inhibiting_Intentions (Condition_Base (This), Inhibitory_Score);
      if Inhibitory_Score < 1.0 then
         Evaluate_Internal_Inhibiting_Evidences (Condition_Base (This), Inhibitory_Score);
         if Inhibitory_Score < 1.0 then
            Evaluate_Internal_Exciting_Intentions (Condition_Base (This), Inhibitory_Score, Excitatory_Distance);
            if Inhibitory_Score < 1.0 then
               Evaluate_Internal_Exciting_Evidences (Condition_Base (This), Inhibitory_Score, Excitatory_Distance);
               if Inhibitory_Score < 1.0 then
                  Discern (This, Excitatory_Distance);
                  Subtract (Condition_Base (This), Excitatory_Distance, Inhibitory_Score);
               end if;
            end if;
         end if;
      end if;
   end Evaluate;

   procedure Evaluate (This  : in out Perception_Condition;
                       Shift : in Real_Accurately) is
      use Conditions_Base.Evaluation;
      Inhibitory_Score    : Positive_Real := 0.0;
      Excitatory_Distance : Positive_Real := 0.0;
   begin
      Reset_Score (Condition_Base (This));
      Evaluate_Internal_Inhibiting_Intentions (Condition_Base (This), Inhibitory_Score);
      if Inhibitory_Score < 1.0 then
         Evaluate_Internal_Inhibiting_Evidences (Condition_Base (This), Inhibitory_Score);
         if Inhibitory_Score < 1.0 then
            Evaluate_Internal_Exciting_Intentions (Condition_Base (This), Inhibitory_Score, Excitatory_Distance);
            if Inhibitory_Score < 1.0 then
               Evaluate_Internal_Exciting_Evidences (Condition_Base (This), Inhibitory_Score, Excitatory_Distance);
               if Inhibitory_Score < 1.0 then
                  Discern (This, Excitatory_Distance);
                  Subtract (Condition_Base (This), Excitatory_Distance, Inhibitory_Score, Shift);
               end if;
            end if;
         end if;
      end if;
   end Evaluate;

   procedure Maximize (This : in out Perception_Condition) is
      use Conditions_Base.Perceptive;
   begin
      Maximize (Condition_Base (This));
      This.Input_Premise.Maximize (Get_Fitting_Nbr (This));
      Adjust_Specificity_Log (This, This.Input_Premise.Get_Specificity_Log);
   end Maximize;

end Nomo.Interpreter.Perception_Conditions;
