-- main is main file of main project written with Ada.
-- Main is Copyright (C) 2025 Manuel De Girardi ; 
--
--   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 := 2025-06-25 13:06:36 ; 
-- Version := 0.5.0r ; 

with Gnat.Sockets;
use Gnat.Sockets;
with Ada.Task_Identification;
use Ada.Task_Identification;
with Gnat.Sha1;
use Gnat;
with Ada.Unchecked_Deallocation;
with Text_Io;
with Ada.Wide_Text_Io;
use Ada.Wide_Text_Io;
with Ada.Characters.Handling;
use Ada.Characters.Handling;
with Ada.Containers.Vectors;
use Ada.Containers;
with Ada.Calendar;
with Ada.Calendar.Formatting;
use Ada.Calendar;
package body M.Servers is
   
   procedure Product_save(Product : in Product_Class;File : in out File_Type) is
   begin
            Put_Line(File, To_Wide_String(Product.Name.all));
      Put_Line(To_Wide_String(Product.Name.all));
      Put_Line(File, Product.Description.all);
      Put_Line(Product.Description.all);
      Put_Line(File, To_Wide_String(Product.Documentation.all));
      Put_Line(To_Wide_String(Product.Documentation.all));
      Put_Line(File, To_Wide_String(Fixed_Unit_Ht'Image(Product.Unit_HT)));
      Put_Line(To_Wide_String(Fixed_Unit_Ht'Image(Product.Unit_HT)));
      Put_Line(File, To_Wide_String(Fixed_Factor'Image(Product.TVA_Rate)));
      Put_Line(To_Wide_String(Fixed_Factor'Image(Product.TVA_Rate)));
      Put_Line(File, To_Wide_String(Fixed_Total'Image(Product.TVA)));
      Put_Line(To_Wide_String(Fixed_Total'Image(Product.TVA)));
      Put_Line(File, To_Wide_String(Fixed_Unit_TTC'Image(Product.Unit_TTC)));
      Put_Line(To_Wide_String(Fixed_Unit_TTC'Image(Product.Unit_TTC)));

   end Product_Save;
   procedure Product_Restore(Product : out Product_Class;File : in out File_Type) is
   begin
      Product.Name := new String ' (To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Product.Name.all));
      Product.Description := new Wide_String ' (Get_Line(File));
      Put_Line(Product.Description.all);
      Product.Documentation := new String ' (To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Product.Documentation.all));
      Product.Unit_Ht := Fixed_Unit_Ht'Value(To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Fixed_Unit_Ht'Image(Product.Unit_HT)));
      Product.TVA_Rate := Fixed_Factor'Value(To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Fixed_Factor'Image(Product.TVA_Rate)));
      Product.TVA := Fixed_Total'Value(To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Fixed_Total'Image(Product.TVA)));
      Product.Unit_TTC := Fixed_Unit_Ttc'Value(To_String(Get_Line(File)));
      Put_Line(To_Wide_String(Fixed_Unit_TTC'Image(Product.Unit_TTC)));
   end Product_Restore;
   
   
   procedure Game_Save is
      File : File_Type;
   begin
      Create(File, Out_File, "main_game.txt", Form => "WCEM=8");
      if Current_Game.Count /= 0 then
	 for I in 1..Current_Game.Count loop
	    Product_Save(Current_Game.Products(I).all, File);
	 end loop;
      end if;
      Close(File);
   end Game_Save;
   procedure Game_Restore is
      File : File_Type;
   begin
      Open(File, In_File, "main_game.txt", Form => "WCEM=8");
      while not End_Of_File(File) loop
	 declare
	    Product : Product_Access := new Product_Class;
	 begin
	    Product_Restore(Product.all, File);
	    Current_Game.Products(Current_Game.Count+1) := Product;
	    Current_Game.Count := Current_Game.Count + 1;
	 end;
	 
      end loop;
      Close(File);
   exception
      when Name_Error =>
	 Put_Line("Products file : main_game.txt : not found.");
	 raise;
      when End_Error =>
	 Close(File);
   end Game_Restore;
   
   
   
   
   function Equal_Command (Left, Right : Command_Record) return Boolean is
   begin
      return Left = Right;
   end Equal_Command;
   function Equal_Facture (Left, Right : Facture_Record) return Boolean is
   begin
      return Left = Right;
   end Equal_Facture;
   function Equal_Client (Left, Right : Client_Record) return Boolean is
   begin
      return Left = Right;
   end Equal_Client;
   
   
   subtype Command_Index is Positive;
   subtype facture_Index is Positive;
   subtype Client_Index is Positive;
   package  Command_vectors is new Vectors (Command_Index, Command_Record, equal_Command);
   package Facture_Vectors is new Vectors (Facture_Index, Facture_Record, equal_Facture);
   package Client_Vectors is new Vectors (Client_Index, Client_Record, equal_Client);
   
   
   
   
   type Business_Manager;
   
   
   task type Console_Process(Business : access Business_Manager) is
      entry Add(Client : in out Client_Record; Command : in out Command_Record; Facture : in out Facture_Record; Success : out Boolean; Id_Transaction : out Natural);
      entry Delete(Client : in Client_Record; Success : out Boolean);
      entry Delete(Id_Transaction : in Natural; Success : out Boolean);
      entry Get(Id_Transaction : in Natural; Facture : out Facture_Record; Success : out Boolean);
      entry Paiement(Id_Transaction : in Natural);
      entry Message (Msg : in Wide_String);
      entry Receive (Wchar : in Wide_Character);
      entry Halt;
   end Console_Process;
   
   
   type Business_Manager is limited
      record
	 Num_Deal       : Natural := 0;
	 Id_Transaction : Natural := 0;
	 Commandes      : Command_Vectors.Vector;
	 Factures       : Facture_Vectors.Vector;
	 Clients        : Client_Vectors.Vector;
	 Console        : Console_Process(Business_Manager'access);
      end record;
	 
   
   
   task body Console_Process is
   begin
      loop
	 select
	    accept Get(Id_Transaction : in Natural; Facture : out Facture_Record; Success : out boolean) do
	       Success := False;
	       for F in 1..Facture_Vectors.Last_Index(Business.factures) loop
		  declare
		     E : constant facture_Record := Facture_Vectors.Element(Business.Factures, F);
		  begin
		     if E.Id_transaction = Id_Transaction then				 
			Facture := E;
			Success := True;
		     end if;
		  end;
	       end loop;
	    end Get;
	 or
	    accept Paiement(Id_Transaction : in Natural) do
	       for F in 1..Facture_Vectors.Last_Index(Business.factures) loop
		  declare
		     E : facture_Record := Facture_Vectors.Element(Business.Factures, F);
		  begin
		     if E.Id_transaction = Id_Transaction then				 
			E.Payed := True;
			Facture_Vectors.Replace_element(Business.Factures, F, E);
		     end if;
		  end;
	       end loop;
	       for Cmd in 1..Command_Vectors.Last_Index(Business.Commandes) loop
		  declare
		     E : Command_Record := Command_Vectors.Element(Business.Commandes, Cmd);
		  begin
		     if E.Id_transaction = Id_Transaction then				 
			E.Payed := True;
			Command_Vectors.Replace_element(Business.Commandes, Cmd, E);
		     end if;
		  end;
	       end loop;
	       for F in 1..Client_Vectors.Last_Index(Business.Clients) loop
		  declare
		     E : Client_Record := Client_Vectors.Element(Business.Clients, F);
		  begin
		     if E.Id_transaction = Id_Transaction then				 
			E.Payed := True;
			Client_Vectors.Replace_element(Business.Clients, F, E);
		     end if;
		  end;
	       end loop;
	    end Paiement;
	 or
	    accept Delete(Id_Transaction : in Natural; Success : out Boolean) do
	       Success := False;
	       for C in 1..Client_Vectors.Last_Index(Business.Clients) loop
		  declare
		     E : constant Client_Record := Client_Vectors.Element(Business.Clients, C);
		  begin
		     if E.Id_transaction = Id_Transaction then
			for F in 1..Facture_Vectors.Last_Index(Business.factures) loop
			   declare
			      E : constant facture_Record := Facture_Vectors.Element(Business.Factures, F);
			   begin
			      if Client_record(E).Id_transaction = Id_Transaction then				 
				 Facture_Vectors.delete(Business.Factures,  F);
			      end if;
			   end;
			end loop;
			for cmd in 1..Command_Vectors.Last_Index(Business.Commandes) loop
			   declare
			      E : constant Command_Record := Command_Vectors.Element(Business.Commandes, cmd);
			   begin
			      if Client_record(E).Id_Transaction = Id_transaction then				 
				 Command_Vectors.delete(Business.Commandes,  cmd);
			      end if;
			   end;
			end loop;
			Client_Vectors.delete(Business.Clients,  C);
			Success := True;			
		     end if;
		  end;
	       end loop;
	    end Delete;
	 or
	    accept Add(Client : in out Client_Record; Command : in out Command_Record; Facture : in out Facture_Record; Success : out Boolean; Id_Transaction : out Natural) do
	       Success := False;
	       Client.Id_Transaction := Business.Id_Transaction + 1;
	       Command.Id_Transaction := Business.Id_Transaction + 1;
	       Facture.Id_Transaction := Business.Id_Transaction + 1;
	       Business.Clients := Client_Vectors."&"(Business.Clients, Client);
	       Business.Commandes := Command_Vectors."&"(Business.Commandes, Command);
	       Business.Factures := Facture_Vectors."&"(Business.Factures, Facture);
	       Success := True;
	       Id_Transaction := Business.Id_Transaction + 1;
	       Business.Id_Transaction := Business.Id_Transaction + 1;
	    end Add;
	 or	    
	    accept Delete(Client : in Client_Record; Success : out Boolean) do
	       Success := False;
	       for C in 1..Client_Vectors.Last_Index(Business.Clients) loop
		  declare
		     E : constant Client_Record := Client_Vectors.Element(Business.Clients, C);
		  begin
		     if E = Client then
			for F in 1..Facture_Vectors.Last_Index(Business.factures) loop
			   declare
			      E : constant facture_Record := Facture_Vectors.Element(Business.Factures, F);
			   begin
			      if Client_record(E) = Client then				 
				 Facture_Vectors.delete(Business.Factures,  F);
			      end if;
			   end;
			end loop;
			for cmd in 1..Command_Vectors.Last_Index(Business.Commandes) loop
			   declare
			      E : constant Command_Record := Command_Vectors.Element(Business.Commandes, cmd);
			   begin
			      if Client_record(E) = Client then				 
				 Command_Vectors.delete(Business.Commandes,  cmd);
			      end if;
			   end;
			end loop;
			Client_Vectors.delete(Business.Clients,  C);
			Success := True;			
		     end if;
		  end;
	       end loop;
	    end Delete;					      
	 or
	    accept Message(Msg : in Wide_String) do
	       New_Line;
	       Put_Line(Msg);
	       New_Line;
	    end Message;
	 or
	    accept Receive (Wchar : in Wide_Character);
	 or
	    accept Halt;

	    exit;
	 end select;
      end loop;
   end Console_Process;
   
   
   
   Business : Business_Manager;
   
   
   
   task Main_Server is
      entry Initialize;
      entry Start;
      entry Stop;
      entry Halt;
   end Main_Server;
   
   task Products_Server is
      entry Initialize;
      entry Start;
      entry Stop;
      entry Halt;
   end Products_Server;
   
   
   
   
   task body Server is
      End_Of_Task : Boolean := False;
      Add  : Gnat.sockets.Sock_Addr_Type;
      Socket   : Socket_Type;
   begin  
      accept Initialize;

      
      Products_Server.Initialize;
      Main_Server.Initialize;
      accept Start do
	 Products_Server.Start;
	 Main_Server.Start;
	 
      end Start;

      loop
	 select
	    accept Initialize;
	 or
	    accept Standby(End_Of_Program : out Boolean) do
	       End_Of_Program := End_Of_Task;
	    end Standby;
	    exit;
	 or
	    accept Start do
	       Products_Server.Start;
	       Main_Server.Start;

	    end Start;
	 or
	    accept Stop;

	    Add.Addr :=
	      Gnat.Sockets.Addresses (Gnat.Sockets.Get_Host_By_Name ("localhost"), 1);
	    
	    Add.Port := 1970;
	    Gnat.sockets.Create_Socket (Socket);
	    delay 0.1;
	    Gnat.Sockets.Set_Socket_Option
	      (Socket,
	       Gnat.Sockets.Socket_Level,
	       (Gnat.Sockets.Reuse_Address, True));      
	    delay 0.1;      
	    Gnat.sockets.Connect_Socket (Socket, Add);
	    delay 0.1;
	    Sockets.Close_Socket(Socket);

	    Main_Server.Stop;
	    
	    Add.Port := 1988;
	    Gnat.sockets.Create_Socket (Socket);
	    delay 0.1;
	    Gnat.Sockets.Set_Socket_Option
	      (Socket,
	       Gnat.Sockets.Socket_Level,
	       (Gnat.Sockets.Reuse_Address, True));      
	    delay 0.1;      
	    Gnat.sockets.Connect_Socket (Socket, Add);
	    delay 0.1;
	    Sockets.Close_Socket(Socket);

	    Products_Server.Stop;
	       
	 or
	    accept Halt do
	       End_Of_Task := True;	       

	       Business.Console.halt;

	    end Halt;
	    Main_Server.Halt;
	    Products_Server.Halt;
	    exit;
	 end select;
      end loop;      
   end Server;
   
   procedure Ctrl_C_Procedure is
      Add  : Gnat.sockets.Sock_Addr_Type;
      Socket   : Socket_Type;
      
      
      
   begin

      

      Add.Addr :=
	   Gnat.Sockets.Addresses (Gnat.Sockets.Get_Host_By_Name ("localhost"), 1);
      
      Add.Port := 1970;
      Gnat.sockets.Create_Socket (Socket);
      delay 0.1;
      Gnat.Sockets.Set_Socket_Option
	(Socket,
	 Gnat.Sockets.Socket_Level,
	 (Gnat.Sockets.Reuse_Address, True));      
      delay 0.1;      
      Gnat.sockets.Connect_Socket (Socket, Add);
      delay 0.1;
      Sockets.Close_Socket(Socket);

      Add.Port := 1988;
      Gnat.sockets.Create_Socket (Socket);
      delay 0.1;
      Gnat.Sockets.Set_Socket_Option
	(Socket,
	 Gnat.Sockets.Socket_Level,
	 (Gnat.Sockets.Reuse_Address, True));      
      delay 0.1;      
      Gnat.sockets.Connect_Socket (Socket, Add);
      delay 0.1;
      Sockets.Close_Socket(Socket);
      
      Server.Halt;      
      Put_Line("End of Ctrl_C_Process");
   end Ctrl_C_Procedure;
   
   type Socket_Access is access all Socket_Type;
   
   task type Human_Thread_Server(Socket : Socket_Access) is
      entry Get_Id(Id : out Task_Id);
   end Human_Thread_Server;
   
   type Thread_server_Access is access Human_Thread_server;
   
   type Human_Thread_Server_Task is
      record
	 Id : Task_Id := Null_Task_id;
	 Thread_server : Thread_server_access;
      end record;
   type thread_server_Task_Access is access Human_Thread_Server_Task;   
   
   
   
   
   task body Human_Thread_Server is
	 
      type String_Access is access all String;
      
      Channel         : constant Stream_Access := Stream(Socket.all);
      Logname         : constant String_Access := new String ' ("webi");
      Passwd          : constant Gnat.sha1.Message_Digest := Sha1.Digest("webi");
      Logged          : Boolean := False;
      
      Logname_Input : String_Access;
      Passwd_Input   : Gnat.Sha1.Message_Digest;
      Enregistrement : Enregistrement_Record;
      
      Bank_Info : Bank_Info_Type := Null_Card;
      Command : Command_Record;
      Index : Natural := 0;
      Facture : Facture_Record;
      Sum : Price_Type := 0.0;
      TVA : Price_Type := 0.0;
		  
      Client  : Client_Record;
      Bank_Card  : Bank_Info_Type := Null_Card;
      Success    : Boolean := False;
      Id_Transaction : Natural := 0;
      Step : Command_Enum := Null_item;
      File : File_Type;
   begin
      
      accept Get_Id(Id : out Task_Id) do
	 Id := Current_Task;
      end Get_Id;      
      Logname_input := new String ' (String'Input(Channel)); 
      Passwd_Input :=  Sha1.Message_Digest'Input(Channel);
      if Logname_Input.all = Logname.all and
	 Passwd_Input = Passwd then
	 --Wide_Text_Io.Put_Line("Checking for user """ & Logname.all & """");	 	    	 
	 Logged := True;
	 --Wide_Text_Io.Put_Line("Adduser for user """ & Logname.all & """");
      end if;	 
      Boolean'Output(Channel, Logged);
      Text_Io.Put_Line("Logged : " & Boolean'Image(Logged));
      if Logged then
	 
	 Step := Command_Enum'Input(Channel);
	 Put_Line("Step : " & To_Wide_String(Command_Enum'Image(Step)));
	 case Step is
	    when Cmd =>
	       Open(File, Append_File, "cmd.txt", Form=>"WCEM=8");
	       Put_Line(File, "Command: " & To_Wide_String(Formatting.Image(Clock)));
	       Put_Line("Command: " & To_Wide_String(Formatting.Image(Clock)));
	       begin
		  
		  Text_Io.Put_Line("Command...");
		  
		  
		  Enregistrement.coordonates.name := Wide_String'Input(Channel);
		  Enregistrement.coordonates.Email := String'Input(Channel);
		  Enregistrement.coordonates.Address := Wide_String'Input(Channel);
		  Enregistrement.coordonates.Phone := String'Input(Channel);
		  Enregistrement.Programs(1) := String'Input(Channel);
		  Enregistrement.Programs(2) := String'Input(Channel);
		  Enregistrement.Programs(3) := String'Input(Channel);
		  Enregistrement.Programs(4) := String'Input(Channel);
		  Enregistrement.Programs(5) := String'Input(Channel);
		  Enregistrement.Programs(6) := String'Input(Channel);
		  Enregistrement.Programs(7) := String'Input(Channel);
		  Enregistrement.Programs(8) := String'Input(Channel);
		  Enregistrement.Programs(9) := String'Input(Channel);
		  Enregistrement.Programs(10) := String'Input(Channel);
		  Enregistrement.Logicial.Objectif := Wide_String'Input(Channel);
		  Enregistrement.Logicial.Motivations := Wide_String'Input(Channel);
		  Enregistrement.Logicial.Objet := Wide_String'Input(Channel);
		  Enregistrement.Logicial.Arguments := Wide_String'Input(Channel);
		  
		  
		  New_Line;
		  
		  
		  for Program in 1..5 loop
		     declare
			Product : Product_Enum := Null_Item;
			
		     begin
			Product := Product_Enum'Value(Enregistrement.Programs(Program));
			if Product /= Null_Item then
			   Command.Products(Product) := My_Prices(Product);		     
			   Index := Index + 1;
			end if;
		     exception
			when others =>
			   null;	       
		     end;
		  end loop;
		  Text_Io.Put_Line("Prices...");
		  
		  for Product in Product_Enum loop
		     Command.Ht_Sum := Command.Ht_Sum + Command.Products(Product);
		  end loop;
		  for Product in Product_Enum loop
		     Command.TVA := Command.TVA + Price_Type(Price_type(Command.Products(Product) / 100.0)) * 10.0;
		  end loop;
		  Text_Io.Put_Line("TVA...");
		  Command.TTC_Sum := Command.Ht_Sum + Command.Tva;
		  Text_Io.Put_Line("Total...");
		  Natural'Output(Channel, Index);
		  Text_Io.Put_Line("index...");
		  for Product in skywalker..Product_Enum'Pred(Null_Item) loop
		     if Command.Products(Product) /= 0.0 then
			Product_enum'Output (Channel, Product);
			Price_Type 'Output(Channel, Command.Products(Product));		  
		     end if;
		  end loop;
		  Price_Type'Output(Channel, Command.Ht_Sum);
		  Price_Type'Output(Channel, Command.TVA);
		  Price_Type'Output(Channel, Command.TTC_Sum);
		  
		  
		  
		  
		  Put_Line(File, "-----------------------------------------------------");
		  Put_Line(File, "--                                                 --");
		  Put_Line(File, "--                 NEW CLIENT                      --");
		  Put_Line(File, "--                                                 --");
		  Put_Line(File, "-----------------------------------------------------");
		  Put_Line(File, Enregistrement.Coordonates.Name);
		  Put_Line(File, To_Wide_String(Enregistrement.Coordonates.Email));
		  Put_Line(File, Enregistrement.Coordonates.Address);
		  Put_Line(File, To_Wide_String(Enregistrement.Coordonates.Phone));
		  New_Line(File);	    
		  New_Line(File);
		  Put_Line(File, Enregistrement.logicial.Objectif);
		  Put_Line(File, Enregistrement.logicial.Motivations);
		  Put_Line(File, Enregistrement.logicial.Objet);
		  Put_Line(File, Enregistrement.logicial.Arguments);
		  New_Line(File);
		  for Product in Skywalker..Product_Enum'Pred(Null_Item) loop
		     if Command.Products(Product) /= 0.0 then
			Put(File, To_Wide_String(Product_Enum'Image(Product)) & " : ");
			Put_Line(File, To_Wide_String(Price_Type 'image(Command.Products(Product))) & " € ;"); 
			
		     end if;
		  end loop;
		  Put_Line(File, "Total HT   : " & To_Wide_String(Price_Type'image(Command.Ht_Sum)) & " € ; ");
		  Put_Line(File, "Total TVA  : " & To_Wide_String(Price_Type'image(Command.TVA)) & " € ; ");
		  Put_Line(File, "total TTC  : " & To_Wide_String(Price_Type'image(Command.TTC_Sum)) & " €. ");
		  
		  Close(File);
		  Command_Record(Facture) := Command;	    
		  Client := Client_Record(Facture);
		  Business.Console.Add(Client, Command, Facture, Success, Id_transaction);
		  if Success then
		     if Id_Transaction /= 0 then
			
			Natural'Output(Channel, Id_Transaction);
			
		     end if;	    
		     
		  else
		     Business.Console.Message("Client " & Client.Name & " not registered !");
		     --  Put_Line(Enregistrement.Coordonates.Name);
		     --  Put_Line(To_Wide_String(Enregistrement.Coordonates.Email));
		     --  Put_Line(Enregistrement.Coordonates.Address);
		     --  Put_Line(To_Wide_String(Enregistrement.Coordonates.Phone));
		     --  New_Line;
		     --  for I in 1..5 loop
		     --  	  Put_Line(To_Wide_String(Enregistrement.Programs(I)));
		     --  end loop;
		     --  New_Line;
		     --  Put_Line(Enregistrement.logicial.Objectif);
		     --  Put_Line(Enregistrement.logicial.Motivations);
		     --  Put_Line(Enregistrement.logicial.Objet);
		     --  Put_Line(Enregistrement.logicial.Arguments);
		     --  New_Line;
		     
		     --  else
		     --  	  Business.Console.Message("Client " & Client.Name & " deleted !");
		     --  end if;	   	       
		  end if;
		  
		  
		  
	       exception
		  when Socket_Exception : Socket_Error =>		  
		     --Ada.Text_Io.Put_Line(Error_Type'Image(Resolve_Exception(Socket_Exception)));
		     
		     raise;
		  when Host_Exception : Host_Error =>
		     --Ada.Text_Io.Put_Line(Error_Type'Image(Resolve_Exception(Host_Exception)));
		     
		     raise;
		  when others =>		  
		     
		     --Environment_Thread.Halt;
		     --Text_Io.Put_Line("Human_Thread_Server : others exception environment halted.");		  
		     raise;
	       end;
	    when Paiement =>
	       Open(File, Append_File,"cmd.Txt", Form=>"WCEM=8");
	       Put_Line(File, "Paiement: ");
	       Id_Transaction := Natural'Input(Channel);

	       Put_Line(File, "Transaction °" & To_Wide_String(Natural'Image(Id_Transaction)));
	       Business.Console.Get(Id_Transaction, Facture, success);
	       if Success then
		  
		  Command := Command_Record(Facture);
		  for Product in Skywalker..Product_Enum'Pred(Null_Item) loop
		     if Command.Products(Product) /= 0.0 then
			
			Put(To_Wide_String(Product_Enum'Image(Product)) & " : ");
			Put_Line(To_Wide_String(Price_Type 'image(Command.Products(Product))) & " € ;"); 
			Index := Index + 1;
		     end if;
		  end loop;
		  Put_Line(File, "Total HT   : " & To_Wide_String(Price_Type'image(Command.Ht_Sum)) & " € ; ");
		  Put_Line(File, "Total TVA  : " & To_Wide_String(Price_Type'image(Command.TVA)) & " € ; ");
		  Put_Line(File, "total TTC  : " & To_Wide_String(Price_Type'image(Command.TTC_Sum)) & " €. ");
		  

		  --------------------------------------------------
		  -- Facture :
		  --------------------------------------------------		  
		  
		  
		  Natural'Output(Channel, Index);		  
		  for Product in Skywalker..Product_Enum'Pred(Null_Item) loop
		     if Command.Products(Product) /= 0.0 then
			
			Product_enum'Output (Channel, Product);
			Price_Type 'Output(Channel, Command.Products(Product));		  
		     end if;
		  end loop;
		  Price_Type'Output(Channel, Command.Ht_Sum);
		  Price_Type'Output(Channel, Command.TVA);
		  Price_Type'Output(Channel, Command.TTC_Sum);		  
	       else
		  Put_Line("bad Request in Get");
	       end if;
	       Close(File);
	    when others =>
	       raise Program_Error;
	 end case;
	 

	 --Environment_Thread.Halt;
	 --Text_Io.Put_Line("Human_Thread_Server : environment halted.");
	 Gnat.Sockets.Close_Socket(Socket.all);
      else
	 Gnat.Sockets.Close_Socket (Socket.all);
      end if;
   exception
      when Constraint_Error =>
	 --Text_Io.Put_Line("Human_Thread_Server : Constraint_error");
	 Gnat.Sockets.Close_Socket(Socket.all);
   end Human_Thread_Server;
   
   
   procedure Unchecked_Deallocation_thread_server is
      new Ada.Unchecked_Deallocation(Human_Thread_Server,thread_server_Access);
   procedure Unchecked_Deallocation_thread_server_task is
      new Ada.Unchecked_Deallocation(Human_Thread_Server_Task,thread_server_Task_Access);
   
   
   

   task body Main_Server is
      
      
      
      
      Max_Client : constant Positive := 500;
      
      Liste : array(1..Max_Client) of Socket_access;
      Liste_Thread_task : array(1..Max_Client) of Thread_Server_Task_Access;
      Bliste : array(1..Max_Client) of Boolean;
      Reads,Write : Socket_Set_Type;

      Selector : Selector_Type;
      Srv_Adr,Adr : Sock_Addr_Type;
      Srv_Socket : Socket_Type;
      Status : Selector_Status;

      Ptr : Integer := 0;
      
      
      function Chercher return Natural is
      begin
	 for I in 1..Max_Client loop
	    if Liste_Thread_Task(I) = null then
	       return I;
	    elsif not Is_callable(Liste_Thread_Task(I).Id) or Is_terminated(Liste_Thread_Task(I).Id) then
	       Unchecked_Deallocation_Thread_Server(Liste_Thread_Task(I).Thread_Server);
	       Unchecked_Deallocation_Thread_Server_Task(Liste_Thread_Task(I));
	       Liste_Thread_Task(I) := null;
	       Liste(I) := new Socket_Type;
	       return I;
	    end if;
	 end loop;
	 return 0;
      end Chercher;
      
      

      Thread_Suivant : Natural := 0;

      End_Of_Task : Boolean := False;
      Run : Boolean := False;
                       
   begin
      accept Initialize;
      for I in 1..Max_Client loop
	 liste(I) := new Socket_Type;
      end loop;
      Text_Io.Put_Line("Server initialize sockets...");
      
      
      Bliste := (others => False);
      
      Srv_Adr.Addr := Any_Inet_Addr;
      Srv_Adr.Port := 1970;
      
      Create_Socket(Srv_Socket);
      
      Set_Socket_Option
	(Srv_Socket,
	 Socket_Level,
	 (Reuse_Address, True));
      delay 0.2;
      
      Bind_Socket(Srv_Socket,Srv_Adr);

      Listen_Socket(Srv_Socket);
      
      Create_Selector(Selector);
      
	 
	 
      while not End_Of_Task loop
	 loop
	    select
	       accept Initialize;
	    or
	       accept Start;
	       exit;
	    or

	       accept Stop;
	    or
	       accept Halt do
		  End_Of_Task := True;
	       end Halt;
	       exit;
	    end select;
	 end loop;
	 Text_Io.Put_Line("Server sockets initialized.");
	 while not End_Of_Task loop
	    select
	       accept Initialize;
	    or
	       accept Start;
	    or
	       accept Stop;
	       exit;
	    or
	       accept Halt do
		  End_Of_Task := True;
	       end Halt;
	       exit;
	    or
	       delay 0.0;
	       
	       
	       
	       Empty(Reads);
	       
	       Set(Reads,Srv_Socket);

	       for I in 1..Max_Client loop
		  if Bliste(I) then
		     Set(Reads, Liste(I).all);
		  end if;
	       end loop;

	       Check_Selector(Selector, Reads, Write, Status);
	       
	       case Status is
		  when Completed =>
		     
		     if Is_Set(Reads,Srv_Socket) then
			Thread_Suivant := Chercher;

			if Thread_Suivant /= 0 then
			   Ptr := Thread_Suivant;
			   --Text_Io.Put_Line("Server accept");
			   Accept_Socket(Srv_Socket, Liste(Ptr).all, Adr);
			   --Text_Io.Put_Line("Server accepted");
			   --  Set_Socket_Option
			   --                                  (Liste(Ptr).all,
			   --                                   Socket_Level,
			   --                                   (Reuse_Address, True));
			   select
			      accept Halt do				 
				 End_Of_Task := True;
			      end Halt;
			      exit;
			   or
			      accept Stop;
			      exit;
			   or delay 2.0;
			   
			   end select;
			   
			   Bliste(Ptr) := True;
			else
			   delay 1.0;
			   --     Text_Io.Put_Line("Client suivant = zero ");
			   --     select
			   --  	accept Halt;	    
			   --  	--Ptr := Chercher;
			   --  	exit;
			   --     or delay 2.0;
			   --     end select;
			end if;
		     else

			for I in 1..Max_Client loop


			   if bliste(I) then

			      if Is_Set(Reads,Liste(I).all) then
				 Liste_Thread_Task(I) := new Human_Thread_Server_Task;

				 Liste_Thread_Task(I).Thread_Server := new Human_Thread_Server(Liste(i));

				 Liste_Thread_Task(i).Thread_Server.Get_Id(Liste_Thread_Task(i).Id);


				 Bliste(i) := false;

			      end if;
			   end if;
			end loop;
		     end if;
		  when Expired =>
		     Text_Io.Put_Line("expired");
		  when Aborted =>
		     Text_Io.Put_Line("aborted");
	       end case;	
	    end select;
	 end loop;
      end loop;
      Put_Line("Main server halted");
   end Main_Server;
   
   
   
   
   
   
   
   
   
   
   
   
   --------------------------------------------------------------------------------------
   --                              Products server                                     --
   --------------------------------------------------------------------------------------
   --
   -- Products server is products server for web gate.
   --
   -- Version : 1.0.0
   -- Date    : 2025-06-25 12:00:00
   --
   
   
   task type Products_Thread_Server(Socket : Socket_Access) is
      entry Get_Id(Id : out Task_Id);
   end Products_Thread_Server;
   
   type Products_server_Access is access Products_Thread_server;
   
   type Products_Thread_Server_Task is
      record
	 Id : Task_Id := Null_Task_id;
	 Thread_server : Products_server_access;
      end record;
   type Products_server_Task_Access is access Products_Thread_Server_Task;   
   
   
   
   
   task body Products_Thread_Server is
	 
      type String_Access is access all String;
      
      Channel         : constant Stream_Access := Stream(Socket.all);
      Logtype         : String_Access;
   begin
      accept Get_Id(Id : out Task_Id) do
	 Id := Current_Task;
      end Get_Id;      
      delay 0.2;
      Logtype := new String ' (String'Input(Channel));
      if Logtype.all = "Products" then
	 Text_Io.Put_Line("Products");
	 delay 0.2;
	 Natural'Output(Channel, Current_Game.Count);
	 delay 0.2;
	 Text_Io.Put_Line("Count : " & Natural'Image(Current_Game.Count));
	 if Current_Game.Count /= 0 then
	    for I in 1..Current_Game.Count loop
	       Text_Io.Put_Line("Product N° " & Natural'Image(I));
	       Wide_String'Output(Channel, To_Wide_String(Current_Game.Products(I).Name.all));
	       Text_Io.Put_Line(Current_Game.Products(I).Name.all);
	       
	       Wide_String'Output(Channel, Current_Game.Products(I).Description.all);
	       Text_Io.Put_Line(Current_Game.Products(I).Documentation.all);
	       
	       Wide_String'Output(Channel, To_Wide_String(Current_Game.Products(I).Documentation.all));
	       Fixed_Unit_Ht'Output(Channel, Current_Game.Products(I).Unit_Ht);
	       Text_Io.Put_Line(Fixed_Unit_Ht'Image(Current_Game.Products(I).Unit_Ht));
	       
	       Fixed_Factor'Output(Channel, Current_Game.Products(I).TVA_Rate);
	       Text_Io.Put_Line(Fixed_Factor'image(Current_Game.Products(I).TVA_Rate));
	       
	       
	       Fixed_Total'Output(Channel, Current_Game.Products(I).TVA);
	       Text_Io.Put_Line(Fixed_Total'image(Current_Game.Products(I).TVA));
	       
	       Fixed_Unit_Ttc'Output(Channel, Current_Game.Products(I).Unit_TTC);
	       Text_Io.Put_Line(Fixed_Unit_Ttc'image(Current_Game.Products(I).Unit_TTC));
	       
	       delay 0.1;
	    end loop;
	 end if;
	 Text_Io.Put_Line("Done");
      	 Gnat.Sockets.Close_Socket(Socket.all);
      else
	 Gnat.Sockets.Close_Socket (Socket.all);
      end if;
   exception
      when Constraint_Error =>
	 --Text_Io.Put_Line("Human_Thread_Server : Constraint_error");
	 Gnat.Sockets.Close_Socket(Socket.all);
   end Products_Thread_Server;

   
   
   
   procedure Unchecked_Deallocation_Products_server is
      new Ada.Unchecked_Deallocation(Products_Thread_Server, Products_server_Access);
   procedure Unchecked_Deallocation_Products_server_task is
      new Ada.Unchecked_Deallocation(Products_Thread_Server_Task, Products_server_Task_Access);
   
   
   

   task body Products_Server is
      
      
      
      
      Max_Client : constant Positive := 500;
      
      Liste : array(1..Max_Client) of Socket_access;
      Liste_Thread_task : array(1..Max_Client) of Products_Server_Task_Access;
      Bliste : array(1..Max_Client) of Boolean;
      Reads,Write : Socket_Set_Type;

      Selector : Selector_Type;
      Srv_Adr,Adr : Sock_Addr_Type;
      Srv_Socket : Socket_Type;
      Status : Selector_Status;

      Ptr : Integer := 0;
      
      
      function Chercher return Natural is
      begin
	 for I in 1..Max_Client loop
	    if Liste_Thread_Task(I) = null then
	       return I;
	    elsif not Is_callable(Liste_Thread_Task(I).Id) or Is_terminated(Liste_Thread_Task(I).Id) then
	       Unchecked_Deallocation_Products_Server(Liste_Thread_Task(I).Thread_Server);
	       Unchecked_Deallocation_Products_Server_Task(Liste_Thread_Task(I));
	       Liste_Thread_Task(I) := null;
	       Liste(I) := new Socket_Type;
	       return I;
	    end if;
	 end loop;
	 return 0;
      end Chercher;
      
      

      Thread_Suivant : Natural := 0;

      End_Of_Task : Boolean := False;
      Run : Boolean := False;
                       
   begin
      accept Initialize;
      for I in 1..Max_Client loop
	 liste(I) := new Socket_Type;
      end loop;
      Text_Io.Put_Line("Server initialize sockets...");
      
      
      Bliste := (others => False);
      
      Srv_Adr.Addr := Any_Inet_Addr;
      Srv_Adr.Port := 1988;
      
      Create_Socket(Srv_Socket);
      
      Set_Socket_Option
	(Srv_Socket,
	 Socket_Level,
	 (Reuse_Address, True));
      delay 0.2;
      
      Bind_Socket(Srv_Socket,Srv_Adr);

      Listen_Socket(Srv_Socket);
      
      Create_Selector(Selector);
      
	 
	 
      while not End_Of_Task loop
	 loop
	    select
	       accept Initialize;
	    or
	       accept Start;
	       exit;
	    or

	       accept Stop;
	    or
	       accept Halt do
		  End_Of_Task := True;
	       end Halt;
	       exit;
	    end select;
	 end loop;
	 Text_Io.Put_Line("Server sockets initialized.");
	 while not End_Of_Task loop
	    select
	       accept Initialize;
	    or
	       accept Start;
	    or
	       accept Stop;
	       exit;
	    or
	       accept Halt do
		  End_Of_Task := True;
	       end Halt;
	       exit;
	    or
	       delay 0.0;
	       
	       
	       
	       Empty(Reads);
	       
	       Set(Reads,Srv_Socket);

	       for I in 1..Max_Client loop
		  if Bliste(I) then
		     Set(Reads, Liste(I).all);
		  end if;
	       end loop;

	       Check_Selector(Selector, Reads, Write, Status);
	       
	       case Status is
		  when Completed =>
		     
		     if Is_Set(Reads,Srv_Socket) then
			Thread_Suivant := Chercher;

			if Thread_Suivant /= 0 then
			   Ptr := Thread_Suivant;
			   --Text_Io.Put_Line("Server accept");
			   Accept_Socket(Srv_Socket, Liste(Ptr).all, Adr);
			   --Text_Io.Put_Line("Server accepted");
			   --  Set_Socket_Option
			   --                                  (Liste(Ptr).all,
			   --                                   Socket_Level,
			   --                                   (Reuse_Address, True));
			   select
			      accept Halt do				 
				 End_Of_Task := True;
			      end Halt;
			      exit;
			   or
			      accept Stop;
			      exit;
			   or delay 2.0;
			   
			   end select;
			   
			   Bliste(Ptr) := True;
			else
			   delay 1.0;
			   --     Text_Io.Put_Line("Client suivant = zero ");
			   --     select
			   --  	accept Halt;	    
			   --  	--Ptr := Chercher;
			   --  	exit;
			   --     or delay 2.0;
			   --     end select;
			end if;
		     else

			for I in 1..Max_Client loop


			   if bliste(I) then

			      if Is_Set(Reads,Liste(I).all) then
				 Liste_Thread_Task(I) := new Products_Thread_Server_Task;

				 Liste_Thread_Task(I).Thread_Server := new Products_Thread_Server(Liste(i));

				 Liste_Thread_Task(i).Thread_Server.Get_Id(Liste_Thread_Task(i).Id);


				 Bliste(i) := false;

			      end if;
			   end if;
			end loop;
		     end if;
		  when Expired =>
		     Text_Io.Put_Line("expired");
		  when Aborted =>
		     Text_Io.Put_Line("aborted");
	       end case;	
	    end select;
	 end loop;
      end loop;
      Put_Line("Product server halted");
   end Products_Server;
   

   
end M.Servers ;