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

with Nomo.Interpreter.Plant.Internal_Chunks_Register;

with Nomo.Interpreter.Plant.External_Chunk;

with Nomo.Interpreter.Plant.Errors_Manager;

with Nomo.Interpreter.Plant.Rule_Buffer.Writing;

package body Nomo.Interpreter.Plant.Chunks_Memory is

   Reference_Chunk : Chunk_Index;

   procedure Active_Chunk (I         : in Chunk_Index;
                           Operation : in Positive_Integer) is
   begin
      if I = 1 then
         External_Chunk.Set_Operation (Operation);
      else
         Internal_Chunks_Register.Set_Operation (I, Operation);
      end if;
   end Active_Chunk;

   procedure Cancel is
   begin
      External_Chunk.Cancel;
      Internal_Chunks_Register.Cancel;
   end Cancel;

   procedure End_Affectations is
      use Errors_Manager;
   begin
      if Affectation_Manager.Has_Reference_Chunk then
         Reference_Chunk:= Affectation_Manager.Get_Reference_Chunk;
         if Reference_Chunk = 1 then
            External_Chunk.Set_Temporal_Reference (Affectation_Manager.Is_Reference_And_Origin);
         else
            Internal_Chunks_Register.Set_Temporal_Reference (Reference_Chunk, Affectation_Manager.Is_Reference_And_Origin);
         end if;
      end if;
   end End_Affectations;

   procedure New_Affectations is
   begin
      Affectation_Manager.New_Affectation;
      Rule_Buffer.Writing.Reset_Storage;
   end New_Affectations;

   procedure Send_In_Conclusion is
   begin
      if Affectation_Manager.Has_Reference_Chunk then
         Internal_Chunks_Register.Send_In_Conclusion (Reference_Chunk);
      else
         Internal_Chunks_Register.Send_In_Conclusion;
      end if;
   end Send_In_Conclusion;

   procedure Send_In_Excitatory_Condition is
   begin
      External_Chunk.Send_In_Excitatory_Condition;
      Internal_Chunks_Register.Send_In_Excitatory_Condition;
   end Send_In_Excitatory_Condition;

   procedure Send_In_Inhibitory_Condition is
      use Errors_Manager;
   begin
      if External_Chunk.Is_Active then
         Error (INPUT_PREMISE_IN_INHIBITORY_PREMISE);
      end if;
      Internal_Chunks_Register.Send_In_Inhibitory_Condition;
   end Send_In_Inhibitory_Condition;

   procedure Update_Affectations (T : in Positive_Time) is
      use Errors_Manager;
   begin
      --  External_Chunk.Registery doit être appellé avant Internal_Chunks_Register.Registry
      --  afin de répondre au cas où un item sensitif arrive en même temps qu'une création
      --  d'une perception.
      Affectation_Manager.New_Update;
      External_Chunk.Registry;
      Internal_Chunks_Register.Registry;
      if Affectation_Manager.Has_Targeted_Internal then
         if Internal_Chunks_Register.Is_Expired (Affectation_Manager.Get_Targeted_Internal_Chunk, T) then
            Error (EXPIRED_INTERNAL_TARGET);
         else
            if Affectation_Manager.Get_Affected_Chunk = 1 then
               External_Chunk.Assume_With_Target (Internal_Chunks_Register.Get_Capture_Time (Affectation_Manager.Get_Targeted_Internal_Chunk),
                                                  Internal_Chunks_Register.Get_Arrival_Time (Affectation_Manager.Get_Targeted_Internal_Chunk, External_Chunk.Get_Operator));
               if Affectation_Manager.Perception_Is_Present then
                  Internal_Chunks_Register.Create_Perception_Forward (Affectation_Manager.Get_Created_Perception,
                                                              T,
                                                              External_Chunk.Get_Arrival_Time,
                                                              External_Chunk.Get_Type_Index);
               else
                  Internal_Chunks_Register.Cancel;
               end if;
            else
               Internal_Chunks_Register.Assume_With_Target (Affectation_Manager.Get_Affected_Chunk, T, Affectation_Manager.Get_Targeted_Internal_Chunk);
               if Affectation_Manager.Perception_Is_Present then
                  if External_Chunk.Is_Expired (T) then
                     Error (EXPIRED_EXTERNAL_CHUNCK);
                  else
                     Internal_Chunks_Register.Create_Perception_Forward (Affectation_Manager.Get_Created_Perception,
                                                                 T,
                                                                 External_Chunk.Get_Arrival_Time,
                                                                 External_Chunk.Get_Type_Index);
                  end if;
               end if;
            end if;
         end if;
      else
         External_Chunk.Assume (T);
         if Affectation_Manager.Perception_Is_Present then
            if External_Chunk.Is_Expired (T) then
               Error (EXPIRED_EXTERNAL_CHUNCK);
            else
               Internal_Chunks_Register.Create_Perception_Forward (Affectation_Manager.Get_Created_Perception,
                                                           T,
                                                           External_Chunk.Get_Arrival_Time,
                                                           External_Chunk.Get_Type_Index);
               Internal_Chunks_Register.Assume_All (T);
            end if;
         else
            Internal_Chunks_Register.Assume_All (T);
         end if;
      end if;
   end Update_Affectations;

end Nomo.Interpreter.Plant.Chunks_Memory;
