-- tmenu is tiny menu on 80x25
-- Tmenu 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-11-21 19:07:47"
-- Version := "0.0.0r"
with T ; 
with Ada.Wide_Text_Io ;
with Ada.Text_Io ;
use Ada ;
with Gnat.Os_Lib ;
use Gnat ;
use Gnat.Os_Lib;
with Ada.Directories ;
with Ada.Characters.Handling ;
use Ada.Characters ;
with Ada.Wide_Characters.Handling ;
use Ada.Wide_Characters.Handling ;

with Ada.Strings.Fixed ;
use Ada.Strings ;
with PragmARC.Ansi_TTY_Control ;
use PragmARC ;

procedure Tmenu is

   package W_Io renames Ada.Wide_Text_Io;
   use Text_Io;
   
   Target        : Wide_String(1..57) := (others => Wide_Character ' Val (32)) ;
   Last          : Natural := 0 ;
   Args          : Os_Lib.Argument_List_Access;
   Cmd_Name      : String_Access;
   Arg_Top       : Natural := 0;
   Errno         : Integer := 0;
   Menu_Filename : constant String := "main_menu.txt";
   Top_Col       : Positive := 20;
   Entry_Line    : Positive := 23;
   Top_Line      : constant Positive := 4;
   Menu_File     : W_Io.File_Type;
   Program_Name  : String_Access;
   Input_Line    : String_Access;
   Top_Name      : constant Positive := 32;
   Name_Index    : Natural := 0;
   File_Index    : Natural := 0;
   type Action_Array is array (Positive range <>) of String_Access;
   Done          : Boolean := False;
   Success       : Boolean := False;
   Args_Index    : Natural := 0;
   Menu_24 : Action_Array(1..18) := 
     
     (
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String("")),
      new String ' (Handling.To_String(""))
      );
begin
   loop
      Put(Ansi_TTY_Control.Clear_Screen);
      if Os_Lib.Is_Regular_File(Menu_Filename) then
	 W_Io.Open(Menu_File, W_Io.In_File, Menu_Filename, Form => "WCEM=8");
      else
	 return;
      end if;
      if not W_Io.End_Of_File(Menu_File) then
	 begin
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	 exception
	    when others =>
	       Put_Line("Error during reading menu file.");
	       return;
	 end;
      end if;
      for Item in Menu_24 ' Range loop
	 if not W_Io.End_Of_File(Menu_File) then
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Menu_24(Item));
	    Name_Index := Fixed.Index(Input_Line.all, Character'Val(27) & "", Top_Name);
	    Menu_24(Item) := new String ' (Input_Line(Top_Name..Name_Index-1));
	    Os_Lib.Free(Input_Line);
	    File_Index := File_Index + 1;
	 end if;
      end loop;
      if not W_Io.End_Of_File(Menu_File) then
	 begin
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	    Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
	    Put_Line(Input_Line.all);
	    Os_Lib.Free(Input_Line);
	 exception
	    when others =>
	       Put_Line("Error during reading menu file.");
	       New_Line(2);
	       return;
	 end;
      end if;
      W_Io.Close(Menu_File);
      
      
      
      
  Main :
      loop
	 declare
	    
	    Wchar : Wide_Character := Wide_Character ' Val (32);
	 begin
	Menu :
	    loop
	       Put(Ansi_TTY_Control.Position(Entry_Line, Top_Col) & Handling.To_String(Target(Target'First .. Last)));
	       W_Io.Get_immediate(Wchar);
	       
	       if Is_Control (Wchar) then
		  case Wchar is
		     when Wide_Character ' Val (10) | Wide_Character ' Val (13) =>
			Done := True;
		     when Wide_Character ' Val (27) =>
			New_Line(2);
			return;
			
		     when Wide_Character ' Val (127) | Wide_Character ' Val (8) =>
			
			Target(Last) := Wide_Character ' Val (32);
			Last := Last - 1;
			Put(Ansi_TTY_Control.Clear_Screen);
			if Os_Lib.Is_Regular_File(Menu_Filename) then
			   W_Io.Open(Menu_File, W_Io.In_File, Menu_Filename, Form => "WCEM=8");
			else
			   New_Line(2);
			   return;
			end if;
			File_Index := 0;
			if not W_Io.End_Of_File(Menu_File) then
			   begin
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			   exception
			      when others =>
				 Put_Line("Error during reading menu file.");
				 New_Line(2);
				 return;
			   end;
			end if;
			for Item in Menu_24 ' Range loop
			   if not W_Io.End_Of_File(Menu_File) then
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Menu_24(Item));
			      Name_Index := Fixed.Index(Input_Line.all, Character'Val(27) & "", Top_Name);
			      Menu_24(Item) := new String ' (Input_Line(Top_Name..Name_Index-1));
			      Os_Lib.Free(Input_Line);
			      File_Index := File_Index + 1;
			   end if;
			end loop;
			if not W_Io.End_Of_File(Menu_File) then
			   begin
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			      Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
			      Put_Line(Input_Line.all);
			      Os_Lib.Free(Input_Line);
			   exception
			      when others =>
				 Put_Line("Error during reading menu file.");
				 New_Line(2);
				 return;
			   end;
			end if;
			W_Io.Close(Menu_File);

		     when others =>
			null;
		  end case;
		  
		  
	       else
		  
		  Target(Last + 1) := Wchar;
		  Last := Last + 1;
	       end if;
	       
	       if Done then
		  begin
		     

		     
		     
		     Program_Name := new String ' (Handling.To_String(Target(Target'First..Last)));

		     if Program_Name = null or else Program_Name'Length = 0 then
			raise End_Error;
		     elsif Program_Name(Fixed.Index_Non_Blank(Program_Name.all)..Fixed.Index_Non_Blank(Program_Name.all, Backward)) = "exit" then
			New_Line(2);
			return;
		     end if;
		     Done := False;


		     for Name in Menu_24'Range loop
			if Menu_24(Name).all = 
			  Program_Name(Fixed.Index_Non_Blank(Program_Name.all)..Fixed.Index_Non_Blank(Program_Name.all, Backward))
			then

			   Done := True;
			   exit Menu;
			elsif Menu_24(Name).all = 
			  Program_Name(Fixed.Index_Non_Blank(Program_Name.all)..Fixed.Index(Program_Name.all, " ") - 1)			   
			then

			   Args_Index := Fixed.Index(Program_Name.all, " ");
			   Done := True;
			   exit Menu;
			end if;
		     end loop;
		  exception
		     when W_Io.End_Error =>
			Target := (others => Wide_Character ' Val (32)) ;
			Last := 0;
			Put(Ansi_TTY_Control.Position(Entry_Line, 4) & Fixed."*"(64, Character ' Val (32)));
			Put(Ansi_TTY_Control.Position(Entry_Line, 4) & "Error : presse ENTER to continue.");
			
			W_Io.Get_Immediate(Wchar);
			Put(Ansi_TTY_Control.Position(Entry_Line, 4) & Fixed."*"(64, Character ' Val (32)));
			for Old in Menu_24 ' range loop
			   Os_Lib.Free(Menu_24(Old));
			end loop;
			Done := False;
			exit;
		  end;
	       end if;
	       
	    end loop Menu;

	    if not Done then
	       File_Index := 0;
	       Put(Ansi_TTY_Control.Clear_Screen);
	       if Os_Lib.Is_Regular_File(Menu_Filename) then
		  W_Io.Open(Menu_File, W_Io.In_File, Menu_Filename, Form => "WCEM=8");
	       else
		  New_Line(2);
		  return;
	       end if;
	       if not W_Io.End_Of_File(Menu_File) then
		  begin
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		  exception
		     when others =>
			Put_Line("Error during reading menu file.");
			New_Line(2);
			return;
		  end;
	       end if;
	       for Item in Menu_24 ' Range loop
		  if not W_Io.End_Of_File(Menu_File) then
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Menu_24(Item));
		     Name_Index := Fixed.Index(Input_Line.all, Character'Val(27) & "", Top_Name);
		     Menu_24(Item) := new String ' (Input_Line(Top_Name..Name_Index-1));
		     Os_Lib.Free(Input_Line);
		     File_Index := File_Index + 1;
		  end if;
	       end loop;
	       if not W_Io.End_Of_File(Menu_File) then
		  begin
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		     Input_Line := new String ' (handling.To_String(W_Io.Get_Line(Menu_File)));
		     Put_Line(Input_Line.all);
		     Os_Lib.Free(Input_Line);
		  exception
		     when others =>
			Put_Line("Error during reading menu file.");
			New_Line(2);
			return;
		  end;
	       end if;
	       W_Io.Close(Menu_File);
	    end if;
	    exit;
	 exception
	    when others =>
	       null;
	 end;
      end loop Main;

      if Args_Index /= 0 then

	 Args := 
	   Argument_String_To_List(Program_Name(Args_Index + 1 .. Fixed.Index_Non_Blank(Program_Name.all, Backward)));
	 New_Line(2);
	 Spawn(Locate_Exec_On_Path(Handling.To_Lower(Program_Name(Fixed.Index_Non_Blank(Program_Name.all)..Args_Index-1))).all, Args.all, Success);
	 Free(Program_Name);
	 if Success then
	    Target := (others => Wide_Character ' Val (32));
	    Last := 0;
	 end if;
      elsif Fixed.Index_Non_Blank(Program_Name.all) /= 0 then

	 Args := new Argument_List(1..0);       
	 New_Line(2);
	 Spawn(Locate_Exec_On_Path(Handling.To_Lower(Program_Name(Fixed.Index_Non_Blank(Program_Name.all)..Fixed.Index_Non_Blank(Program_Name.all, Backward)))).all, Args.all, Success);
	 Free(Program_Name);
	 if Success then
	    Target := (others => Wide_Character ' Val (32));
	    Last := 0;
	 end if;
      else
	 Target := (others => Wide_Character ' Val (32));
	 Free(Program_Name);
	 Last := 0;
      end if;
   end loop;

end Tmenu ;