--  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.Interpreter.Plant.Operators;

with Nomo.Numerics.Reals.Long;
with Nomo.Numerics.Accurately.Constants;
with Nomo.Numerics.Reals.Elementary_Functions;

package body Nomo.Interpreter.External_Messages.Premises.Plant is

   use Numerics.Reals.Long;
   use Numerics.Accurately.Constants;
   use Numerics.Reals.Elementary_Functions;

   procedure Adjust_Trend (This        : in out External_Premise;
                           Fitting_Nbr : in Count) is
   begin
      for I in 1 .. This.Size loop
         if This.Tolerance (I) /= Zero_Plus and This.Tolerance (I) /= Positive_Infinity then
            This.Trend (I).Values_Sum :=  Long_Real (This.Information (I) * Real (Fitting_Nbr));
            This.Trend (I).Squares_Sum :=  Long_Real ((This.Information (I)**2 + This.Tolerance (I)) * Real (Fitting_Nbr));
         end if;
      end loop;
   end Adjust_Trend;

   procedure Readjust_Trend (This            : in out External_Premise;
                             Old_Fitting_Nbr : in Count;
                             Fitting_Nbr     : in Count) is
   begin
      for I in 1 .. This.Size loop
         This.Trend (I).Squares_Sum := This.Trend (I).Squares_Sum / Long_Real (Old_Fitting_Nbr);
         This.Trend (I).Squares_Sum := This.Trend (I).Squares_Sum * Long_Real (Fitting_Nbr);
      end loop;
   end Readjust_Trend;

   procedure Set (This     : out External_Premise;
                  Message  : in External_Message;
                  Size     : in Component_Index;
                  Operator : in Positive) is
      use Interpreter.Plant.Operators;
      Tolerance : Positive_Real renames External_Operators_With_Parameters (Operator).Information_Tolerance;
   begin
      This.Size := Size;
      This.Information (1 .. Size) := Message (1 .. Size);
      This.Specificity_Log := 0.0;
      for I in 1 .. Size loop
         This.Tolerance (I) := Tolerance;
         This.Trend (I).Values_Sum := Long_Real (Message (I));
         if Tolerance = Zero_Plus then
            This.Specificity_Log := This.Specificity_Log + Zero_Plus_Log;
         elsif Tolerance = Positive_Infinity then
            This.Specificity_Log := This.Specificity_Log + Positive_Infinity_Log;
         else
            This.Trend (I).Values_Sum :=  Long_Real (Message (I));
            This.Trend (I).Squares_Sum :=  Long_Real ((Message (I)**2 + Tolerance));
            This.Specificity_Log := This.Specificity_Log + Log_10 (Tolerance / 2.0);
         end if;
      end loop;
   end Set;

end Nomo.Interpreter.External_Messages.Premises.Plant;
