program GUI;

uses crt, gLib2D, sdl_addon, sdl, sdl_ttf, sysutils, dateutils;

// -------------- Stack stuff

const
	STACK_SIZE = 100;

type
	stack_text = record
		text : Array[1..STACK_SIZE] of string;
		top_ptr : integer;
	end;

function initStack() : stack_text;
begin
	initStack.top_ptr := 0;
end;

function isEmpty(txt : stack_text) : boolean;
begin
	isEmpty := txt.top_ptr = 0;
end;

function isFull(txt : stack_text) : boolean;
begin
	isFull := txt.top_ptr = STACK_SIZE;
end;

function pop(var txt : stack_text) : string;
begin
	if isEmpty(txt) then pop := ''
	else
	begin
		pop := txt.text[txt.top_ptr];
		txt.top_ptr := txt.top_ptr-1;
	end;
end;

procedure push(input : string ; var txt : stack_text);
begin
	if not isFull(txt) then
	begin
		txt.top_ptr := txt.top_ptr + 1;
		txt.text[txt.top_ptr] := input;
	end;
end;

// -------------- SDL Addon
(*
function sdl_key_release : integer;
begin
    if (_event.type_ <> SDL_KEYUP) then
        exit(-1);
    
    exit(_event.key.keysym.sym);
end;
*)
// -------------- Background

procedure blitBG(bgImg : gImage);
begin
	gBeginRects(bgImg);
		gSetAlpha(255);
		gSetCoordMode(g_up_left);
		gSetCoord(0,0);
		gAdd;
	gEnd;	
end;

// -------------- Input

procedure blitInput(inputImg : gImage ; empty, bottom : boolean);
begin
	gBeginRects(inputImg);
		if empty then gSetAlpha(100) else gSetAlpha(255);
		gSetCoordMode(g_up_left);
		if bottom then gSetCoord(75,499) else gSetCoord(75,450);
		gSetColor(white);
		gAdd;
	gEnd;
end;

procedure showInput(var input : stack_text ; font : PTTF_font ; var line_full : boolean ; bottom : boolean);
var
	buffer : gImage;
begin
	if isEmpty(input) then
	begin
		buffer := gTextLoad('< Tapez votre message >',font);
		blitInput(buffer,true,false);
		gTexFree(buffer);
	end
	else
	begin
		buffer := gTextLoad(pop(input),font);
		blitInput(buffer,false,bottom and not isEmpty(input));
		gTexFree(buffer);
		if (buffer^.w > 420) and bottom then
			line_full := true;
		if bottom and not isEmpty(input) then showInput(input,font,line_full,false);
	end;
end;

// -------------- Chatlog

procedure blitChatlog(chatlogImg : gImage ; y : integer);
begin
	gBeginRects(chatlogImg);
	        gSetAlpha(255);
	        gSetCoordMode(g_up_left);
	        gSetCoord(75,y);
	        gSetColor(white);
	        gAdd;
	gEnd;
end;

procedure showChatlog(var chatlog : stack_text ; font : PTTF_font ; y : integer);
var
	buffer : gImage;
begin
	if not isEmpty(chatlog) and (y > 0) then
	begin
		buffer := gTextLoad(pop(chatlog),font);
		blitChatlog(buffer,y);
		gTexFree(buffer);
		showChatlog(chatlog,font,y-49);
	end;
end;

// -------------- Other blitting

procedure wholeBlit(bg : gImage ; input, chatlog : stack_text ; font : PTTF_font ; var line_full : boolean);
var
	tmpChat, tmpInput : stack_text;
begin
	blitBG(bg);
	tmpChat := chatlog;
	showChatlog(tmpChat,font,334);
	tmpInput := input;
	showInput(tmpInput,font,line_full,true);
	gFlip;
end;

// -------------- Keyboard/Updates

function send(var chatlog, input : stack_text) : integer;
var
	buffer : stack_text;
begin
	buffer := initStack();
	repeat
		push(pop(input),buffer)
	until isEmpty(input);
	push('Utilisateur dit :',chatlog);
	repeat
		push(pop(buffer),chatlog)
	until isEmpty(buffer);
	send := 0;
end;

function sdl_to_ascii(key : integer) : string;
// Conversion SDLK -> ASCII
var
	tmp : integer;
begin
	tmp := 0;
	case key of
		31 : sdl_to_ascii := 'ç';
		94 :
		begin
			while (tmp <= 0) and (sdl_update = 1) do
			begin
				tmp := sdl_get_keypressed;
				if (tmp > 0) then
				begin
					case tmp of
						32 : sdl_to_ascii := '^';
						94 : sdl_to_ascii := '^^';
						97 : sdl_to_ascii := 'â';
						101 : sdl_to_ascii := 'ê';
						105 : sdl_to_ascii := 'î';
						111 : sdl_to_ascii := 'ô';
						117 : sdl_to_ascii := 'û';
						121 : sdl_to_ascii := 'ŷ';
					else
						sdl_to_ascii := '^'+sdl_to_ascii(tmp);
					end;
				end;
			end;
		end;			
		224 : sdl_to_ascii := 'à';
		232 : sdl_to_ascii := 'è';
		233 : sdl_to_ascii := 'é';
		249 : sdl_to_ascii := 'ù';
	else
		sdl_to_ascii := chr(key);
	end;
end;

procedure appendInput(
	var input : stack_text;
	txt : string;
	var line_full : boolean);
var
	buffer : string;
begin
	buffer := pop(input);
	if (txt = '\0') and (length(buffer) > 1) then
	// Si backspace (et si possible sur une ligne)
		push(copy(buffer,1,length(buffer)-1),input)
	else if line_full then
	// Sinon, si ligne remplie
	begin
		line_full := false;
		push(buffer,input);
		push(txt,input);
	end
	else // Sinon, ajout en milieu de ligne
		push(buffer+txt,input);
end;

function update(
	var input, chatlog : stack_text;
	var line_full, caps, circ, trem : boolean) : integer;
var
	timestart : tDateTime; // Temps de départ (on keypress)
	key : integer; // Caractère entré
begin
	key := sdl_get_keypressed;
	if (key > 0) then
	begin
		case key of
			SDLK_caps : caps := not caps;
			SDLK_rshift, SDLK_lshift : caps := not caps;
			SDLK_return : update := 1;
			SDLK_escape : update := 3;
			94 :
			begin
				if circ then appendInput(input,'^',line_full);
				if trem then appendInput(input,'"',line_full);
				if circ or trem then
				begin
					if circ then appendInput(input,'^',line_full)
					else if trem then appendInput(input,'"',line_full);
				end;
				circ := not circ;
			end;
			224 : appendInput(input,'à',line_full);
			232 : appendInput(input,'è',line_full);
			233 : appendInput(input,'é',line_full);
			249 : appendInput(input,'ù',line_full);
		else
			if circ and not caps then
				case key of
					32 : appendInput(input,'^',line_full);
					97 : appendInput(input,'â',line_full);
					101 : appendInput(input,'ê',line_full);
					105 : appendInput(input,'î',line_full);
					111 : appendInput(input,'ô',line_full);
					117 : appendInput(input,'û',line_full);
					121 : appendInput(input,'ŷ',line_full);
				else
					sdl_to_ascii := '^'+sdl_to_ascii(tmp);
				end
			else
				
	

// -------------- Main procedures

procedure main();
// Procédure principale du GUI
var
	chatlog : stack_text; // Messages envoyés/reçus
	input : stack_text; // Message potentiel à envoyer
	event : integer; // Détermine un événement
	// 0 = Etat initial, 1 = Envoi du message utilisateur, 2 = Retour du bot, 3 = Quitter
	line_full : boolean; // true si ligne pleine, false sinon
	font : PTTF_font; // Police
	bg : gImage;
	caps : boolean; // Détermine si majuscules ou non
	circ : boolean; // Détermine si mode circonflexe ou non
	trem : boolean; // trema ou non
	
begin
	gClear(black);

	font := TTF_OpenFont('font.ttf', 30); // Police
	line_full := false; // Champ texte vide
	event := 0; // Etat initial
        
	bg := gTexLoad('background.jpg'); // Initialisation background
        
	chatlog := initStack(); // Init chatlog
	push('EISTI-Bot dit :',chatlog);
	push('Salutations, jeune ami(e) !',chatlog);
	
	input := initStack(); // Init input

	wholeBlit(bg,input,chatlog,font,line_full);
	
	while true do
	begin
		case event of
			1 : begin
				event := send(chatlog,input);
				line_full := false;
				wholeBlit(bg,input,chatlog,font,line_full);
				end;
			3 : exit;
		end;
		while sdl_update = 1 do
		begin
			begin
			if (sdl_get_keypressed > 0) then
			begin
				timestart := NOW;
				event := sdl_key(input,sdl_get_keypressed,line_full,caps,circ);
				wholeBlit(bg,input,chatlog,font,line_full);
			end;
			if sdl_do_quit then
				exit;
			end;
		end;
	end;
        
	gTexFree(bg);
end;

begin
	main();
end.
