-- 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 Lib.Intell;
---------------------------------------------------------------------------
--               client->termin->inter->config->center->G consol
--                                      |
-- hander->cyborg->intell->engine  ->	acces server_record
---------------------------------------------------------------------------
--           Neural network (Layer 0 -> Hander
--                          |   \/               cyborg -> Search->Path_Finding
--                         /\   |                intell -> Manual
--           Neural network (layer 1 -> Engine /
--                           |                 /  \
--                          /\               \/     \
--                               [ server ]           Lexic
---------------------------------------------------------------------------
with Lib.Classe ;
with Lib.Player ;
------------------------------------------------------
--
--
--
------------------------------------------------------
with Lib.Window ;
with Lib.Search ;
with Lib.Enumes ;
with Lib.Errors ;

with Ansi_Console;

With Ada.Unchecked_Deallocation;
use Ada;
with Gnat.Semaphores;
use Gnat.Semaphores;
with Gnat.Sha1;
use Gnat;
generic
   Glossary_Filename : String;
   Width_Line :Word_Range;
   Max_Words : Lexical_Range;
   Samples_Max : Positive;
   Network_Filename : String;
   Lines : Line_Range;
   Cols  : Column_Range;
   
   with package Classes is new Lib.Classe (<>);
   with package Window is new Lib.Window (<>);
package Lib.Engine is
   use Enumes;   
   use Player ;
   package Intelligency is new Lib.Intell (Glossary_Filename, Width_Line, Max_Words, Samples_Max, Network_Filename, Lines, Cols, Classes, window);
   
   type Engine_Record;
   
   use Classes;
   
   
   
   
   
   
   function equal (Left, Right : in Abstracted_Access) return Boolean;
   function "<" (Left, Right : in Abstracted_Access) return Boolean;
   function uniform  (E : in Abstracted_Access) return Float;
   function Heuristic (E : in Abstracted_Access) return Float;
   
   type E_Array is array (Positive range <>) of Abstracted_Access;
   
   function Successors (E : in Abstracted_Access) return E_Array;
   
   
   
   package Path_Finding is new Lib.Search.Path_Finding
     (Abstracted_Access, Heuristic, Uniform, Equal, "<", E_Array, Successors);
   
   
   procedure Astar (Start : in Abstracted_Access;
		    Goal : in Abstracted_Access;
		    Close  : out Abstracted_Vectors.Vector);
   
   
   task type Astar_Process (Engine : access Engine_Record) is
      entry Init (Start : in Abstracted_Access;
		  Goal : in Abstracted_Access);
      entry Close_Set(Closed_Out : out Abstracted_Vectors.Vector; End_Of_Task : out Boolean);
      entry Halt;
   end Astar_Process;
   
   
   task type Engine_Process (Engine : access Engine_Record) is
      entry Halt (End_Of_Program : out Boolean);
      entry Initialize;
      entry Receive (Wchar : in Wide_Character);
      entry Mode(Mode : out Mode_Enum);
      entry Reset;
      entry Switch (Mode : in Mode_Enum);
      entry Lock;
      entry Unlock;
      entry Set_On_Esc(Is_Escape : in Boolean);      
      entry Page_Down;
      entry Page_Up;
      entry Up_Arrow;
      entry Down_Arrow;
      entry Left_Arrow;
      entry Right_Arrow;
      entry Full_Screen;
      entry Del;
      entry Begin_Of;
      entry End_Of;
      entry Overwrite;
      entry Screen_Print;
      entry Shutdown;
      entry Send (Who, Where, How, Why, How_Mutch, How_Many : in Wide_String; Objects : out Intelligency.Object_Set);      
   end Engine_Process;
   
   
   type Window_Access is access Classes.Windows.Window_Type;
   
   procedure Win_Free is new Unchecked_Deallocation(Classes.Windows.Window_Type, Window_Access);
   
   
   
   
   Lines_Left : constant Natural := Lines-21;
   

   
   procedure Help(Win       : in Classes.Windows.Window_Type;
		  Win_Index : in out Positive;
		  Name      : out Name_Type);
   
   
   
   
   
   
   
   use Ansi_Console;
   
   Main_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (1, 1, 
      Lines, Cols,
      Classes.Windows.Single_Line_Frame, Cyan, Red);
   
   
   Input_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (4, 2, 
      3, Cols-2,
      Classes.Windows.Single_Line_Frame, yellow, white);
   
   
   Output_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (9, 2,
      4, (Cols-2)/2,
      Classes.Windows.Single_Line_Frame, green, magenta);
   
   Internal_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (15, 2,
      4, (Cols-2)/2,
      Classes.Windows.Single_Line_Frame, white, blue);
                  
   
   
   User_Objects_Tree_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (21, 2, 
      Lines_Left/2, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, yellow, white);
   
   
   User_Objects_View_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (21+Lines_Left/2+1, 2, 
      Lines_Left/2-1, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, Cyan, yellow);
   
   Ai_Objects_Tree_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (21, (Cols-2)/4+3, 
      Lines_Left/2, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, yellow, white);
   
   
   Ai_Objects_View_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (21+Lines_Left/2+1, (Cols-2)/4+3, 
      Lines_Left/2-1, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, Cyan, yellow);   
   
   
   Start_State_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (9, (Cols-2)/2+3, 
      10, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, Cyan, yellow);
   
   End_State_Win : constant Window_Access := new Classes.Windows.Window_Type '
     (9, (Cols-2)/2+3+(Cols-2)/4, 
      10, (Cols-2)/4,
      Classes.Windows.Single_Line_Frame, Cyan, yellow);
   
   
   use Intelligency.Expr_Vectors;
   use Intelligency.Prompt_Vectors;
   --use Classes;
   use Classes.Abstracted_Vectors;
   
   procedure Accounting_Wins_Draw(Wins : Accounting_Windows_Type);
   
   
   Accounting_Wins : Accounting_Windows_Type(21, (cols-2)/2+3);
   
   
   
   type Main_Windows_Type is tagged
      record
	 
	 Main_Win_Ptr : Window_Access := Main_Win;
	 
	 Input_Win_Ptr : Window_Access := Input_Win;
	 Output_Win_Ptr : Window_Access := Output_Win;
	 Internal_Win_Ptr : Window_Access := Internal_Win;
	 
	 User_Objects_Tree_Win_Ptr : Window_Access := User_Objects_Tree_Win;
	 User_Objects_View_Win_Ptr : Window_Access := User_Objects_View_Win;
	 
	 Ai_Objects_Tree_Win_Ptr : Window_Access := Ai_Objects_Tree_Win;
	 Ai_Objects_View_Win_Ptr : Window_Access := Ai_Objects_View_Win;
	 
	 
	 Start_State_Win_Ptr : Window_Access := Start_State_Win;
	 End_State_Win_Ptr : Window_Access := End_State_Win;	 	 
	 
	 Accounting_Wins : Accounting_Windows_Type(21, (Cols-2)/2+3);
	 
      end record;
   
   
   
   procedure Wins_Draw(Main_Wins : Main_Windows_Type);      
   
   Wins_Main : Main_Windows_Type;
   
   type Object_Counter is array (Tag_Name'Range) of Natural;
   
   type Terminal_record is tagged
      record
	 Write_Line_Index : Natural := 1;
	 Wins_Main : Main_Windows_Type;
	 Page_Index : Natural := 0;
	 Line : Intelligency.V_Line_Range := 1;
	 Col  : Column_Range := 1;            
	 V_Win_First : Intelligency.V_Index_Type := 0;
	 V_Win_Last  : Intelligency.V_Index_Type := 0;
	 Expr_List : Intelligency.Expr_Vectors.Vector;	    
	 Expr : Intelligency.Expression_Type := (others => Wide_Character'Val(32));	    
	 Prompt_List : Intelligency.Prompt_Vectors.Vector;
	 Prompt : Name_Type;
	 Obj    : Abstracted_Access;
	 V_Switch : Objects_Vector;
	 Obj_Cur  : Abstracted_Access;
	 Top      : Abstracted_Access;
	 Path_Index : Natural := 0;
      end record;
   procedure Save(T : in Terminal_Record);
   
   procedure Save (Object : in Abstracted_Access;
		   Filename : in String);
   
   
   procedure Restore(T : in out Terminal_Record;
   		     Win : in Classes.Windows.Window_Type;
   		     State : in Classes.Windows.Window_Type;
   		     Filename : in String);
   
   procedure Right_Exec (T : in out Terminal_Record;
   			 Win : in Classes.Windows.Window_Type;
   			 Prompt : out Name_Type);
   
   procedure Update(T : in out Terminal_Record;
   		    Prompt : in Name_Type;
   		    Expr   : in Intelligency.Expression_Type);
   
   
   procedure Switch(T : in out Terminal_Record;
   		    Num : in Abstracted_Index;
   		    Prompt : out Name_Type;
   		    Success : out boolean) ;
   
   
   procedure State_Draw(Where : in Classes.Windows.Window_Type;
			State : in Intelligency.Account.Account_State_Type);
   
   procedure Global_Content_Print (Object : Abstracted_Access;
   				   Win       : in Classes.Windows.Window_Type;
   				   Win_Index : in out Natural);
   
   -- Attribute the tree sum of heuristical and uniform values for all nodes.
   procedure Valuate_Tree (Object  : in Abstracted_Access);
   
   -- Estimate the ucost (unifom) and hcost (heuristic) values of full tree.
   procedure Evaluate_Tree (Object  : in Abstracted_Access;
			    Ucost   : out Float;
			    Hcost   : out float);
   
   
   type Terminal_Access is access all Terminal_Record;
   
   procedure Terminal_Free is new Ada.Unchecked_Deallocation(Terminal_Record, Terminal_Access);
   
   
   
   
   
   type Identified_Domain_Record is tagged
      record	
	 Id     : Identity_Record;
	 Term   : Terminal_Record;
	 Domain : Intelligency.Ai_Domain_Record(8192);
      end record;
   
   type Identified_Domain_Access is access all Identified_Domain_Record;
   
   type Identified_Domain_Arrays is array (Positive range <>) of Identified_Domain_Record;
   
   type Domain_Set(Max_Users : Positive) is tagged
      record
	 Set : Identified_Domain_Arrays(1..Max_Users);
      end record;
   
   
   
   
   type Engine_Record(Max_Users : Positive) is new Intelligency.Intell_Record with
      record
	 Astar_Proc  : Astar_Process (Engine_Record ' access);
	 Engine_Proc : Engine_Process (Engine_Record ' access);
	 Users       : User_Set(Max_Users);
	 Domains     : Domain_Set(Max_Users);
      end record;
   
   package Users_Manager is
      
      
      
      function Add_User(Logname : in String;
			Passwd : in Sha1.Message_Digest) return Boolean;
      

      
      function Check_passwd(Logname : in String;
			    Passwd : in Sha1.Message_Digest) return Boolean;
      
      
   private
      
      
      -- User define --
      
      subtype Logname_Type is String (1..64);
      
      
      
      type User_Type is tagged
	 record
	    Logname : Logname_Type := (others => Character ' Val (32)) ;
	    Passwd : Sha1.Message_Digest;
	 end record;                  
      
      procedure Initialize(User : out User_Type;
			   Name : in String);
      -- Get player named "Name".
      
      
      
      procedure Set_Pass(User : in out User_Type;
			 Pass : in Sha1.Message_Digest);
      -- Set password for player.
      
      function Check_Pass(User : in User_Type;
			  Pass : in Sha1.Message_Digest) return Boolean;
      -- Return True is getted password is valid. False else.      
      
      
      
      
   end Users_Manager;
   
   use Users_Manager;
end Lib.Engine ;