-- This program is the last attempt of artificial intelligency with Ada.
-- Elhoim is Copyright (C) 2023 Manuel ; 
--
--   This program is free software; you can redistribute it and/or modify
--   it under the terms of the GNU General Public License as published by
--   the Free Software Foundation; either version 2 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 General Public License for more details.
--
--   You should have received a copy of the GNU General Public License
--   along with this program; if not, write to the Free Software
--   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
--
-- Date := "2023-05-01 20:03:01"
-- Version := "1.0.0a"


with Gnat.Os_Lib;
with Ada.Text_Io;
use Ada;
with Ada.Directories;
with Ada.Characters.Handling;
use Ada.Characters;
with Ada.Strings.Fixed;
use Ada.Strings;
with Gnat.Strings;
use Gnat.Strings;
with Lib.Operat ;
use Lib.Operat ;

with Gnat.Directory_Operations;
use Gnat.Directory_Operations;
with Lib.Shared;
use Lib.Shared;
package body Lib.Compil is
   
   use Result;
   
   procedure Initialize is
   begin
      Text_Io.Put_Line("TOTO 1");
      Specifications_Filenames_Search :=
	Operat.Spawn ("find " & Path & Dir_Separator & Project_name & " -iname " & "\""*.ads\""", Path & Dir_Separator & "Out_File.txt");
      Text_Io.Put_Line("TOTO 2");
      if Specifications_Filenames_Search.Args /= null then
	 for Arg in Specifications_Filenames_Search.Args'Range loop
	    Free(Specifications_Filenames_Search.Args(Arg));
	    end loop;
      end if;
      Text_Io.Put_Line("TOTO 3");
      Implementations_Filenames_Search :=
	Operat.Spawn ("find " & Path & Dir_Separator & Project_name & " -iname " & """*.adb""", Path & Dir_Separator & "Out_File.txt");
      Text_Io.Put_Line("TOTO 4");
      if Implementations_Filenames_Search.Args /= null then
	 for Arg in Implementations_Filenames_Search.Args'Range loop
	    Free(Implementations_Filenames_Search.Args(Arg));
	    end loop;
      end if;
      Text_Io.Put_Line("TOTO 5");
   end Initialize;
   

   procedure Replace_Description (Var_Name : in String; Value : in String; Node : in String) is
      Filename : constant String := Project_Name & Dir_separator & Project_Prefix & "-" & Node & "src" & Dir_separator & "lib" & Dir_Separator & To_Lower(Project_Prefix) & '-' & To_Lower(Node) & ".ads";
      
      Source : Text_Io.File_Type;
      Target : Text_Io.File_Type;
      
      Tmp_Filename : constant String := Filename & ".tmp";
      Done : Boolean := False;
   begin      
      Text_Io.Put_Line("Change value of " & Var_Name & " to " & Value & " in " & Node & " ; ");
      Text_Io.Put_Line("with filename : " & Filename);
      if Os_Lib.Is_Regular_File(Filename) then
	 Text_Io.Create(Target, Text_Io.Out_File, Tmp_Filename);
	 Text_Io.Open(Source, Text_Io.In_File, Filename);
	 while not Text_Io.End_Of_File(Source) loop
	    declare
	       Line : constant String := Text_Io.Get_Line(Source);
	    begin
	       if not Done then
		  if Fixed.Index(Line, Var_Name) /= 0 then
		     
		     Text_Io.Put_Line(Target, Line(Line'First..Fixed.Index(Line, "=")+1) & Value & " ; ");	       
		     Done := True;
		  else
		     Text_Io.Put_Line(Target, Line);
		  end if;		  
	       else
		  Text_Io.Put_Line(Target, Line);
	       end if;
	    end;
	 end loop;
	 Text_Io.Close(Target);
	 Text_Io.delete(Source);
	 
	 directories.Rename(Tmp_Filename, Filename);
      end if;
   end Replace_Description;
   
   
   procedure Main_Description (Var_Name : in String; Value : in String; Node : in String) is
      Filename : constant String := Project_Name & Dir_separator & Project_Prefix & "-" & Node & "src" & Dir_separator & "lib" & Dir_Separator & To_Lower(Project_Prefix) & '-' & To_Lower(Node) & ".adb";
      Source : Text_Io.File_Type;
      Target : Text_Io.File_Type;
      
      Tmp_Filename : constant String := Filename & ".tmp";
      Done : Boolean := False;
   begin      
      Text_Io.Put_Line("Change value of " & Var_Name & " to " & Value & " in " & Node & " ; ");
      Text_Io.Put_Line("with filename : " & Filename);
      if Os_Lib.Is_Regular_File(Filename) then
	 Text_Io.Create(Target, Text_Io.Out_File, Tmp_Filename);
	 Text_Io.Open(Source, Text_Io.In_File, Filename);
	 while not Text_Io.End_Of_File(Source) loop
	    declare
	       Line : constant String := Text_Io.Get_Line(Source);
	    begin
	       if not Done then
		  if Fixed.Index(Line, Var_Name) /= 0 then
		     
		     Text_Io.Put_Line(Target, Line(Line'First..Fixed.Index(Line, "=")+1) & Value & " ; ");	       
		     Done := True;
		  else
		     Text_Io.Put_Line(Target, Line);
		  end if;		  
	       else
		  Text_Io.Put_Line(Target, Line);
	       end if;
	    end;
	 end loop;
	 Text_Io.Close(Target);	 
	 Text_Io.delete(Source);      
	 
	 directories.Rename(Tmp_Filename, Filename);
      end if;
   end Main_Description;

   procedure Set_Date(Date : out Date_Record; To : in Calendar.Time) is
      
   begin
      Calendar.Split(To, Date.Year, Date.Month, Date.Day, Date.Hours);
   end Set_date;
   
   procedure Set_Start_Time(Date : in Calendar.Time := Calendar.Clock) is
   begin
      Set_Date(Start_Date, Date);
   end Set_Start_Time;
   
   
   function Check_Modification_To_New_Description return Boolean is
      Verax : Boolean := False;
   begin
      for File_Id in Specifications_Filenames_Search.Wlines'Range loop
      	 if Calendar.">"(Directories.Modification_Time(To_String(Result."-"(Specifications_Filenames_Search.Wlines(File_Id)))),
			 Calendar.Time_Of(Start_Date.Year, Start_Date.Month, Start_Date.Day, Start_Date.Hours)) then
	    Text_Io.Put_Line("Modified filename : " & To_String(Result."-"(Specifications_Filenames_Search.Wlines(File_Id))));
	    Verax := True;
	    
	    declare
	       Filename : constant Wide_String := (-Specifications_Filenames_Search.Wlines(File_Id));
	       Basename : constant String := Base_Name(Handling.To_String(Filename), ".ads");
	       Node     : constant String := basename(Fixed.Index(Basename, "-", Backward)+1..Basename'Last);
	    begin
	       Replace_Description("Date", Formatting.Image(Clock), Node);
	       Replace_Description
		 ("Version", Lib.To_String(Lib.Shared.Version), Node);
	    end;
	    
      	 end if;
      end Loop;
      
      return Verax;
   end Check_Modification_To_New_Description;
   
   function Check_Modification_To_New_Action return Boolean is
      Verax : Boolean := False;
   begin
      for File_Id in Implementations_Filenames_Search.Wlines'Range loop
	 if Calendar.">"(Directories.Modification_Time(To_String(Result."-"(implementations_Filenames_Search.Wlines(File_Id)))),
			 Calendar.Time_Of(Start_Date.Year, Start_Date.Month, Start_Date.Day, Start_Date.Hours)) then
	    Text_Io.Put_Line("Modified filename : " & To_String(Result."-"(Specifications_Filenames_Search.Wlines(File_Id))));
	    Verax := True;
	    
	    declare
	       Filename : constant Wide_String := (-Specifications_Filenames_Search.Wlines(File_Id));
	       Basename : constant String := Base_Name(Handling.To_String(Filename), ".adb");
	       Node     : constant String := basename(Fixed.Index(Basename, "-", Backward)+1..Basename'Last);
	    begin
	       Main_Description("Date", Formatting.Image(Clock), Node);
	       Main_Description
		 ("Version", Lib.To_String(Lib.Shared.Version), Node);
	    end;
	    
	 end if;
      end Loop;

      return Verax;
   end Check_Modification_To_New_Action;
   
   
   procedure update (Filename : in String; Var_Name : in String; Value : in String) is
      Source : Text_Io.File_Type;
      Target : Text_Io.File_Type;
      
      Tmp_Filename : constant String := Filename & ".tmp";
      Done : Boolean := False;
   begin      
      Text_Io.Put_Line("Change value of " & Var_Name & " to " & Value & " in " & filename & " ; ");

      if Os_Lib.Is_Regular_File(Filename) then
	 Text_Io.Create(Target, Text_Io.Out_File, Tmp_Filename);
	 Text_Io.Open(Source, Text_Io.In_File, Filename);
	 while not Text_Io.End_Of_File(Source) loop
	    declare
	       Line : constant String := Text_Io.Get_Line(Source);
	    begin
	       if not Done then
		  if Fixed.Index(Line, Var_Name) /= 0 then
		     
		     Text_Io.Put_Line(Target, Line(Line'First..Fixed.Index(Line, "=")+1) & Value & " ; ");	       
		     Done := True;
		  else
		     Text_Io.Put_Line(Target, Line);
		  end if;		  
	       else
		  Text_Io.Put_Line(Target, Line);
	       end if;
	    end;
	 end loop;
	 Text_Io.Close(Target);
	 Text_Io.delete(Source);      
	 directories.Rename(Tmp_Filename, Filename);
      end if;
   end Update;
   
   
   
   ----------------------------------------------------------------------------------
   --                                                                              --
   ----------------------------------------------------------------------------------
   
   procedure To_Major is
   begin
      Compil.Replace_Description ("Current_Major", Outils.Integer_Image(Integer(Version.Major)), "lib");
   end To_Major;
   
   procedure To_Minor is
   begin
      Compil.Replace_Description ("Current_Minor", Outils.Integer_Image(Integer(Version.Minor)), "lib");
   end To_Minor;
   
   procedure To_Revision is
   begin
      Compil.Replace_Description ("Current_Revision", Outils.Integer_Image(Integer(Version.Revision)), "lib");
   end To_Revision;
   
   procedure To_Release is
   begin
      Compil.Replace_Description ("Current_Release", Character'Image(Character'Value(Release_Enum'Image(Version.Release))), "lib");
   end To_Release;
   
   
   procedure Version_Update(Version : in out Version_Record; Errno: out Integer) is
   begin
      --Set_date(Shared_Date, Calendar.Clock);
      if not New_Version then
	 Errno := -1;
	 return;
      end if;
      -- Change major if is the current year > Major_Version.
      
      
      if New_Action and New_Description then
	 Version.Release := 'r';
      else
	 if New_Action then
	    Version.Release := 'b';
	 end if;
	 if New_Description then
	   Version.Release := 'a';
	 end if;
      end if;
      
      -- Change minor if some function is modified or added.
      if New_Description then	    
	 if Version.Minor + 1 < Minor_Range'Last then
	    Version.Minor := Version.Minor + 1;	      
	    Version.Revision := 0;		  	    
	    
	 else
	    Errno := -2;
	    
	 end if;
      end if;
      
      -- Change minor if some data description is modified or added.
      if New_Action then	       
	 if Version.Revision + 1 < Revision_Range'Last then
	    Version.Revision := Version.Revision + 1;
	    
	 else
	    Errno := Errno - 4;
	 end if;
      end if;
      
      

   end Version_Update;

   
   
end Lib.Compil ;