--  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 Ada.Directories;

with Ada.Strings.Unbounded;

with Nomo.Internal_Messages.Conclusions.Printing;

package body Nomo.Gen_Rule_Storages.Full_Printing is

   package body CVS is

      package Internal_Messages_Conclusions_Printing is new Internal_Messages.Conclusions.Printing.CVS (Internal_Type_Index);

      procedure Put_Header (File : in out File_Type) is
      begin
         Put (File, "time");
         Put (File, ", id");
         Put (File, ", fitting_nbr");
         Put (File, ", relevance");
         Put (File, ", credibility");
         Put_External_Premise_Header (File);
         Put_Internal_Premises_Header (File);
         Put_External_Message_Header (File);
         Internal_Messages_Conclusions_Printing.Put_Header (File);
      end Put_Header;

      procedure Put (File : in out File_Type;
                     This : in Full_Rule_Storage;
                     T    : in Time) is
         use Type_Categories;
      begin
         Put (File, Time'Image (T));
         Put (File, "," & Positive'Image (This.Id));
         Put (File, "," & Numerics.Fitting.Count'Image (This.Fitting_Nbr));
         Put (File, "," & Real_Accurately_0_To_1'Image (This.Relevance));
         Put (File, "," & Real_0_To_1'Image (This.Credibility));
         if Get_Category (This.Conclusion_Type) = Perception then
            Put_CVS (File, This.External_Condition);
         else
            Put_External_Premise_NA (File);
         end if;
         Put_CVS (File,
                  This.Internal_Condition,
                  This.Internal_Condition_Types,
                  This.Internal_Condition_Properties,
                  This.Internal_Premises_Number);
         if Get_Category (This.Conclusion_Type) = Command then
            Put_CVS (File, This.External_Conclusion, This.External_Conclusion_Size);
         else
            Put_External_Message_NA (File);
         end if;
         Internal_Messages_Conclusions_Printing.Put (File,
                                                     This.Internal_Conclusion,
                                                     Get_Category (This.Conclusion_Type),
                                                     This.Conclusion_Type);
      end Put;

   end CVS;

   package body XML is

      procedure Put_Header (File : in out File_Type) is
      begin
         Put (File, "<?xml version=""1.0"" encoding=""Utf-8"" standalone=""No""?>");
         Put (File, "<rules>");
      end Put_Header;

      package Internal_Messages_Conclusions_Printing is new Internal_Messages.Conclusions.Printing.XML (Component_Index,
                                                                                                        Internal_Type_Index,
                                                                                                        External_Message,
                                                                                                        Put_Xml);
      use Internal_Messages_Conclusions_Printing;

      procedure Put (File : in out File_Type;
                     This : in Full_Rule_Storage;
                     T    : in Time) is
        use Type_Categories;
      begin
         Put (File, "<rule time=""" & Time'Image (T) & """");
         Put (File, " id=""" & Positive'Image (This.Id) & """");
         Put (File, " fitting_nbr=""" & Numerics.Fitting.Count'Image (This.Fitting_Nbr) & """");
         Put (File, " relevance=""" & Real_Accurately_0_To_1'Image (This.Relevance) & """");
         Put (File, " credibility=""" & Real_0_To_1'Image (This.Credibility) & """>");
         if Get_Category (This.Conclusion_Type) = Perception then
            Put_XML (File, This.External_Condition, Positive'Value (External_Type_Index'Image (This.External_Condition_Type)));
         end if;
         Put_XML (File,
                  This.Internal_Condition,
                  This.Internal_Condition_Types,
                  This.Internal_Condition_Properties,
                  This.Internal_Premises_Number);
         Put (File,
              This.Internal_Conclusion,
              Get_Category (This.Conclusion_Type),
              This.Conclusion_Type,
              This.External_Conclusion,
              This.External_Conclusion_Size);
         Put (File, "</rule>");
      end Put;

      procedure Put_Ending (File : in out File_Type) is
      begin
         Put (File, "</rules>");
      end Put_Ending ;

   end XML;

   package body DB is

      Rule_Id_Max : Positive;
      Is_New_Id   : Boolean;
      Program     : Ada.Strings.Unbounded.Unbounded_String;

      procedure Create_Log (Path : in String) is
      begin
         Create (Log, Out_File, Path & "log.csv");
         Put (Log, "time");
         Put (Log, ", rule_id");
         Put (Log, ", fitting_nbr");
         Put (Log, ", relevance");
         Put_Line (Log, ", credibility");
      end Create_Log;

      procedure Create_Input (Path : in String) is
      begin
         Create (Input, Out_File, Path & "input.csv");
         Put (Input, "time");
         Put (Input, ", rule_id");
         Put (Input, ", index");
         Put (Input, ", value");
         Put (Input, ", activator");
         Put (Input, ", tolerance");
         Put_Line (Input, ", specificity_log");
      end Create_Input;

      procedure Create_Output (Path : in String) is
      begin
         Create (Output, Out_File, Path & "output.csv");
         Put (Output, "time");
         Put (Output, ", rule_id");
         Put_Line (Output, ", value");
      end Create_Output;

      procedure Create_Premise (Path : in String) is
      begin
         Create (Premise, Out_File, Path & "premise.csv");
         Put (Premise, "time");
         Put (Premise, ", rule_id");
         Put (Premise, ", index");
         Put (Premise, ", specificity_log");
         Put (Premise, ", property");
         Put (Premise, ", type_id");
         Put (Premise, ", information_value");
         Put (Premise, ", credibility_value");
         Put (Premise, ", credibility_activator");
         Put (Premise, ", credibility_tolerance");
         Put (Premise, ", timespan_value");
         Put (Premise, ", timespan_activator");
         Put_Line (Premise, ", timespan_tolerance");
      end Create_Premise;

      procedure Create_Conclusion (Path : in String) is
      begin
         Create (Conclusion, Out_File, Path & "conclusion.csv");
         Put (Conclusion, "time");
         Put (Conclusion, ", rule_id");
         Put (Conclusion, ", value");
         Put_Line (Conclusion, ", delay");
      end Create_Conclusion;

      procedure Create (Path : in String) is
      begin
         Create_Log (Path);
         Create_Input (Path);
         Create_Output (Path);
         Create_Premise(Path);
         Create_Conclusion (Path);
         Open_Rule (Path);
      end Create;

      procedure Open_Rule (Path : in String) is
         use Ada.Strings.Unbounded;
         I : Natural;
         Buffer : Unbounded_String;
      begin
         if Ada.Directories.Exists (Path & "rule.csv") then
            Rule_Id_Max := 1;
            Is_New_Id := False;
            Open (Rule, In_File, Path & "rule.csv");
            while not End_Of_File (Rule) loop
               Buffer := To_Unbounded_String(Get_Line (Rule));
            end loop;
            Close (Rule);
            I := Index (Buffer, ", ", Length(Buffer), Ada.Strings.Backward) - 1;
            I := Index (Buffer, ", ", I, Ada.Strings.Backward) + 2;
            Program := Unbounded_Slice (Buffer, I, Index (Buffer, " ", I));
            I := Index (Program, ",", Length(Program), Ada.Strings.Backward);
            if I /= 0 then
               Program := Unbounded_Slice (Program, 1, I - 1);
            end if;
            Rule_Id_Max := Positive'Value (Slice(Buffer, 1, Index (Buffer, ",", 1) - 1));
            Open (Rule, Append_File, Path & "rule.csv");
         else
            Rule_Id_Max := Positive'Last;
         end if;
      end Open_Rule;

      procedure Open (Path : in String) is
      begin
         if Ada.Directories.Exists (Path & "log.csv") then
            Open (Log, Append_File, Path & "log.csv");
         else
            Create_Log (Path);
         end if;
         if Ada.Directories.Exists (Path & "input.csv") then
            Open (Input, Append_File, Path & "input.csv");
         else
            Create_Input (Path);
         end if;
         if Ada.Directories.Exists (Path & "output.csv") then
            Open (Output, Append_File, Path & "output.csv");
         else
            Create_Output (Path);
         end if;
         if Ada.Directories.Exists (Path & "premise.csv") then
            Open (Premise, Append_File, Path & "premise.csv");
         else
            Create_Premise (Path);
         end if;
         if Ada.Directories.Exists (Path & "conclusion.csv") then
            Open (Conclusion, Append_File, Path & "conclusion.csv");
         else
            Create_Conclusion (Path);
         end if;
         Open_Rule (Path);
      end Open;

      procedure Put (This : in Full_Rule_Storage;
                     T    : in Time) is
      begin
         Put (Log, Time'Image (T));
         Put (Log, "," & Positive'Image (This.Id));
         Put (Log, "," & Numerics.Fitting.Count'Image (This.Fitting_Nbr));
         Put (Log, "," & Real_Accurately_0_To_1'Image (This.Relevance));
         Put_Line (Log, "," & Real_0_To_1'Image (This.Credibility));
         if Type_Categories."="(Get_Category (This.Conclusion_Type), Type_Categories.Perception) then
            Put_DB (Input, T, This.Id, This.External_Condition);
         end if;
         Put_DB (Premise,
                 T,
                 This.Id,
                 This.Internal_Condition,
                 This.Internal_Condition_Types,
                 This.Internal_Condition_Properties,
                 This.Internal_Premises_Number);
         if Type_Categories."="(Get_Category (This.Conclusion_Type), Type_Categories.Command) then
            Put_DB (Output, T, This.Id, This.External_Conclusion, This.External_Conclusion_Size);
         end if;
         Internal_Messages.Conclusions.Printing.DB.Put (Conclusion, T, This.Id, This.Internal_Conclusion);
         if This.Id > Rule_Id_Max then
            declare
               use Ada.Strings.Unbounded;
               Rule_Id : constant String := Positive'Image (This.Id);
            begin
               if not (Is_New_Id) then
                  Is_New_Id := True;
                  New_Line (Rule);
               end if;
               Put (Rule, Rule_Id);
               Put (Rule, ", R" & Rule_Id (2 .. Rule_Id'Last));
               Put (Rule, ", " & To_String (Program));
               Put (Rule, ", " & To_String (Program));
               Put_Line (Rule, ", " & Internal_Type_Index'Image (This.Conclusion_Type));
            end;
         end if;
      end Put;

      procedure Close is
      begin
         Close (Log);
         Close (Rule);
         Close (Input);
         Close (Output);
         Close (Premise);
         Close (Conclusion);
      end Close ;

   end DB;

end Nomo.Gen_Rule_Storages.Full_Printing;
