/****************************************************************************
	Aplikace Plocha pro ovladani PC v rezimu Touchpadu a Plochy

*****************************************************************************/
#ifdef PCSIM
	#include "stdafx.h"
#endif

#include "Applications.h"
#include "GRAPHICS.h"
#include "OS.h"
#include "extra.h"
#include "Drivers.h"
#include "GLCD.h"
#include "ImagesDesktop.h"

TScreen desktopScreen;													//Obrazovka aplikace
TScreenObject desktopScreenObjects[DESKTOP_OBJECT_COUNT];				//Objekty aplikace

ANSWER freshStart;														//Flag jestkli byla aplikace prave spustena

/****************************************************************************
	Definice pisem aplikace

*****************************************************************************/
FONT desktopScreenFont = {RGB_DARK_RED,FONT_SMALL,RGB_LIGHT_BLUE};;
FONT desktopButtonsFont = {RGB_CYAN,FONT_MINIMAL,RGB_LIGHT_GRAY};
FONT desktopTouchpadFont = {RGB_CYAN,FONT_SMALL,RGB_DARK_GRAY};

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

*****************************************************************************/
TScreenObjectParams desktopButtonsParams = {DESKTOP_TOUCHPAD_OFFSET_X-2*DESKTOP_BUTTON_OFFSET,(DESKTOP_YC-DESKTOP_YA-2*DESKTOP_TOUCHPAD_OFFSET_Y-2*DESKTOP_BUTTON_OFFSET)/3,&desktopButtonsFont};
TScreenObjectParams desktopMainShapeParams = {DESKTOP_XC-DESKTOP_XA,DESKTOP_YC-DESKTOP_YA,&desktopScreenFont};
TScreenObjectParams desktopTouchpadParams = {DESKTOP_XC-DESKTOP_XA-2*DESKTOP_TOUCHPAD_OFFSET_X,DESKTOP_YC-DESKTOP_YA-2*DESKTOP_TOUCHPAD_OFFSET_Y,&desktopTouchpadFont};

TOUCHPAD_MODE touchpadMode = TOUCHPAD;													//Aktualni rezim touchpadu

#ifdef PCSIM
static unsigned char serialBuffer[2560000];												//Seriovy buffer - definice pro simulator
#else
static unsigned char *serialBuffer;/*[2560000]__attribute__ ((section(".bss2")));*/		//Defomoce pro hardware
#endif

unsigned char kbDataToSend[1000];														//Buffer pro klavesnicova data k odeslani
TApplicationInternal DesktopInternal;													//Definice ridiciho objektu

static DESKTOP_MORE_STATE startingObject;												//Spousteci objekt dcerine aplikace								

int DesktopResult = -1;																	//Vysledek aplikace

ANSWER remoteConnectionEstablished = NO;												//Flag s informaci o aktivite spojeni

TIME_STAMP lastClickTime;																//Casova znamka - poledni klik
TIME_STAMP lastFrameReceived;															//Casova znamka - prijeti poslednich dat
POSITION lastClickPosition;																//posledni pozice kliknuti

POSITION prevPosition;																	//POsledni prijata pozice																

int x_offset = 0;																		//Offset obrazu z PC na displeji
int y_offset = 0;																		


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

	Vstup: 
		msg:			Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
RESULT DMsgBox(MESSAGE * msg)
{
	POSITION* tmpPosition = 0;

	switch (msg->msg)
	{
	case RUN:
		DebugOut("Desktop RUN command received.\n");
		remoteConnectionEstablished = NO;								//Reset flagu

		if (DesktopInternal.State == DESKTOP_READY)						//POkud je aplikace zinicializovana
		{
			DesktopResult = -1;											//reset vysledku
			DesktopInternal.State = DESKTOP_RESTART;					//start aplikace
			freshStart = YES;											//Spousteni "od nuly"
			return PASSED;
		}
		DebugOut("Desktop could not be run.\n");
		return FAILED;
			
		break;
	case INIT:
		if (DesktopInternal.State == DESKTOP_NOT_INITIALIZED)			//Pokud neni zinicializovana
		{
			DebugOut("Desktop INIT command received.\n");
			DesktopInternal.State = DESKTOP_INITIALIZE;					//Inicializuj
			return PASSED;
		}
		break;
	case GET_STATE:
		return (RESULT)DesktopInternal.State;							//Vraci stav aplikace
		break;
	case GET_RESULT:
		return (RESULT)DesktopResult;									//Vraci vysledek po ukonceni aplikace
		break;			
	case APP_CLICK:
		DesktopInternal.ClickPosition.isFresh = YES;					//Bylo prijato kliknuti od OS
		tmpPosition = (POSITION*)msg->data;								//Ulozeni dat ze zpravy pro dalsi zpracovani
		DesktopInternal.ClickPosition.x = tmpPosition->x;
		DesktopInternal.ClickPosition.y = tmpPosition->y;
		DebugOut("Desktop click received.\n");
		return PASSED;
		break;
	default:
		break;	
	}
	return FAILED;
}

/****************************************************************************
	Vykresleni Touchpadu

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void DrawDesktopTouchpad(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	DrawTextBoxShape(obj, message);

}

/****************************************************************************
	Funkce pro vykresleni vychoziho grafickeho objektu aplikace

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopMainCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (remoteControl != OS_TOUCHPAD)
		DrawTextBoxShape(obj,MSG_NO_BACKGROUND);
	else
		DrawTextBoxShape(obj,message);
	/*LCD_Goto_XY(obj->x+9, obj->y+8);
	if (remoteControl != OS_TOUCHPAD)
		LCD_printf(obj->caption);*/
}


/****************************************************************************
	Funkce odezvy tlacitka Klavesnice
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopKeyboardCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))	//Pokud neuplynul dostatecny cas, konec
		return;
	DesktopInternal.RunApplication(KEYBOARD);					//Jinak posli pozadavek na spusteni klavesnice
    LCD_store_videoRam();										//Uloz obrazovy buffer
}

/****************************************************************************
	Funkce odezvy tlacitka Prepinac Touchpad/Sipky
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopTouchpadSwitchCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))		//Ochrana proti sklouznuti prstu
		return;
	if (touchpadMode == TOUCHPAD)									//Pokud je rezim Touchpad
	{
		touchpadMode = ARRAYS;										//Prepni na rezim sipek
		obj->bitmap = BMP_touchpad;									//Vnut tlacitku obrazek
		obj->caption = STR_SCROLL_TOUCH;							//Uprav text tlacitka
	}
	else
	{
		touchpadMode = TOUCHPAD;									//jinak nastav rezim touchpadu
		obj->bitmap = BMP_sipky;									//Vnut obrazek sipek
		obj->caption = STR_SCROLL_ARRAY;							//Nahrad text tlacitka
	}
	desktopScreen.UpdateObject(obj->id,MSG_NO_BACKGROUND);			//Aktualizuj objekt
}

/****************************************************************************
	Funkce odezvy tlacitka Specialni klavesnice
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopSpecialsCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))		//pokud neuplynula dostatecne dlouha doba, konec
		return;
	DesktopInternal.RunApplication(SPECIALS);						//Spust klavesnici a uloz video buffer
    LCD_store_videoRam();
}


/****************************************************************************
	Funkce odezvy tlacitka Leva mys
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopMouseLeftCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))				//kontrola casoveho limitu
		return;
	/*if (CheckSerialSendComplete() == NO)									//Kontrola jestli je mozne odesilat
		return;*/
	SendSerialMessage(remoteConnection,(unsigned char*)"m\"c,0,0\"m\r\n");	//Odeslani informace o kliknuti

}

/****************************************************************************
	Funkce odezvy tlacitka Prava mys
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopMouseRightCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))				//Kontrola limitu
		return;
	/*if (CheckSerialSendComplete() == NO)
		return;*/
	 SendSerialMessage(remoteConnection,(unsigned char*)"m\"p,0,0\"m\r\n");	//Odeslani kliknuti
}


/****************************************************************************
	Funkce odezvy Touchpad

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void desktopTouchpadCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (touchpadMode == TOUCHPAD)														//Pokud je rezim touchpadu
	{
	  lastClickTime = GetTimeStamp();													//Odebrat casovou znamku
	  lastClickPosition.x = DesktopInternal.ClickPosition.x;							//ulozit pozici kliknuti
	  lastClickPosition.y = DesktopInternal.ClickPosition.y;
	  lastClickPosition.isFresh = YES; 
	}
	else
	{
		if (DesktopInternal.ClickPosition.x > 350)										//Pokud je kliknuti do prave casti Touchpadu	
		{

			SendSerialMessage(remoteConnection,(unsigned char*)"k\"P,{RIGHT},0\"k\n");	//Odeslat pravou sipku
		}
		else if (DesktopInternal.ClickPosition.x < 130)									//pokud je do leve casti
		{

			SendSerialMessage(remoteConnection,(unsigned char*)"k\"P,{LEFT},0\"k\n");	//Odeslat levou sipku
		}
		else if (DesktopInternal.ClickPosition.y < 110)									//POkud je nahoru
		{
			SendSerialMessage(remoteConnection,(unsigned char*)"k\"P,{UP},0\"k\n");		//Odeslat nahoru
		}
		else																			//jinak
		{
			SendSerialMessage(remoteConnection,(unsigned char*)"k\"P,{DOWN},0\"k\n");	//odeslat dolu
		}
	}
}


/****************************************************************************
	Funkce odezvy tlacitka Konec
	===>je implementovana ochrana proti sklouznuti prstu z touchpadu na 
		tlacitko.

	Vstup: 
		obj:				instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void DesktopExitButtonCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	if (BUTTON_SAFE_TIMEOUT > GetElapsedTime(lastClickTime))								//Ochranny limit
		return;
	TDialogCfg cfg = {QUESTION,COUNTDOWN_NONE,100,(unsigned char*)STR_END_DESKTOP,30};		//Sestaveni konfigurace Dialogu
	MESSAGE dialogMessage = {CONFIG,&cfg};													//Sestaveni zpravy pro aplikaci
	SendTaskMessage(DIALOG,&dialogMessage);													//Odeslani konfigurace
	DesktopInternal.RunApplication(DIALOG);													//Spusteni aplikace
    LCD_store_videoRam();																	//Ulozeni stavu plochy
}



/****************************************************************************
	Inicializace aplikace

	Vstup: 
		neni

	Vystup
		RESULT:		vysledek procesu

*****************************************************************************/
RESULT desktopInitialize(void)
{
	desktopScreen.Init(CONNECTOR_OBJECT_COUNT,desktopScreenObjects,&desktopScreenFont,NO);				//Inicializace obrazovky
	DesktopInternal.Init(DESKTOP,DESKTOP_XA,DESKTOP_YA,DESKTOP_XC,DESKTOP_YC,&desktopScreen,0,YES);		//Inicializace ridici struktury
	if (DesktopInternal.Screen == 0)
		return FAILED;
	
	/****************************************************************************
		Inicializace objektu

	*****************************************************************************/

		DesktopInternal.Screen->objects[DESKTOP_MAIN_SHAPE].Init(		DESKTOP_XA,
																DESKTOP_YA,
																BACKGROUND,
																DESKTOP_MAIN_SHAPE,
																STR_DESKTOP_ACQUIRE,
																OBJECT_ENABLED,
																&desktopMainShapeParams,
																0,
																&desktopMainCallback);

		DesktopInternal.Screen->objects[DESKTOP_TOUCHPAD].Init(	DESKTOP_XA+DESKTOP_TOUCHPAD_OFFSET_X,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y,
																BUTTON,
																DESKTOP_TOUCHPAD,
																(unsigned char*)" ",
																OBJECT_ENABLED,
																&desktopTouchpadParams,
																&desktopTouchpadCallback,
																&DrawTextBoxShape);
		
		DesktopInternal.Screen->objects[DESKTOP_MOUSE_LEFT].Init(DESKTOP_XA+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y,
																BUTTON,
																DESKTOP_MOUSE_LEFT,
																(unsigned char*)0,
																BMP_Mouse_left,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&desktopMouseLeftCallback,
																&DrawBitmappedButton);

		DesktopInternal.Screen->objects[DESKTOP_MOUSE_RIGHT].Init(DESKTOP_XA+DESKTOP_TOUCHPAD_OFFSET_X+desktopTouchpadParams.width+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y+0*(desktopButtonsParams.height+DESKTOP_BUTTON_OFFSET),
																BUTTON,
																DESKTOP_MOUSE_RIGHT,
																(unsigned char*)0,
																BMP_Mouse_right,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&desktopMouseRightCallback,
																&DrawBitmappedButton);

		DesktopInternal.Screen->objects[DESKTOP_KEYBOARD_BUTTON].Init(DESKTOP_XA+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y+desktopButtonsParams.height+DESKTOP_BUTTON_OFFSET,
																BUTTON,
																DESKTOP_KEYBOARD_BUTTON,
																STR_TEXT,
																BMP_Keyboard,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&desktopKeyboardCallback,
																&DrawBitmappedButton);



		DesktopInternal.Screen->objects[DESKTOP_SPECIALS_BUTTON].Init(DESKTOP_XA+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y+2*(desktopButtonsParams.height+DESKTOP_BUTTON_OFFSET),
																BUTTON,
																DESKTOP_SPECIALS_BUTTON,
																STR_SPEC,
																BMP_Joystick,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&desktopSpecialsCallback,
																&DrawBitmappedButton);

		DesktopInternal.Screen->objects[DESKTOP_EXIT_BUTTON].Init(DESKTOP_XA+DESKTOP_TOUCHPAD_OFFSET_X+desktopTouchpadParams.width+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y+2*(desktopButtonsParams.height+DESKTOP_BUTTON_OFFSET),
																BUTTON,
																DESKTOP_EXIT_BUTTON,
																STR_CANCEL,
																BMP_Exit,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&DesktopExitButtonCallback,
																&DrawBitmappedButton);

		DesktopInternal.Screen->objects[DESKTOP_SCROLL_BUTTON].Init(DESKTOP_XA+DESKTOP_TOUCHPAD_OFFSET_X+desktopTouchpadParams.width+DESKTOP_BUTTON_OFFSET,
																DESKTOP_YA+DESKTOP_TOUCHPAD_OFFSET_Y+1*(desktopButtonsParams.height+DESKTOP_BUTTON_OFFSET),
																BUTTON,
																DESKTOP_SCROLL_BUTTON,
																STR_SCROLL_ARRAY,
																BMP_sipky,
																OBJECT_ENABLED,
																&desktopButtonsParams,
																&desktopTouchpadSwitchCallback,
																&DrawBitmappedButton);

		return PASSED;
}


/****************************************************************************
	Funkce pri kazdem spusteni provede kontrolu prijatych dat a jejich zpracovani

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
static void ProceedSerialData(void)
{
	int xmin = 0;
	int xmax = 0;
	int ymin = 0;
	int ymax = 0;
	long int i = 0;
	if (CheckSerialBuffer(remoteConnection) == YES)													//Pokud byla prijata data
	{
#ifndef PCSIM
		serialBuffer = GetSerialData(remoteConnection);												//ziskej data ze serioveho bufferu - verze pro LPC2478
#else
		GetSerialData(remoteConnection,serialBuffer);												//ziskej data kopirovanim
#endif
		
		if (serialBuffer[0] == '?')																	//Prijata otazka na konfiguraci
		{
			if (remoteControl == OS_TOUCHPAD)														//Pokud je touchpad
			{
				SendSerialMessage(remoteConnection,(unsigned char*)"ERD,CT=Peripheral\r\n");		//odesli konfiguraci touchpadu
			}
			else
			{
				SendSerialMessage(remoteConnection,(unsigned char*)"ERD,CT=Display\r\n");			//jinak Plocha
			}
			
			
		}
		else if (serialBuffer[0] == 'F')															//Prijat obraz
		{
			i++;
			xmin = getNumber(serialBuffer+1);														//Ziskani pozice XA
			while(IS_NUMBER(serialBuffer[i]))														//posun na dalsi pozici
				i++;
			ymin = getNumber(serialBuffer+(i+1));													//Ziskani pozice YA
			i++;
			while(IS_NUMBER(serialBuffer[i]))														//POsun na dalsi pozici
				i++;
			xmax = xmin+getNumber(serialBuffer+(i+1));												//Ziskani sirky
			i++;
			while(IS_NUMBER(serialBuffer[i]))														//Posun na dalsi pozici
				i++;
			ymax = ymin+getNumber(serialBuffer+(i+1));												//ziskani vysky
			i++;
			while(IS_NUMBER(serialBuffer[i]))														//Posun
				i++;
			i+=2;
			unsigned short * tmpData = (unsigned short*)(serialBuffer+i);							//Pretypovani do short aby se urychlilo kopirovani bajtu
			int cntr = 0;
			for(int y = ymin; y < ymax-2; y++)														//Ulozeni pixelu na patricne pozice
			{
				for (int x = xmin; x < xmax; x++)
				{
					LCD_put_RAW_pix(x+DESKTOP_XA+x_offset,y+DESKTOP_YA+y_offset,/*serialBuffer+i*/tmpData[cntr++]);
					i+=2;
				}
			}
			clearBuffer(serialBuffer,1);															//Smazani prvni pozice v bufferu (= zneplatneni paketu)
			desktopScreen.UpdateObject(DESKTOP_MOUSE_LEFT,MSG_NO_BACKGROUND);						//Aktualizace patricnych objektu
			desktopScreen.UpdateObject(DESKTOP_MOUSE_RIGHT,MSG_NO_BACKGROUND);
			desktopScreen.UpdateObject(DESKTOP_KEYBOARD_BUTTON,MSG_NO_BACKGROUND);
			desktopScreen.UpdateObject(DESKTOP_SPECIALS_BUTTON,MSG_NO_BACKGROUND);
			desktopScreen.UpdateObject(DESKTOP_EXIT_BUTTON,MSG_NO_BACKGROUND);
            desktopScreen.UpdateObject(DESKTOP_SCROLL_BUTTON,MSG_NO_BACKGROUND);
			desktopScreen.UpdateObject(DESKTOP_TOUCHPAD,MSG_NO_BACKGROUND);
			SendSerialMessage(remoteConnection,(unsigned char*)"a\"\"a\r\n");						//Odeslani Acknowledge	
                               
		}
		else if (serialBuffer[0] == 'O')															//Prijeti paketu s offsetem
		{
			i++;													
			x_offset = getNumber(serialBuffer+1);													//Ziskani souradnice X
			while(IS_NUMBER(serialBuffer[i]))
				i++;
			y_offset = getNumber(serialBuffer+(i+1));												//Ziskani souradnice Y
			SendSerialMessage(remoteConnection,(unsigned char*)"a\"\"a\r\n");						//Odeslani Acknowledge
			clearBuffer(serialBuffer,1);															//Zneplatneni

		}
		else if (serialBuffer[0] == 'M')															//Prijata pozice mysi
		{
			//DebugOut("Mouse data ignored.\r\n");
            i++;
			int mouse_x = getNumber(serialBuffer+1);												//pozice X
			while(IS_NUMBER(serialBuffer[i]))
				i++;
			int mouse_y = getNumber(serialBuffer+(i+1));											//pozice Y
#ifndef PCSIM
			//Ulozeni pozice do ridiciho registru kurzoru - v PC dost tezko realizovatelne, proto neni v simulatoru akce k dispozici
            CRSR_XY = (((DESKTOP_YA+mouse_y+y_offset-16) << CRSR_XY_CrsrY_BIT) &CRSR_XY_CrsrY_MASK)  |((DESKTOP_XA+mouse_x+x_offset-16)&CRSR_XY_CrsrX_MASK);
#else
			DebugOut("Cursor moved to position [");
			DebugOut(int2char(mouse_x));
			DebugOut("; ");
			DebugOut(int2char(mouse_y));
			DebugOut("]\r\n");
#endif
			clearBuffer(serialBuffer,1);															//Zneplatneni paketu
			SendSerialMessage(remoteConnection,(unsigned char*)"a\"\"a\r\n");						//Odeslani Acknowledge
		}

		if (remoteConnectionEstablished == NO)														//Pokud nebylo pripojeni navazane, ted uz je
		{
			remoteConnectionEstablished = YES;
			SendTaskMessage(STATUS_BAR, &DEFAULT_MSG_REFRESH);
		}
		lastFrameReceived = GetTimeStamp();															//Ziskani TimeStamp

	}
	if (remoteConnectionEstablished == YES && GetElapsedTime(lastFrameReceived) > 5000)				//Pokud nebyla dlouho prijata zadna data
	{
		SendSerialMessage(remoteConnection,(unsigned char*)"a\"\"a\r\n");							//Poslat Acknowledge (hele, ja sem ale zivej a nemam co delat)
		lastFrameReceived = GetTimeStamp();															//Bereme timestamp
		remoteConnectionEstablished = NO;															//Spojeni asi neni aktivni
		SendTaskMessage(STATUS_BAR, &DEFAULT_MSG_REFRESH);      
	}
	else if (GetElapsedTime(lastFrameReceived) > 15000)												//Zkousime znovu, jestli nebylo spojeni obnoveno
	{
		SendSerialMessage(remoteConnection,(unsigned char*)"a\"\"a\r\n");
		lastFrameReceived = GetTimeStamp();
	}
	
}

TIME_STAMP lastMove;																				

/****************************************************************************
	Funkce pro zpracovani kliku a posunu. Puvodne mela podporovat kliknuti 
	a tahani po touchpadu.

	TODO: tohle byl pekny orisek, proto jsem se nakonec rozhodl, ze klikani 
	bude realizovano jinym tlacitkem. Asi je to lepsi... Ale kdyby se nahodou
	nekomu chtelo...:-)

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
void desktopProceedClick(void)
{
  unsigned char mouseBuffer[25];
  if (lastClickPosition.isFresh == YES)
  {

    if (GetElapsedTime(lastClickTime) < 20 /*|| CheckSerialSendComplete() == NO*/)		//Aby se funkce nespoustela moc casto
      return;
#ifndef PCSIM
	/****************************************************************************
		Nasledujici kus kodu se venuje implementaci klikani pres touchpad. 
		Jak se zda, chce to ale podstatne hlubsi zamysleni, na ktere neni cas.

	*****************************************************************************/
      if (wasReleasedQuery() == YES && hasMovedQuery() == NO)							
      {
        if (GetElapsedTime(lastMove) < 30)
        {
          lastClickPosition.isFresh = NO;
          return;
        }
        strcopy((unsigned char*)"m\"",mouseBuffer);
        str_append(mouseBuffer,(unsigned char*)"c,");
        str_append(mouseBuffer,(unsigned char*)"0,");
        str_append(mouseBuffer,(unsigned char*)"0\"m\r\n");
        //SendSerialMessage(remoteConnection,mouseBuffer);
        prevPosition.isFresh = NO;
        lastClickPosition.isFresh = NO;
      }
      else
      {
        if (prevPosition.isFresh == YES && hasMovedQuery() == YES)											//Pokud doslo k pohybu na plose
        {
          
          strcopy((unsigned char*)"m\"",mouseBuffer);														//Zacneme sestavovat informaci pro PC - jedna se o zpravu o mysi
          str_append(mouseBuffer,(unsigned char*)"R,");														//Relativni posun
          if (lastClickPosition.x-prevPosition.x < 0)														//pokud je posun zaporny
          {
            str_append(mouseBuffer,(unsigned char*)"-");													//pridame minus
          }
          str_append(mouseBuffer,(unsigned char*)int2char(ABS(lastClickPosition.x-prevPosition.x)));		//a na zaver pozici X
          str_append(mouseBuffer,(unsigned char*)",");														//Oddelovac
          if (lastClickPosition.y-prevPosition.y < 0)														//Posun v Y jestli je zaporny
          {
            str_append(mouseBuffer,(unsigned char*)"-");													
          }
          str_append(mouseBuffer,(unsigned char*)int2char(ABS(lastClickPosition.y-prevPosition.y)));		//vlozeni pozice Y
          str_append(mouseBuffer,(unsigned char*)"\"m\r\n");												//ukoncovaci cast paketu
          if (!(ABS(lastClickPosition.x-prevPosition.x) == 0 && ABS(lastClickPosition.y-prevPosition.y) == 0))
            SendSerialMessage(remoteConnection,mouseBuffer);
        }
        prevPosition.x = lastClickPosition.x;																//Ulozeni pozice
        prevPosition.y = lastClickPosition.y;
        prevPosition.isFresh = YES;
        lastMove = GetTimeStamp();													
      }
      if (wasReleasedQuery() == YES)
        prevPosition.isFresh = NO;
#endif

  }
}


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

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
void AppDesktop(void)
{
	switch (DesktopInternal.State)
	{
	case DESKTOP_NOT_INITIALIZED:
		break;
	case DESKTOP_INITIALIZE:
		DesktopInternal.State = DESKTOP_READY;									//Prechod na dalsi stav
		if (desktopInitialize() !=PASSED)										//POkud se nepodari inicializace
		{
			DebugOut("Desktop could not be initialized. Falling to error.\n");
			DesktopInternal.State = DESKTOP_ERROR;								//Spadni do chyby
			break;
		}
		DebugOut("Desktop initialized.\n");
		break;
	case DESKTOP_RESTART:
		DesktopInternal.Startup();												//Nezbytne ulohy pro start aplikace
#ifndef PCSIM
        if (remoteSSL == YES)													//Nastaveni timeoutu pro prijeti dat z UARTu
        {
            UartSetRecvTimeout(750);
        }
        else
            UartSetRecvTimeout(45);
#endif
		if (remoteControl == OS_DESKTOP)										//pokud je rezim plochy
		{
#ifndef PCSIM
			CRSR_enable(YES);													//Zapnout kurzor
#endif
		}
		DesktopInternal.State = DESKTOP_DRAW;									//Prechod na dalsi stav
		break;
	case DESKTOP_DRAW:
		if (freshStart == YES)													//pokud je aplikace startovana
			DesktopInternal.Screen->Draw();										//Vykresli ji
		else
			LCD_restore_videoRam();												//pokud jde o navrat od jinud, obnov obraz z pameti
		DesktopInternal.State = DESKTOP_ACTIVE;
		break;
	case DESKTOP_ACTIVE:
		DesktopInternal.ProceedClick();											//Zpracovani kliknuti
		ProceedSerialData();													//Zpracovani dat ze seriove linky
		desktopProceedClick();													//Zpracovani kliknuti na urovni aplikace
		BacklightRequest();														//pozadavek na podsvetleni - to nesmi pri behu aplikace zhasnout
		break;
	case DESKTOP_WAITING:
		switch(DesktopInternal.TryToResume())									//POkus o navrat z aplikace
		{
		case KEYBOARD:
			if(KeyboardBuffer.TextBuffer[0] == 0)								//Pokud nejsou v klavesnici data, konec
				break;
			strcopy((unsigned char*)"k\"P,",kbDataToSend);						//jinak vezmi hlavicku klavesnice
			str_append(kbDataToSend,KeyboardBuffer.TextBuffer);					//Pridej data klavesnice
			str_append(kbDataToSend,(unsigned char*)",0\"k\n");					//ukonceni paketu dat
			SendSerialMessage(remoteConnection,kbDataToSend);					//Odeslat data
			break;
		case DIALOG:
			if ((ANSWER)SendTaskMessage(DIALOG,&DEFAULT_MSG_GET_RESULT)==YES)		//Pokud je navrat z dialogu s vysledkem ANO
			{
				DesktopInternal.State = DESKTOP_STOP;								//Zahaj ukoncovaci procedury
				SendSerialMessage(remoteConnection,(unsigned char*)"!STOP!\r\n");	//Odesli PC pozadavek na ukonceni komunikace
			}
			else
				DesktopInternal.State = DESKTOP_DRAW;								//jinak provedeme prekresleni
			break;
		case SPECIALS:
			{
				clearBuffer(kbDataToSend,1000);										//Vymazani bufferu
				strcopy((unsigned char*)"k\"P,",kbDataToSend);						//opet klavesnicova hlavicka
				switch((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT))
				{
			
				case FN_ENTER:
					str_append(kbDataToSend,(unsigned char*)"{ENTER}");				//pridame info o stisknute klavese - Enter
					break;
				case FN_SPACE:
					str_append(kbDataToSend,(unsigned char*)" ");					//Mezera
					break;
				case FN_ESCAPE:
					str_append(kbDataToSend,(unsigned char*)"{ESC}");				//Escape
					break;
				case FN_DEL:
					str_append(kbDataToSend,(unsigned char*)"{DEL}");				//Delete
					break;
				case FN_BACKSPACE:
					str_append(kbDataToSend,(unsigned char*)"{BS}");				//Backspace
					break;
				case FN_TAB:
					str_append(kbDataToSend,(unsigned char*)"{TAB}");				//Tabulator
					break;
				case FN_HOME:
					str_append(kbDataToSend,(unsigned char*)"{HOME}");				//Home
					break;
				case FN_END:
					str_append(kbDataToSend,(unsigned char*)"{END}");				//End
					break;
				default:															//JInak rozhodneme jestli bylo CTRL+neco nebo ALT+neco
					if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>='A' && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<='Z')
					{       
						kbDataToSend[4] = '^';										//CTRL+neco
						kbDataToSend[5] = '(';
						str_append(kbDataToSend,KeyboardBuffer.TextBuffer);
						str_append(kbDataToSend,(unsigned char*)")");
					}else if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>='a' && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<='z')
					{
						kbDataToSend[4] = '%';										//ALT+neco
						kbDataToSend[5] = '(';
						str_append(kbDataToSend,KeyboardBuffer.TextBuffer);
						str_append(kbDataToSend,(unsigned char*)")");
					}else if ((SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)>=FN_F1 && (SPECIALS_OBJECTS)SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)<=FN_F12)
					{
						kbDataToSend[4] = '{';										//F+neco
						kbDataToSend[5] = 'F';
						kbDataToSend[6] = 0;
						str_append(kbDataToSend,(unsigned char*)int2char(SendTaskMessage(SPECIALS,&DEFAULT_MSG_GET_RESULT)));
						str_append(kbDataToSend,(unsigned char*)"}");
					}
                                        
					break;
				}
				str_append(kbDataToSend,(unsigned char*)",0\"k\n");					//Ukonceni paketu
				SendSerialMessage(remoteConnection,kbDataToSend);
				break;
			}
		case NONE:
			break;
		default:
			DebugOut("Returned to Desktop from unknown application.\n");
			break;
		}
		freshStart = NO;															//jedna se o navrat z aplikace
		break;
	case DESKTOP_READY:
		break;
	case DESKTOP_STOP:
		DesktopInternal.Stop();														//Ukoncovaci akce
		UartSetRecvTimeout(45);
                remoteConnectionEstablished = NO;											//Spojeni ukonceno	
#ifndef PCSIM
		CRSR_enable(NO);															//Zakazani kurzoru
#endif
		break;
	case DESKTOP_ERROR:
		break;
	default:
		break;
	}
}