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

with Nomo.Internal_Messages.Premises;

with Nomo.Interpreter.Internal_Events;

with Nomo.Interpreter.Premises_Index.Arrays.Evaluation;

package body Nomo.Interpreter.Internal_Events_Index.Registers is

   use Premises_Index.Premises_Index_Instance;
   use Internal_Messages.Premises;

   procedure Discern_One_Excitation (Trace        : in Internal_Events_Array;
                                     Forked       : in Boolean;
                                     First        : in Internal_Event_Index;
                                     Last         : in Internal_Event_Index;
                                     Propositions : in out Internal_Premises;
                                     Designation  : in Premise_Index;
                                     Distance     : out Positive_Real);
   pragma Precondition (Designation > 0);

   procedure Discern_One_Excitation (Trace        : in Internal_Events_Array;
                                     Forked       : in Boolean;
                                     First        : in Internal_Event_Index;
                                     Last         : in Internal_Event_Index;
                                     Propositions : in out Internal_Premises;
                                     Designation  : in Premise_Index;
                                     Distance     : out Positive_Real) is
      use Internal_Events;
      use Premises_Index.Arrays.Evaluation;
      Buffer      : Positive_Real;
      Event_Scope : Internal_Event_Index := First;
      Proposition : Internal_Premise renames Get(Propositions, Designation).all;

      procedure Measure_Distance (I : in Internal_Event_Index);

      procedure Measure_Distance (I : in Internal_Event_Index) is
      begin
         Buffer := Proposition.Measure_Distance (To_Internal_Message (Trace (I)).all);
         if Buffer < Distance then
            Distance := Buffer;
            Event_Scope := I;
         end if;
      end Measure_Distance;

   begin
      Distance := Positive_Real'Last;
      if Forked then
         for I in First .. Internal_Events_Array'Last loop
            Measure_Distance (I);
         end loop;
         for I in Internal_Event_Index'First .. Last loop
            Measure_Distance (I);
         end loop;
      else
         for I in First .. Last loop
            Measure_Distance (I);
         end loop;
      end if;
      Note (Propositions, Designation, To_Internal_Message (Trace (Event_Scope)).all);
   end Discern_One_Excitation;

   procedure Discern_The_Excitations (Trace        : in Internal_Events_Array;
                                      Forked       : in Boolean;
                                      First        : in Internal_Event_Index;
                                      Last         : in Internal_Event_Index;
                                      Matchmaker   : in out Matchmakers.Matchmaker;
                                      Propositions : in out Internal_Premises;
                                      Designation  : in Premises_Focus;
                                      Distance     : out Positive_Real);

   procedure Discern_The_Excitations (Trace        : in Internal_Events_Array;
                                      Forked       : in Boolean;
                                      First        : in Internal_Event_Index;
                                      Last         : in Internal_Event_Index;
                                      Matchmaker   : in out Matchmakers.Matchmaker;
                                      Propositions : in out Internal_Premises;
                                      Designation  : in Premises_Focus;
                                      Distance     : out Positive_Real) is
      use Internal_Events;
      use Premises_Index.Arrays.Evaluation;
      Buffer                 : Positive_Real;
      Event_Scope            : Internal_Event_Index := First;
      Is_Resolved            : Boolean := False;
      Internal_Premise_Scope : Premise_Index range 1 .. Premise_Index'Last;
   begin
      for I in Designation.Get_First .. Designation.Get_Last loop
         Matchmaker.New_Table (I);
         declare
            Proposition : Internal_Premise renames Get(Propositions, I).all;
         begin
            if Forked then
               for J in First .. Internal_Events_Array'Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
               for J in Internal_Events_Array'First .. Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
            else
               for J in First .. Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
            end if;
         end;
         if not Matchmaker.Last_Table_Have_Minimum then
            Is_Resolved := True;
            Matchmaker.Reset;
            exit;
         end if;
      end loop;
      if Is_Resolved then
         Distance := Positive_Real'Last;
      else
         Matchmaker.Match;
         Distance := 0.0;
         for I in Designation.Get_First .. Designation.Get_Last loop
            Matchmaker.Get_Optimum_Pair (Event_Scope, Internal_Premise_Scope, Buffer);
            Distance := Distance + Buffer;
            Note (Propositions, Internal_Premise_Scope, To_Internal_Message (Trace (Event_Scope)).all);
         end loop;
      end if;
   end Discern_The_Excitations;

   procedure Discern_Exciting_Evidences (This         : in Internal_Register;
                                         Matchmaker   : not null access Matchmakers.Matchmaker;
                                         Propositions : not null access Internal_Premises;
                                         Designation  : in Premises_Focus;
                                         Distance     : out Positive_Real) is
      use Premises_Index.Arrays.Evaluation;
      Premises_Number : constant Positive := Positive (Designation.Get_Size);
   begin
      if This.Evidences_Number >= Premises_Number then
         if Premises_Number = 1 then
            Discern_One_Excitation (This.Trace,
                                    This.Forked_Evidences,
                                    This.Most_Ancient_Evidence,
                                    This.Current_Evidence,
                                    Propositions.all,
                                    Designation.Get_First,
                                    Distance);
         else
            Discern_The_Excitations (This.Trace,
                                     This.Forked_Evidences,
                                     This.Most_Ancient_Evidence,
                                     This.Current_Evidence,
                                     Matchmaker.all,
                                     Propositions.all,
                                     Designation,
                                     Distance);
         end if;
      else
         Distance := Positive_Real'Last;
      end if;
   end Discern_Exciting_Evidences;

   procedure Discern_Exciting_Intentions (This           : in Internal_Register;
                                          Matchmaker     : not null access Matchmakers.Matchmaker;
                                          Propositions   : not null access Premises_Index.Arrays.Internal_Premises;
                                          Designation    : in Premises_Index.Focus.Premises_Focus;
                                          Distance       : out Positive_Real) is
      Premises_Number : constant Positive := Positive(Designation.Get_Size);
   begin
      if This.Intentions_Number >= Premises_Number then
         if Premises_Number = 1 then
            Discern_One_Excitation (This.Trace,
                                    This.Forked_Intentions,
                                    Internal_Event_Index (Natural (This.Current_Evidence + 1) mod Index_Modulo),
                                    This.Last_Intention,
                                    Propositions.all,
                                    Designation.Get_First,
                                    Distance);
         else
            Discern_The_Excitations (This.Trace,
                                     This.Forked_Intentions,
                                     Internal_Event_Index (Natural (This.Current_Evidence + 1) mod Index_Modulo),
                                     This.Last_Intention,
                                     Matchmaker.all,
                                     Propositions.all,
                                     Designation,
                                     Distance);
         end if;
      else
         Distance := Positive_Real'Last;
      end if;
   end Discern_Exciting_Intentions;

   procedure Discern_One_Inhibition (Trace       : in Internal_Events_Array;
                                     Forked      : in Boolean;
                                     First       : in Internal_Event_Index;
                                     Last        : in Internal_Event_Index;
                                     Proposition : in Internal_Premise;
                                     Score       : out Positive_Real);

   procedure Discern_One_Inhibition (Trace       : in Internal_Events_Array;
                                     Forked      : in Boolean;
                                     First       : in Internal_Event_Index;
                                     Last        : in Internal_Event_Index;
                                     Proposition : in Internal_Premise;
                                     Score       : out Positive_Real) is
      use Internal_Events;
      use Numerics.Reals.Elementary_Functions;
      use Premises_Index.Arrays.Evaluation;
      Distance     : Positive_Real;
      Buffer       : Positive_Real;

      procedure Measure_Distance (I : in Internal_Event_Index);

      procedure Measure_Distance (I : in Internal_Event_Index) is
      begin
         Buffer := Proposition.Measure_Distance (To_Internal_Message (Trace (I)).all);
         if Buffer < Distance then
            Distance := Buffer;
         end if;
      end Measure_Distance;

   begin
      Distance := Positive_Real'Last;
      if Forked then
         for I in First .. Internal_Events_Array'Last loop
            Measure_Distance (I);
         end loop;
         for I in Internal_Events_Array'First .. Last loop
            Measure_Distance (I);
         end loop;
      else
         for I in First .. Last loop
            Measure_Distance (I);
         end loop;
      end if;
      Score := Exp (-Distance);
   end Discern_One_Inhibition;

   procedure Discern_The_Inhibitions (Trace        : in Internal_Events_Array;
                                      Forked       : in Boolean;
                                      First        : in Internal_Event_Index;
                                      Last         : in Internal_Event_Index;
                                      Matchmaker   : in out Matchmakers.Matchmaker;
                                      Propositions : in Internal_Premises;
                                      Designation  : in Premises_Focus;
                                      Score        : out Positive_Real);

   procedure Discern_The_Inhibitions (Trace        : in Internal_Events_Array;
                                      Forked       : in Boolean;
                                      First        : in Internal_Event_Index;
                                      Last         : in Internal_Event_Index;
                                      Matchmaker   : in out Matchmakers.Matchmaker;
                                      Propositions : in Internal_Premises;
                                      Designation  : in Premises_Focus;
                                      Score        : out Positive_Real) is
      use Internal_Events;
      use Numerics.Reals.Elementary_Functions;
      use Premises_Index.Arrays.Evaluation;
      Distance                : Positive_Real;
      Event_Scope             : Internal_Event_Index := First;
      Is_Resolved             : Boolean := False;
      Have_Minimum            : Boolean := False;
      Internal_Premise_Scope  : Premise_Index;
   begin
      for I in Designation.Get_First .. Designation.Get_Last loop
         Matchmaker.New_Table (I);
         declare
            Proposition : Internal_Premise renames Get(Propositions, I).all;
         begin
            if Forked then
               for J in First .. Internal_Events_Array'Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
               for J in Internal_Events_Array'First .. Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
            else
               for J in First .. Last loop
                  Matchmaker.Put_Pair (J, Proposition.Measure_Distance (To_Internal_Message (Trace (J)).all));
               end loop;
            end if;
         end;
         if Matchmaker.Last_Table_Have_Zero then
            Is_Resolved := True;
            Matchmaker.Reset;
            exit;
         end if;
         if not Have_Minimum then
            Have_Minimum := Matchmaker.Last_Table_Have_Minimum;
         end if;
      end loop;
      if Is_Resolved then
         Score := 1.0;
      else
         Score := 0.0;
         if Have_Minimum then
            Matchmaker.Match;
            for I in Designation.Get_First .. Designation.Get_Last loop
               Matchmaker.Get_Optimum_Pair (Event_Scope, Internal_Premise_Scope, Distance);
               Score := Score + Exp (-Distance);
            end loop;
         else
            Matchmaker.Reset;
         end if;
      end if;
   end Discern_The_Inhibitions;

   procedure Discern_Inhibiting_Evidences (This         : in Internal_Register;
                                           Matchmaker   : not null access Matchmakers.Matchmaker;
                                           Propositions : not null access constant Internal_Premises;
                                           Designation  : in Premises_Focus;
                                           Score        : out Positive_Real) is
      use Premises_Index.Arrays.Evaluation;
   begin
      if This.Evidences_Number /= 0 then
         if Designation.Get_Size = 1 then
            Discern_One_Inhibition (This.Trace,
                                    This.Forked_Evidences,
                                    This.Most_Ancient_Evidence,
                                    This.Current_Evidence,
                                    Get (Propositions.all, Designation.Get_First).all,
                                    Score);
         else
            Discern_The_Inhibitions (This.Trace,
                                     This.Forked_Evidences,
                                     This.Most_Ancient_Evidence,
                                     This.Current_Evidence,
                                     Matchmaker.all,
                                     Propositions.all,
                                     Designation,
                                     Score);
         end if;
      else
         Score := 0.0;
      end if;
   end Discern_Inhibiting_Evidences;

   procedure Discern_Inhibiting_Intentions (This         : in Internal_Register;
                                            Matchmaker   : not null access Matchmakers.Matchmaker;
                                            Propositions : not null access constant Internal_Premises;
                                            Designation  : in Premises_Focus;
                                            Score        : out Positive_Real) is
      use Premises_Index.Arrays.Evaluation;
   begin
      if This.Intentions_Number /= 0 then
         if Designation.Get_Size = 1 then
            Discern_One_Inhibition (This.Trace,
                                    This.Forked_Intentions,
                                    Internal_Event_Index (Natural(This.Current_Evidence + 1) mod Index_Modulo),
                                    This.Last_Intention,
                                    Get(Propositions.all, Designation.Get_First).all,
                                    Score);
         else
            Discern_The_Inhibitions (This.Trace,
                                     This.Forked_Intentions,
                                     Internal_Event_Index (Natural(This.Current_Evidence + 1) mod Index_Modulo),
                                     This.Last_Intention,
                                     Matchmaker.all,
                                     Propositions.all,
                                     Designation,
                                     Score);
         end if;
      else
         Score := 0.0;
      end if;
   end Discern_Inhibiting_Intentions;

   procedure Put_Forked_Intentions (Trace              : in Internal_Events_Array;
                                    Current_Evidence   : in Internal_Event_Index;
                                    Last_Intention     : in Internal_Event_Index;
                                    New_Last_Intention : in out Internal_Event_Index;
                                    Forked_Intentions  : in out Boolean;
                                    Arrival_Time       : in Positive_Time);

   procedure Put_Forked_Intentions (Trace              : in Internal_Events_Array;
                                    Current_Evidence   : in Internal_Event_Index;
                                    Last_Intention     : in Internal_Event_Index;
                                    New_Last_Intention : in out Internal_Event_Index;
                                    Forked_Intentions  : in out Boolean;
                                    Arrival_Time       : in Positive_Time) is
      use Internal_Events;
      Not_Found : Boolean := True;
   begin
      for I in reverse Internal_Event_Index'First .. Last_Intention loop
         if Trace (I).Before (Arrival_Time) then
            Not_Found := False;
            New_Last_Intention := I + 1;
            exit;
         end if;
      end loop;
      if Not_Found then
         for I in reverse Current_Evidence .. Internal_Events_Array'Last loop
            if Trace (I).Before (Arrival_Time) then
               New_Last_Intention := Internal_Event_Index (Natural (I + 1) mod Index_Modulo);
               exit;
            end if;
         end loop;
         Forked_Intentions :=  New_Last_Intention < Current_Evidence and then Current_Evidence /= Internal_Event_Index'Last;
      end if;
   end Put_Forked_Intentions;

   procedure Put_Unforked_Intentions (Trace              : in Internal_Events_Array;
                                      Current_Evidence   : in Internal_Event_Index;
                                      Last_Intention     : in Internal_Event_Index;
                                      New_Last_Intention : in out Internal_Event_Index;
                                      Forked_Intentions  : in out Boolean;
                                      Arrival_Time       : in Positive_Time);
   pragma Precondition (Last_Intention >= Current_Evidence);

   procedure Put_Unforked_Intentions (Trace              : in Internal_Events_Array;
                                      Current_Evidence   : in Internal_Event_Index;
                                      Last_Intention     : in Internal_Event_Index;
                                      New_Last_Intention : in out Internal_Event_Index;
                                      Forked_Intentions  : in out Boolean;
                                      Arrival_Time       : in Positive_Time) is
      use Internal_Events;
   begin
      for I in reverse Current_Evidence .. Last_Intention loop
         if Trace (I).Before (Arrival_Time) then
            New_Last_Intention := Internal_Event_Index (Natural (I + 1) mod Index_Modulo);
            exit;
         end if;
      end loop;
      Forked_Intentions :=  New_Last_Intention < Current_Evidence and then Current_Evidence /= Internal_Event_Index'Last;
   end Put_Unforked_Intentions;

   procedure Put_Event (This         : in out Internal_Register;
                        Content      : in Internal_Messages.Internal_Message;
                        Arrival_Time : in Positive_Time) is
      New_Last_Intention : Internal_Event_Index := Internal_Event_Index (Natural (This.Last_Intention + 1) mod Index_Modulo);
      Trace              : Internal_Events_Array renames This.Trace;
   begin
      if This.Forked_Intentions or else (This.Current_Evidence = Internal_Event_Index'Last and then This.Last_Intention /= This.Current_Evidence) then
         Put_Forked_Intentions (Trace,
                                This.Current_Evidence,
                                This.Last_Intention,
                                New_Last_Intention,
                                This.Forked_Intentions,
                                Arrival_Time);
      else
         Put_Unforked_Intentions (Trace,
                                  This.Current_Evidence,
                                  This.Last_Intention,
                                  New_Last_Intention,
                                  This.Forked_Intentions,
                                  Arrival_Time);
      end if;
      if This.Most_Ancient_Evidence = Internal_Event_Index (Natural (New_Last_Intention + 1) mod Index_Modulo) then
         if This.Evidences_Number /= 0 then
            This.Most_Ancient_Evidence := Internal_Event_Index (Natural (This.Most_Ancient_Evidence + 1) mod Index_Modulo);
         end if;
      end if;
      This.Last_Intention := New_Last_Intention;
      Trace (New_Last_Intention).Set_Event (Content, Arrival_Time);
      This.Intentions_Number := Integer (This.Last_Intention - This.Current_Evidence) mod Index_Modulo;
   end Put_Event;

   procedure Update_Forked_Evidences (Trace                     : in out Internal_Events_Array;
                                      Current_Evidence          : in Internal_Event_Index;
                                      Most_Ancient_Evidence     : in Internal_Event_Index;
                                      New_Most_Ancient_Evidence : in out Internal_Event_Index;
                                      T                         : in Positive_Time);

   procedure Update_Forked_Evidences (Trace                     : in out Internal_Events_Array;
                                      Current_Evidence          : in Internal_Event_Index;
                                      Most_Ancient_Evidence     : in Internal_Event_Index;
                                      New_Most_Ancient_Evidence : in out Internal_Event_Index;
                                      T                         : in Positive_Time) is
      Not_Found : Boolean := True;
   begin
      for I in Most_Ancient_Evidence .. Internal_Events_Array'Last loop
         if Trace (I).Not_Expired (T) then
            New_Most_Ancient_Evidence := I;
            Not_Found := False;
            for J in New_Most_Ancient_Evidence .. Internal_Events_Array'Last loop
               Trace (J).Update_Time_Span (T);
            end loop;
            for J in Internal_Event_Index'First .. Current_Evidence loop
               Trace (J).Update_Time_Span (T);
            end loop;
            exit;
         end if;
      end loop;
      if Not_Found then
         for I in Internal_Events_Array'First .. Current_Evidence loop
            if Trace (I).Not_Expired (T) then
               New_Most_Ancient_Evidence := I;
               for J in New_Most_Ancient_Evidence .. Current_Evidence loop
                  Trace (J).Update_Time_Span (T);
               end loop;
               exit;
            end if;
         end loop;
      end if;
   end Update_Forked_Evidences;

   procedure Update_Unforked_Evidences (Trace                     : in out Internal_Events_Array;
                                        Current_Evidence          : in Internal_Event_Index;
                                        Most_Ancient_Evidence     : in Internal_Event_Index;
                                        New_Most_Ancient_Evidence : in out Internal_Event_Index;
                                        T                         : in Positive_Time);

   procedure Update_Unforked_Evidences (Trace                     : in out Internal_Events_Array;
                                        Current_Evidence          : in Internal_Event_Index;
                                        Most_Ancient_Evidence     : in Internal_Event_Index;
                                        New_Most_Ancient_Evidence : in out Internal_Event_Index;
                                        T                         : in Positive_Time) is
   begin
      for I in Most_Ancient_Evidence .. Current_Evidence  loop
         if Trace (I).Not_Expired (T) then
            New_Most_Ancient_Evidence := I;
            for J in New_Most_Ancient_Evidence .. Current_Evidence loop
               Trace (J).Update_Time_Span (T);
            end loop;
            exit;
         end if;
      end loop;
   end Update_Unforked_Evidences;

   procedure Update_Forked_Intentions (Trace                : in out Internal_Events_Array;
                                       Current_Evidence     : in Internal_Event_Index;
                                       Last_Intention       : in Internal_Event_Index;
                                       New_Current_Evidence : in out Internal_Event_Index;
                                       T                    : in Positive_Time);

   procedure Update_Forked_Intentions (Trace                : in out Internal_Events_Array;
                                       Current_Evidence     : in Internal_Event_Index;
                                       Last_Intention       : in Internal_Event_Index;
                                       New_Current_Evidence : in out Internal_Event_Index;
                                       T                    : in Positive_Time) is
      Not_Found : Boolean := True;
   begin
      for I in Current_Evidence + 1 .. Internal_Events_Array'Last loop
         if Trace (I).After (T) then
            Trace (I).Update_Time_Span (T);
            Not_Found := False;
            New_Current_Evidence := I - 1;
            for J in I + 1 .. Internal_Events_Array'Last loop
               Trace (J).Update_Time_Span (T);
            end loop;
            for J in Internal_Events_Array'First .. Last_Intention loop
               Trace (J).Update_Time_Span (T);
            end loop;
            exit;
         else
            Trace (I).Reset_Time_Span;
         end if;
      end loop;
      if Not_Found then
         for I in Internal_Events_Array'First .. Last_Intention loop
            if Trace (I).After (T) then
               Trace (I).Update_Time_Span (T);
               New_Current_Evidence := Internal_Event_Index (Integer (I - 1) mod Index_Modulo);
               for J in Internal_Event_Index (Natural (I + 1) mod Index_Modulo) .. Last_Intention loop
                  Trace (J).Update_Time_Span (T);
               end loop;
               exit;
            else
               Trace (I).Reset_Time_Span;
            end if;
         end loop;
      end if;
   end Update_Forked_Intentions;

   procedure Update_Unforked_Intentions (Trace                : in out Internal_Events_Array;
                                         Current_Evidence     : in Internal_Event_Index;
                                         Last_Intention       : in Internal_Event_Index;
                                         New_Current_Evidence : in out Internal_Event_Index;
                                         T                    : in Positive_Time);

   procedure Update_Unforked_Intentions (Trace                : in out Internal_Events_Array;
                                         Current_Evidence     : in Internal_Event_Index;
                                         Last_Intention       : in Internal_Event_Index;
                                         New_Current_Evidence : in out Internal_Event_Index;
                                         T                    : in Positive_Time) is
   begin
      for I in Current_Evidence + 1 .. Last_Intention loop
         if Trace (I).After (T) then
            New_Current_Evidence := I - 1;
            for J in I .. Last_Intention loop
               Trace (J).Update_Time_Span (T);
            end loop;
            exit;
         else
            Trace (I).Reset_Time_Span;
         end if;
      end loop;
   end Update_Unforked_Intentions;

   procedure Update (This : in out Internal_Register;
                     T    : in Positive_Time) is
      New_Current_Evidence      : Internal_Event_Index := This.Current_Evidence;
      New_Most_Ancient_Evidence : Internal_Event_Index := Internal_Event_Index (Natural (This.Current_Evidence + 1) mod Index_Modulo);
   begin
      if New_Most_Ancient_Evidence /= This.Most_Ancient_Evidence then
         if This.Forked_Evidences then
            Update_Forked_Evidences(This.Trace,
                                    This.Current_Evidence,
                                    This.Most_Ancient_Evidence,
                                    New_Most_Ancient_Evidence,
                                    T);
         else
            Update_Unforked_Evidences(This.Trace,
                                      This.Current_Evidence,
                                      This.Most_Ancient_Evidence,
                                      New_Most_Ancient_Evidence,
                                      T);
         end if;
         This.Most_Ancient_Evidence := New_Most_Ancient_Evidence;
      end if;
      if This.Last_Intention /= This.Current_Evidence then
         New_Current_Evidence := This.Last_Intention;
         if This.Forked_Intentions or else (This.Current_Evidence = Internal_Event_Index'Last and then This.Last_Intention /= This.Current_Evidence) then
            Update_Forked_Intentions(This.Trace,
                                     This.Current_Evidence,
                                     This.Last_Intention,
                                     New_Current_Evidence,
                                     T);
         else
            Update_Unforked_Intentions(This.Trace,
                                       This.Current_Evidence,
                                       This.Last_Intention,
                                       New_Current_Evidence,
                                       T);
         end if;
         This.Forked_Intentions :=   This.Last_Intention  < New_Current_Evidence and then New_Current_Evidence /= Internal_Event_Index'Last;
         This.Intentions_Number := Integer (This.Last_Intention - New_Current_Evidence) mod Index_Modulo;
      end if;
      This.Evidences_Number := Integer (New_Current_Evidence + 1 - New_Most_Ancient_Evidence) mod Index_Modulo;
      This.Forked_Evidences := (This.Evidences_Number > 0 and  New_Most_Ancient_Evidence > New_Current_Evidence) or else (This.Evidences_Number = 0 and New_Most_Ancient_Evidence < New_Current_Evidence);
      This.Current_Evidence := New_Current_Evidence;
   end Update;

end Nomo.Interpreter.Internal_Events_Index.Registers;
