with Gnat.Sockets;
use Gnat.Sockets;
with Ada.Task_Identification;
use Ada.Task_Identification;
with Gnat.Sha1;
use Gnat;
with Ada.Streams.Stream_Io;
use Ada.Streams;
with Ada.Unchecked_Deallocation;

with Ada.Wide_Text_Io;
with Ada.Text_Io;

use Ada;

with Ada.Strings.Wide_Fixed;
use Ada.Strings;
with Ada.Characters.Handling;
use Ada.Characters;


with Gnat.Directory_Operations;
use Gnat.Directory_Operations;


with Ada.Wide_Characters;
with Ada.Wide_Characters.handling;


with Ada.Strings.UTF_Encoding.Strings;
with Ada.Strings.UTF_Encoding.Wide_Strings;

procedure Quickstartonline is
   
   
   
      function System(Line : in String) return Integer;
   pragma Import (C, System, "system");
   
   Errno : Integer := 0;   
   
   
   
   type socket_access is access all socket_type;   
   
   task The_Human_Server is
      entry Init;
      entry Halt;
   end The_Human_Server;
   
   
   type Wide_String_Access is access all Wide_String;
   procedure Wide_Free is new Ada.Unchecked_Deallocation(Wide_String, Wide_String_Access);
   
   type Wline_Array is array (Positive range <>) of Wide_String_Access;
   
      
   task body The_Human_Server is


      Filename : access string;
      project_name : access string;
      version : access string;


      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
	 
	 
	 Channel         : constant Stream_Access := Stream(Socket.all);
	 Hello           : access Wide_String;
	 
	 Success         : Boolean := False;
	 
	 Directory : access String;

	 fullpath : access string;

      begin
	 
	 accept Get_Id(Id : out Task_Id) do
	    Id := Current_Task;
	 end Get_Id;      
	 Hello := new Wide_String ' (Wide_String'Input(Channel));
	 Wide_Text_Io.Put_Line("hello");
	 filename := new string ' (String'Input(Channel));
	 project_name := new string ' (String'Input(Channel));
	 Version := new string ' (String'Input(Channel));
	 directory := new string ' (String'Input(Channel));
	 fullpath := new string ' ("/var/www/html/" & Directory.all & "/" & filename.all & ".txt");
	 text_io.put_line("Filenalme : " & Filename.all);
	 text_io.put_line("Project Name : " & project_name.all);
	 text_io.put_line("Version : " & version.all);
	 
	 Change_Dir("/var/www/html/" & Directory.all); 
	 
	 Errno := System("/usr/bin/bash -c ""/root/.bin/quickstart.sh " & fullpath.all & " " & project_name.all & " " & version.all & """" & Character'Val(0));      	   	    
	 
	 Change_Dir("/var/www/html/quickstart");
	 
	 Errno := System("chown -R www-data.www-data /var/www/html/" & Directory.all & Character'Val(0));
	 
	 
	 --text_io.Put_Line(integer'image(errno));
	 wide_String'Output(Channel, "hello");
      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);
      
      
      Max_Client : constant Positive := 50;
      
      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 Init;
      Text_Io.Put_Line("Server initialize sockets...");
      for I in 1..Max_Client loop
	 liste(I) := new Socket_Type;
      end loop;

      
      Bliste := (others => False);
      
      Srv_Adr.Addr := Any_Inet_Addr;
      Srv_Adr.Port := 7947;
      
      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);
      
      Text_Io.Put_Line("Server sockets initialized.");
      loop	 
	 
	 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;	    
			--Ptr := Chercher;
			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 loop;
   end The_Human_Server;
   
   
   
   
   
   
   
   
   
   
   
begin
	
	 The_Human_Server.init;
end quickstartonline;
