-- wterm is wide text terminal.
-- Wterm is Copyright (C) 2023 David Lightman ; 
--
--   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-10-20 13:18:00"
-- Version := "0.0.0r"
with Text_Io;
with Gnat.Sockets;
with Ada.Wide_Text_Io;
with Ada.Characters.Handling;
use Ada.Characters.Handling;
package body W.App.Engine is
   use Gnat.Sockets;
   package W_Io renames Ada.Wide_Text_Io;
   --type Term_Key is (None, Get, Screen, Line_count, Refresh, Position, line, Col, Logout, Lines, Columns);
   
   function System (Line : in String) return Integer;
   pragma Import (C, System,"system");
   Errno : Integer := 0;
   
   
   task type Console_Process(Channel : Stream_Access) is
      entry Initialize;            
      entry Halt;
   end Console_Process;
   
   task type Term_Process (Server : access String) is
      entry Initialize(Initialized : out Boolean);            
   end Term_Process;
   
   
   
   
   task body Console_Process is
      
      
      task Screen_Process is
	 entry Initialize;
	 entry Receive(Line : in Wide_String; Pos : in Natural);
	 entry Halt;	 
      end Screen_Process;
      
      task body Screen_Process is
	 
      begin
	 accept Initialize do
	    W_Io.Put(Wide_String ' Input (Channel));
	 end Initialize;
	 
	 loop
	    
	    select
	       accept Halt;
	       exit;
	    or
	       accept Receive(Line : in Wide_String; Pos : in Natural) do
		  	    
		  W_Io.Put(Line);
		  if Pos < Line'Length then
		     Errno := System("espeak " & """" & To_String(Line(Pos..Line'Last)) & """" & " 2> /dev/null" & Character'Val(0));
		  end if;
	       end Receive;
	    end select;
	 end loop;
      end Screen_Process;
      
      task Keyboard_Process is
	 entry Receive (Wchar : in Wide_Character);
	 entry Halt;
      end Keyboard_Process;
      
      task body Keyboard_Process is
      begin
	 loop
	    select
	       accept Receive (Wchar : in Wide_Character) do
		  Wide_Character'Output(Channel, Wchar);
	       end Receive;
	    or
	       accept Halt;
	       exit;
	    end select;
	 end loop;
      end Keyboard_Process;
      
      
      
      
      Key : Term_Key := None;
      Wchar : Wide_Character;
      
      Line_Pos : Natural := 0;
   begin
      accept Initialize do
	 Screen_Process.Initialize;
      end Initialize;
      loop
	 select
	    accept Halt do
	       Screen_Process.Halt;
	       --Text_Io.Put_Line("Screen halted");
	       Keyboard_Process.Halt;
	       --Text_Io.Put_Line("Keyboard halted");
	    end Halt;
	    exit;
	 or
	    delay 0.05;	    
	 end select;
	 Key := Term_Key'Input(Channel);
	 case Key is
	    when None =>
	       null;
	    when Get =>
	       begin
		  W_Io.Get_Immediate(Wchar);
		  Keyboard_Process.Receive(Wchar);
	       exception
		  when W_Io.End_Error =>
		     Keyboard_Process.Receive(Wide_Character'Val(4));	       
		     Screen_Process.Halt;		     
		     Keyboard_Process.Halt;		     
		     
		     exit;
	       end;
	       
	    when Screen =>
	       Line_Pos := Natural ' Input(Channel);
	       Screen_Process.Receive(Wide_String ' Input(Channel), Line_Pos);
	    when Logout =>
	       --Screen_Process.Halt;	      
	       --Keyboard_Process.Halt;	       
	       --exit;	       
	       Screen_Process.Receive(" exit ", natural'last);
	    when others =>
	       null;
	 end case;
      end loop;
   end Console_Process;
   
   
   task body Term_Process is
      Socket  : Socket_Type;
      Addr    : Sock_Addr_Type;      
      Channel : Stream_Access;
      Connected : Boolean := False;
   begin
      accept Initialize(Initialized : out Boolean) do
	 Initialized := False;
	 if Server'Length /= 0 then
	    begin
	       Addr.Addr := Addresses (Get_Host_By_Name (Server.all));
	       
	       Addr.Port := 6060;
	       
	       Create_Socket (Socket);
	       
	       Set_Socket_Option
		 (Socket,
		  Socket_Level,
		  (Reuse_Address, True));
	       
	       delay 0.2;
	       Connect_Socket (Socket, Addr);
	       Channel :=  Stream(Socket);	 
	       delay 0.2;
	       Wide_String'Output(Channel, "hello");
	       Initialized := True;
	       Connected := True;
	    exception
	       when Socket_Error =>
		  null;	       
	    end;
	    
	 end if;
      end Initialize;
      
      if Connected then
	 
	 declare
	    Console : Console_Process(Channel);
	 begin
	    Console.Initialize;	 
	 exception
	    when Socket_Error =>
	       Console.Halt;	       
	 end;
      end if;
	 
   end Term_Process;
   
   
   
   
   procedure Linux (Hostname : in String;Lines : in Line_Range;Columns : in Column_Range) is
      Term : Term_Process(new String ' (Hostname));
      Initialized : Boolean := False;
   begin
      Term.Initialize(Initialized);
      
      if not Initialized then
	 W_Io.Put_Line("Faillure");
      end if;
   end Linux;
   
   procedure Fvwm (Hostname : in String;Lines : in Line_Range;Columns : in Column_Range) is
      Term : Term_Process(new String ' (Hostname));
      Initialized : Boolean := False;
   begin
      Term.Initialize(Initialized);
      
      if not Initialized then
	 W_Io.Put_Line("Faillure");
      end if;
   end Fvwm;
end W.App.Engine ;