/****************************************************************************
	Aplikace Konzole je emulator terminalu. Umoznuje ovladat pocitac s
	OS Linux pomoci terminalu.

*****************************************************************************/
#ifdef PCSIM
	#include "stdafx.h"
#endif
#include "Applications.h"
#include "OS.h"
#include "GRAPHICS.h"
#include "lBuffer.h"
#include "extra.h"
#include "GLCD.h"
#include "Drivers.h"

/****************************************************************************
	Definice pisem pro aplikaci

*****************************************************************************/
FONT consoleScreenFont = {RGB_GREEN,FONT_SMALL,RGB_LIGHT_BLUE};
FONT consoleTextBoxFont = {RGB_GREEN, FONT_MINIMAL, RGB_BLACK};
FONT consoleButtonFont = {RGB_RED,FONT_SMALL,RGB_DARK_GRAY};

TScreen consoleScreen;															//Okno aplikace
TScreenObject consoleScreenObjects[CONSOLE_OBJECT_COUNT];						//Definice pole objektu

TApplicationInternal ConsoleInternal;											//Ridici objekt aplikace

LBuffer textBoxBuff;															//Jadro aplikace (zpracovava data ze seriove linky a formatuje je do text boxu)

CURSOR_STATE *localCursor;														//Ukazatel na stav kurzoru

#ifdef PCSIM
static unsigned char serialBuffer[10000] = "";									//Definice serioveho bufferu - verze pro PC
#else
static unsigned char serialBuffer[10000]__attribute__ ((section(".bss2"))), SerialOutRS232_2 __attribute__ ((section(".bss2")));												//Seriovy buffer - verze pro LPC2478
#endif

/****************************************************************************
	Definice parametru objektu obrazu

*****************************************************************************/
TScreenObjectParams consoleTextBoxParams = {CONSOLE_TEXT_BOX_WIDTH, CONSOLE_TEXT_BOX_HEIGHT, &consoleTextBoxFont};
TScreenObjectParams consoleButtonParams = {CONSOLE_BUTTONS_WIDTH, CONSOLE_BUTTONS_HEIGHT, &consoleButtonFont};

/****************************************************************************
	Funkce pro kresleni Text boxu

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void DrawConsoleTextBox(TScreenObject * obj, OBJECT_MESSAGE msg)
{
	TRect textAreaRect = {obj->x, obj->y, obj->x+obj->params->width, obj->y+obj->params->height};		//Definice obdelniku text boxu
	if (msg == MSG_COMPLETE)																			//POkud se ma prekreslit vse
		DrawTextBoxShape(obj,MSG_NONE);																	//Vykresli tvar objektu
	LCD_Set_Font(&consoleTextBoxFont);																	//Nastaveni fontu
	LCD_Set_ROI(&textAreaRect);																			//Nastaveni ROI
	for (short i = 0; i < textBoxBuff.length; i++)														//Vypsani textovych linek
	{
		LCD_Goto_XY(obj->x+5, obj->y+i*LCD_get_font_height(consoleTextBoxFont.size)+8);
		textBoxBuff.PrintLine(i);
	}

	drawCursor(localCursor->active);																	//Vykresleni kurzoru
}

/****************************************************************************
	Funkce odezvu ukoncovaciho tlacitka

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void EndButtonCallback(TScreenObject * obj, OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;obj;
#endif
	ConsoleInternal.State = CONSOLE_STOP;											//Ukonceni aplikace
}

/****************************************************************************
	Funkce pro odezvu tlacitka klavesnice

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void KeyboardButtonCallback(TScreenObject * obj, OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;obj;
#endif
	ConsoleInternal.RunApplication(KEYBOARD);										//Spusteni klavesnice
}

/****************************************************************************
	Odezva tlacitka Spojeni

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void SetupButtonCallback(TScreenObject * obj,OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;obj;
#endif
	ConsoleInternal.State = tmp_dialog_show;										//Vyzadani spusteni dialogu
}

/****************************************************************************
	Odezva tlacitka Specialni klavesnice

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void SpecialsButtonCallback(TScreenObject * obj,OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg; obj;
#endif
	ConsoleInternal.RunApplication(SPECIALS);										//Spusteni aplikace Specials
}

/****************************************************************************
	Odezva TextBoxu na kliknuti
		=> reaguje jako bych mackal na sipky, podobne jako Touchpad

	Vstup: 
		obj:			Instance objektu
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
void ConsoleTextBoxCallback(TScreenObject * obj, OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;obj;
#endif
	char buff[5] = {0x1B,'O',0,0};											//Sestaveni prikazoveho stringu
	switch(msg)
	{
	case MSG_CLICK:
		if (ConsoleInternal.ClickPosition.x > 350)							//Pokud klikam doprava
		{

			buff[2] = 'C';													//vlozim C
			SendSerialMessage(remoteConnection,(unsigned char*)buff);		//odeslat
		}
		else if (ConsoleInternal.ClickPosition.x < 130)						//Pokud klikam doleva
		{

			buff[2] = 'D';													//pridam D
			SendSerialMessage(remoteConnection,(unsigned char*)buff);		//Odeslat
		}
		else if (ConsoleInternal.ClickPosition.y < 110)						//Klikam nahoru
		{
			buff[2] = 'A';													//pridam A
			SendSerialMessage(remoteConnection,(unsigned char*)buff);		//Odeslat
		}
		else
		{
			buff[2] = 'B';													//Pridam B ->dolu
			SendSerialMessage(remoteConnection,(unsigned char*)buff);		//Odeslat
		}

	default:
		break;
	}
}


/****************************************************************************
	Funkce pro inicializaci aplikace

	Vstup: 
		neni

	Vystup
		RESULT:			Vysledek operace

*****************************************************************************/
RESULT consoleInitialize(void)
{
	consoleScreen.Init(CONSOLE_OBJECT_COUNT,consoleScreenObjects,&consoleScreenFont,YES);					//Inicializace okna aplikace
	ConsoleInternal.Init(CONSOLE,CONSOLE_XA, CONSOLE_YA, CONSOLE_XC, CONSOLE_YC,&consoleScreen,0,YES);		//Inicializace ridici struktury
    textBoxBuff.Init();																					//Inicializace textoveho bufferu
	if (ConsoleInternal.Screen == 0)
	{
		DebugOut("Screen could not be alocated.\n");
		return FAILED;
	}
	/****************************************************************************
		Inicializace parametru objektu

	*****************************************************************************/
	ConsoleInternal.Screen->objects[CONSOLE_TEXT_BOX].Init(	CONSOLE_TEXT_BOX_LEFT,
															CONSOLE_TEXT_BOX_TOP,
															TEXT_BOX,
															CONSOLE_TEXT_BOX,
															0,
															OBJECT_ENABLED,
															&consoleTextBoxParams,
															&ConsoleTextBoxCallback,
															&DrawConsoleTextBox);

	ConsoleInternal.Screen->objects[CONSOLE_KEYBOARD].Init(	CONSOLE_BUTTONS_LEFT+CONSOLE_BUTTONS_DISTANCE*(CONSOLE_KEYBOARD-1),
															CONSOLE_BUTTONS_TOP,
															BUTTON,
															CONSOLE_KEYBOARD,
															STR_KEYBOARD,
															OBJECT_ENABLED,
															&consoleButtonParams,
															&KeyboardButtonCallback,
															&DrawButton);

	ConsoleInternal.Screen->objects[CONSOLE_EXIT].Init(		CONSOLE_BUTTONS_LEFT+CONSOLE_BUTTONS_DISTANCE*(CONSOLE_EXIT-1),
															CONSOLE_BUTTONS_TOP,
															BUTTON,
															CONSOLE_EXIT,
															STR_EXIT,
															OBJECT_ENABLED,
															&consoleButtonParams,
															&EndButtonCallback,
															&DrawButton);

	ConsoleInternal.Screen->objects[CONSOLE_CONNECTION].Init(	CONSOLE_BUTTONS_LEFT+CONSOLE_BUTTONS_DISTANCE*(CONSOLE_CONNECTION-1),
																CONSOLE_BUTTONS_TOP,
																BUTTON,
																CONSOLE_CONNECTION,
																STR_SETUP,
																OBJECT_ENABLED,
																&consoleButtonParams,
																&SetupButtonCallback,
																&DrawButton);

	ConsoleInternal.Screen->objects[CONSOLE_SPECIALS].Init(	CONSOLE_BUTTONS_LEFT+CONSOLE_BUTTONS_DISTANCE*(CONSOLE_SPECIALS-1),
															CONSOLE_BUTTONS_TOP,
															BUTTON,
															CONSOLE_CONNECTION,
															STR_SPECIALS,
															OBJECT_ENABLED,
															&consoleButtonParams,
															&SpecialsButtonCallback,
															&DrawButton);
	localCursor = textBoxBuff.GetCursorState();			//Ziskani ukazatele na strukturu kurzoru

	
return PASSED;
}



/****************************************************************************
	Postovni schranka aplikace

	Vstup: 
		msg:			Zprava pro aplikaci

	Vystup
		RESULT:			Vysledek

*****************************************************************************/
RESULT CMsgBox(MESSAGE * msg)
{
	POSITION* tmpPosition = 0;
	switch (msg->msg)
	{
	case RUN:
		DebugOut("Console RUN command received.\n");
		if (ConsoleInternal.State == CONSOLE_READY)						//Pokud je aplikace zinicializovana
		{
			ConsoleInternal.State = CONSOLE_RESTART;					//pozaduj spusteni
            textBoxBuff.Init();											//resetuj buffer
			return PASSED;
		}
		break;
	case INIT:
		if (ConsoleInternal.State == CONSOLE_NOT_INITIALIZED)			//Pokud neni zinicializovana
		{
			DebugOut("Console INIT command received.\n");
			ConsoleInternal.State = CONSOLE_INITIALIZE;					//Inicializuj
			return PASSED;
		}
		break;
	case GET_STATE:
		//DebugOut("Console GET_STATE command received.\n");
		return (RESULT)ConsoleInternal.State;							//Vraci stav aplikace
		break;
	case APP_CLICK:
		ConsoleInternal.ClickPosition.isFresh = YES;					//Po prijeti kliknuti
		tmpPosition = (POSITION*)msg->data;								//Uloz data k dalsimu zpracovani
		ConsoleInternal.ClickPosition.x = tmpPosition->x;
		ConsoleInternal.ClickPosition.y = tmpPosition->y;
		DebugOut("Console click received.\n");
		return PASSED;
	default:
		break;
		
	}
	return FAILED;
}

/****************************************************************************
	Zpracovani dat ze seriove linky

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
static void ProceedSerialData(void)
{
	if (CheckSerialBuffer(remoteConnection) == YES)							//pokud jsou prijata data
	{
#ifndef PCSIM
		GetSerialData(remoteConnection,serialBuffer);						//Odeber je ze zasobniku
#else
		GetSerialData(remoteConnection,serialBuffer);						//Odeber je ze zasobniku
#endif
                
		textBoxBuff.insertData(serialBuffer);								//predej je parseru
		clearBuffer(serialBuffer,10000);									//Vymaz buffer

		ConsoleInternal.Screen->objects[CONSOLE_TEXT_BOX].draw(&ConsoleInternal.Screen->objects[CONSOLE_TEXT_BOX],MSG_CLICK);	//Prekresli Text box
		
	}
}


/****************************************************************************
	Ridici stavovy automat aplikace

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
void AppConsole(void)
{

	switch(ConsoleInternal.State)
	{
	case CONSOLE_NOT_INITIALIZED:
		break;
	case CONSOLE_INITIALIZE:
		consoleInitialize();									//Zinicializuj aplikaci
		ConsoleInternal.State = CONSOLE_READY;					//Prejdi do dalsiho stavu
		break;
	case CONSOLE_RESTART:	
		ConsoleInternal.Startup();								//Proved akce nutne pro spusteni
		ConsoleInternal.State = CONSOLE_DRAW;					//Prejdi do dalsiho stavu
		if (remoteConnection == OS_WIFI)						//Pokud je spojeni pres wifi
		{
			unsigned char t[40] = "IP: ";						//Vypis ve stavovem panelu IP
			str_append(t,remoteIP);
			StatusBarTextUpdate(t);
		}
		else
		{
			unsigned char t[40] = "Baudrate: ";					//jinak vypis komunikacni rychjlost (skoda ze se tam nevejde jmeno konzole)
			str_append(t,(unsigned char*)int2char(baudRates[baudIndex]));
			str_append(t,(unsigned char*)"kbps");
			StatusBarTextUpdate(t);
		}
		break;
	case CONSOLE_DRAW:	
		ConsoleInternal.Screen->Draw();							//Vykresli applikaci
		SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_REFRESH);		//Aktualizuj status bar
		ConsoleInternal.State = CONSOLE_ACTIVE;					//Prejdi do aktivniho stavu
		break;
	case CONSOLE_ACTIVE:
		ConsoleInternal.ProceedClick();							//Zpracuj kliknuti
		if (localCursor->changed == YES)						//Zpracuj informace o kurzoru
		{
			localCursor->changed = NO;
			ConsoleInternal.SetCursor(localCursor->active, localCursor->blink);
		}
		ConsoleInternal.ProceedCursor();						//proved pripadna blikani a tak...
		ProceedSerialData();									//zpracuj data ze seriovky
		break;
	case CONSOLE_WAITING:
		switch (ConsoleInternal.TryToResume())										//pokus o navrat z aplikace
		{
		case KEYBOARD:
			SendSerialMessage(remoteConnection,KeyboardBuffer.TextBuffer);						//Oeslani dat z klavesnice
			break;
		case SPECIALS:
			{
				unsigned char buff[8] = "";
				switch((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT))		//Zpracovani dat ze spec. klavesnice
				{
			
				case FN_ENTER:
					SendSerialMessage(remoteConnection,(unsigned char*)"\n");					//Enter
					break;
				case FN_SPACE:
					SendSerialMessage(remoteConnection,(unsigned char*)" ");					//Mezernik
					break;
				case FN_ESCAPE:
					buff[0] = 27;
					SendSerialMessage(remoteConnection,buff);									//Escape
					break;
				case FN_DEL:
					buff[0] = 127;
					SendSerialMessage(remoteConnection,buff);									//Delete
					break;
				case FN_BACKSPACE:
					buff[0] = BS;
					buff[1] = 0;
					SendSerialMessage(remoteConnection,buff);									//Backspace
					break;
				case FN_TAB:
					buff[0] = 9;
					SendSerialMessage(remoteConnection,buff);									//Tabulator
					break;
				case FN_HOME:
					//TODO...
					break;
				default:
					//zpracovani dalsich klaves (CTRL+neco nebo ALT+neco, pripadne F1-F12 - viz text)
					if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>='A' && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<='Z')
					{
						buff[0] = (unsigned char)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)-'A'+1;
					}else if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>='a' && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<='z')
					{
						buff[0] = (unsigned char)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)-'a'+0x1B;
					}else if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>=FN_F1 && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<=FN_F12)
					{
						buff[0] = ESC;
						buff[1] = '[';
						char corr = 0;
						if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT) > FN_F5)
							corr++;
						if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT) > FN_F10)
							corr++;
						unsigned char* out = (unsigned char*)int2char((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)+10+corr);
						strcopy(out,buff+2);
						str_append((unsigned char*)buff,(unsigned char*)"~");

					}
					SendSerialMessage(remoteConnection,buff);						//Odeslani pres seriovku
					break;
				}
				break;
			}
		case NONE:
			break;
		default:
			DebugOut("Returned to Console from unknown application.\n");
			break;
		}
		break;
	case CONSOLE_DIALOG_WAITING:
		ConsoleInternal.WaitForDialogStop();										//Cekani na dialog
		break;
	case CONSOLE_STOP:
		ConsoleInternal.Stop();														//Ukoncovaci prikazy
		break;
	case CONSOLE_READY:
		break;
	case CONSOLE_ERROR:
		break;
	case tmp_dialog_show:
		if (ConsoleInternal.GetAnswer((char*)"Nastavit parametry?") == NOT_ANSWERED)						//Konfiguracni skript
		{
			break;
		}
		else
		{
			if ((ANSWER)SendTaskMessage(DIALOG,&DEFAULT_MSG_GET_RESULT) == YES)							
			{
				DebugOut("YES!!!");
				SendSerialMessage(remoteConnection,(unsigned char*)"echo nastavuji parametry okna\n");		//info uziveteli
				SendSerialMessage(remoteConnection,(unsigned char*)"\nstty cols 60\nstty rows 16\n");		//nastaveni rozmeru terminalu
			}
			else
				DebugOut("NO!!!");

			ConsoleInternal.State = CONSOLE_DRAW;
		}
		break;
	default:
		break;
	}


}