--  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.Elementary_Functions;

package body Nomo.Internal_Messages.Premises.Gen_Checking is


   procedure Get_Actuator (This        : in Internal_Premise;
                           Time_Span   : out Time_Interval;
                           Credibility : out Real_0_To_1) is
   begin
      Time_Span := This.Actuator_Time_Span;
      Credibility := This.Actuator_Credibility;
   end Get_Actuator;

   procedure Get_New_Time_Span (Landmark  : in Internal_Premise;
                                Time_Span : out Positive_Time_Interval;
                                Bonus     : out Positive_Time_Interval) is
      use Numerics.Reals.Elementary_Functions;
   begin
      Time_Span := Landmark.Time_Span;
      Bonus := Positive_Time_Interval (Check_Cover * Sqrt (Real (Landmark.Time_Span_Tolerance)));
      --  "Check_Cover" a déjà été divisé par deux donc pas besoin de diviser par 2 la tolérance
   end Get_New_Time_Span;

   procedure Maximize_Border_Cover (Diff            : in Positive_Time;
                                    Fitting_Nbr     : in Positive_Time;
                                    Time_Span       : in Time;
                                    Specificity_Log : out Real_Accurately;
                                    Squares_Sum     : in out Positive_Time;
                                    Tolerance       : out Strictly_Positive_Real;
                                    Values_Sum      : in out Time);
   --  Dans "Maximize_Border_Cover", on considère que la tolérance concernant
   --  l'information et la crédibilité est soit nul soit infini, par conséquent
   --  seule l'étiquette temporelle est maximisée.

   procedure Maximize_Border_Cover (Diff            : in Positive_Time;
                                    Fitting_Nbr     : in Positive_Time;
                                    Time_Span       : in Time;
                                    Specificity_Log : out Real_Accurately;
                                    Squares_Sum     : in out Positive_Time;
                                    Tolerance       : out Strictly_Positive_Real;
                                    Values_Sum      : in out Time) is
      use Numerics.Reals.Elementary_Functions;
      Temp : Strictly_Positive_Real;
   begin
      Values_Sum := Values_Sum + Time_Span;
      Squares_Sum := Squares_Sum + (2 * (Time_Span ** 2 + Diff ** 2) * Fitting_Nbr - Squares_Sum) / (Fitting_Nbr + 1);
      Temp := Strictly_Positive_Real (Squares_Sum / Fitting_Nbr - Time_Span ** 2);
      Tolerance := Temp * 2.0;
      Specificity_Log := Log_10 ( Temp);
   end Maximize_Border_Cover;

   procedure Maximize_Landmark (This        : in out Internal_Premise;
                                Fitting_Nbr : in Count) is
      use Numerics.Reals.Elementary_Functions;
      Diff : constant Time_Interval := This.Time_Span - This.Actuator_Time_Span;
   begin
      if Diff > Time_Interval (Check_Cover * Sqrt(Real (This.Time_Span_Tolerance))) then
         Maximize_Border_Cover (Time (Diff),
                                Positive_Time (Fitting_Nbr),
                                Time (This.Time_Span),
                                This.Specificity_Log,
                                This.Time_Span_Trend.Squares_Sum,
                                This.Time_Span_Tolerance,
                                This.Time_Span_Trend.Values_Sum);
      else
         Maximize_Time_Span (This.Actuator_Time_Span,
                             Fitting_Nbr,
                             This.Time_Span,
                             This.Specificity_Log,
                             This.Time_Span_Trend.Squares_Sum,
                             This.Time_Span_Tolerance,
                             This.Time_Span_Trend.Values_Sum);
      end if;
   end Maximize_Landmark;

   procedure Set_Actuator (This        : out Internal_Premise;
                           Time_Span   : in Time_Interval;
                           Credibility : in Real_0_To_1) is
   begin
      This.Actuator_Time_Span := Time_Span;
      This.Actuator_Credibility := Credibility;
   end Set_Actuator;

end Nomo.Internal_Messages.Premises.Gen_Checking;
