/****************************************************************************
	Aplikace Dialog pro zobrazovani jednoduchych oznameni uzivateli a 
	ziskavani odpovedi typu ANO/NE.

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

#include "OS.h"
#include "GRAPHICS.h"
#include "Applications.h"
#include "GLCD.h"

unsigned char DialogBuffer[1000] = "";													//Textovy buffer pro text zobrazeny uzivateli

FONT DialogScreenFont = {RGB_CYAN,FONT_SMALL,RGB_DARK_GRAY};							//Definice fontu

TScreen dialogScreen;																	//Definice obrazovky aplikace

TScreenObject dialogScreenObjects[DIALOG_OBJECT_COUNT];									//Objekty aplikace

static TApplicationInternal DialogInternal;												//Ridici objekt aplikace

TRect countDownPosition = {DIALOG_XC-35,DIALOG_YC-65,DIALOG_XC-2,DIALOG_YC-47};			//Oblast pro odpocet

/****************************************************************************
	Parametry objektu aplikace

*****************************************************************************/
TScreenObjectParams DialogMainShapeParams = {DIALOG_XC-DIALOG_XA,DIALOG_YC-DIALOG_YA,&DialogScreenFont};
TScreenObjectParams DialogTextBoxParams = {DIALOG_XC-DIALOG_XA,DIALOG_YC-DIALOG_YA-45,&DialogScreenFont};

int lastChar = 0;																		//Pomocna promenna pro rolovani textu
TIME_STAMP lastRefresh;																	//Okamzik posledniho refreshe
TIME_STAMP timeOfStart;																	//Okamzik startu aplikace
ANSWER LastAnswer = NOT_ANSWERED;														//Ziskana odpoved

TDialogCfg Config = {INFO,COUNTDOWN_NONE,0,DialogBuffer,3};;							//Lokalni konfiguracni struktura


/****************************************************************************
	Funkce pro kresleni tvaru tlacitka

	Vstup: 
		msg:			zprava aplikaci

	Vystup
		RESULT:			vysledek operace

*****************************************************************************/
RESULT DWMsgBox(MESSAGE * msg)						
{
	POSITION* tmpPosition = 0;
	switch (msg->msg)
	{
	case CONFIG:
		if (DialogInternal.State == DIALOG_READY)						//Pokud je aplikace zinicializovana
		{
			TDialogCfg *tmp = (TDialogCfg*)msg->data;					//prijmi konfiguracni data
			Config.type = tmp->type;						
			strcopy(tmp->text,Config.text);								//Uloz je
			Config.timeout_type = tmp->timeout_type;					//proved konfiguraci
			Config.timeout = tmp->timeout-1;
			Config.scroll_time = tmp->scroll_time;
			return PASSED;
		}
		else return FAILED;
		break;
	case RUN:
		DebugOut("Dialog RUN command received.\n");
		if (DialogInternal.State == DIALOG_READY)						//pokud je aplikace zinicializovana
		{
			LastAnswer = NOT_ANSWERED;									//Vymaz posledni odpoved
			DialogInternal.State = DIALOG_PROCEED_CONFIG;				//Prejdi do stavu zpracovani konfigurace
			if (msg->data == 0)											//POkud nebyla prijata konfig. data, uz nekdy byla prijata
			{
				return PASSED;
			}
			else
			{
				TDialogCfg *tmp = (TDialogCfg*)msg->data;				//Jinak proved konfiguraci s aktualnimi daty
				Config.type = tmp->type;
				strcopy(tmp->text,Config.text);
				Config.timeout_type = tmp->timeout_type;
				Config.timeout = tmp->timeout-1;
				Config.scroll_time = tmp->scroll_time;
				return PASSED;
			}
		}
		DebugOut("Dialog could not be run, not configured.");
		return FAILED;
		break;
	case INIT:
		if (DialogInternal.State == DIALOG_NOT_INITIALIZED)			//POkud neni aplikace zinicializovana
		{
			DebugOut("Dialog INIT command received.\n");
			DialogInternal.State = DIALOG_INITIALIZE;				//Proved inicializaci
			return PASSED;	
		}
		break;
	case GET_STATE:
		//DebugOut("Dialog GET_STATE command received.\n");
		return (RESULT)DialogInternal.State;						//Vraci interni stav
		break;
	case APP_CLICK:
		DialogInternal.ClickPosition.isFresh = YES;					//prijat klik pro aplikaci
		tmpPosition = (POSITION*)msg->data;							//Je ulozen pro zpracovani
		DialogInternal.ClickPosition.x = tmpPosition->x;
		DialogInternal.ClickPosition.y = tmpPosition->y;
		DebugOut("Dialog click received.\n");
		return PASSED;
		break;
	case GET_RESULT:
		return (RESULT)LastAnswer;									//Vraci posledni odpoved
		break;
	default:
		break;
		
	}
	return FAILED;
}

/****************************************************************************
	Vykresleni dialogove zpravy pripadne cisla odpoctu

	Vstup: 
		obj:			instance objektu
		message:		parametr volani

	Vystup
		neni

*****************************************************************************/
void DrawDialogTextBox(TScreenObject* obj ,OBJECT_MESSAGE message)
{
	int length = get_length(Config.text);
	switch (message)
	{
	case MSG_COMPLETE:
		DrawTextBoxShape(obj,message);												//Vykresli tvar aplikace
		LCD_Goto_XY(obj->x+5, obj->y+8);											//Presun se na pozici pro text
		lastChar += LCD_cprintf(lastChar,Config.text,-1);							//Vytiskni cast textu, ktera se vejde do ROI
		if (lastChar >=length)														//Pokud je vytisknut konec textu, brat se na zacatek
		lastChar = 0;
	case MSG_LOWER_RIGHT:
		if (Config.timeout_type == COUNTDOWN_VISIBLE)								//POzadavek na tisk dolniho rohu s odpoctem casu
		{	
			LCD_Set_ROI(&countDownPosition);										//Nastaveni ROI
			LCD_Set_Font(&DialogScreenFont);										//Nastaveni fontu
			LCD_Goto_XY(countDownPosition.xA,countDownPosition.yA);					//nastaveni pozice tisku
			//Tisk zbyvajiciho casu	
			LCD_printf((unsigned char*)int2char(integerDiv(Config.timeout-GetElapsedTime(timeOfStart),10)));
			LCD_printf((unsigned char*)"s");
		}

		break;
	}

}

/****************************************************************************
	Funkce odpovedi tlacitek na klik

	Vstup: 
		obj:			instance objektu
		message:			parametr volani

	Vystup
		neni

*****************************************************************************/
void DialogButtonCallback(TScreenObject* obj ,OBJECT_MESSAGE message)
{
#ifdef FIX_ALL_WARNINGS
	message;
#endif
	//Podle ID objektu je ulozena odpoved
	switch(obj->id)
	{
	case DIALOG_BUTTON_OK:
		LastAnswer = YES;
		break;
	case DIALOG_BUTTON_CANCEL:
		LastAnswer = NO;
		break;
	case DIALOG_BUTTON_INFO_OK:
		LastAnswer = I_KNOW;
		break;
	default:
		DebugOut("Dialog invalid answer generated.\n");
		LastAnswer = NOT_ANSWERED;
		break;
	}
	
	DialogInternal.State = DIALOG_STOP;		//Aplikace je ukoncena
}


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

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
RESULT dialogInitialize(void)
{
	dialogScreen.Init(DIALOG_OBJECT_COUNT,dialogScreenObjects,&DialogScreenFont,0);					//Inicializace okna
	DialogInternal.Init(DIALOG,DIALOG_XA,DIALOG_YA,DIALOG_XC,DIALOG_YC,&dialogScreen,0,NO);			//Inicializace ridici struktury
		if (DialogInternal.Screen == 0)
		{
			return FAILED;
		}
		
		/****************************************************************************
			Inicializace objektu

		*****************************************************************************/
		DialogInternal.Screen->objects[DIALOG_MAIN_SHAPE].Init(	DIALOG_XA,
															DIALOG_YA,
															BACKGROUND,
															DIALOG_MAIN_SHAPE,
															0,
															OBJECT_ENABLED,
															&DialogMainShapeParams,
															0,
															&DrawTextBoxShadowed);

		DialogInternal.Screen->objects[DIALOG_BUTTON_OK].Init(	DIALOG_XA+DIALOG_OK_LEFT,
															DIALOG_YA + DIALOG_OK_TOP,
															BUTTON,
															DIALOG_BUTTON_OK,
															STR_OK,
															OBJECT_ENABLED,
															&PARAMS_BTN_OK,
															DialogButtonCallback,
															DrawButton);

		DialogInternal.Screen->objects[DIALOG_BUTTON_CANCEL].Init(DIALOG_XA+DIALOG_CANCEL_LEFT,
															DIALOG_YA + DIALOG_CANCEL_TOP,
															BUTTON,
															DIALOG_BUTTON_CANCEL,
															STR_CANCEL,
															OBJECT_ENABLED,
															&PARAMS_BTN_CANCEL,
															DialogButtonCallback,
															DrawButton);

		DialogInternal.Screen->objects[DIALOG_BUTTON_INFO_OK].Init(DIALOG_XA+DIALOG_INFO_OK_LEFT,
															DIALOG_YA + DIALOG_INFO_OK_TOP,
															BUTTON,
															DIALOG_BUTTON_INFO_OK,
															STR_OK,
															OBJECT_ENABLED,
															&PARAMS_BTN_INFO_OK,
															&DialogButtonCallback,
															&DrawButton);

		DialogInternal.Screen->objects[DIALOG_TEXT_BOX].Init(		DIALOG_XA,
															DIALOG_YA,
															TEXT_BOX,
															DIALOG_TEXT_BOX,
															(unsigned char*)"",
															OBJECT_ENABLED,
															&DialogTextBoxParams,
															0,
															&DrawDialogTextBox);
	return PASSED;
}


/****************************************************************************
	Zpracovani casovanych udalosti aplikace jako jsou automaticke posuny apod.

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
void ProceedSwitch(void)
{

	if (GetElapsedTime(lastRefresh) > Config.scroll_time)											//Pokud nastal okamzik prepnuti
	{																								//Prekresli text
		DialogInternal.Screen->objects[DIALOG_TEXT_BOX].draw(&DialogInternal.Screen->objects[DIALOG_TEXT_BOX],MSG_COMPLETE);
		lastRefresh = GetTimeStamp();
	}
	if (Config.timeout_type > COUNTDOWN_NONE)														//Pokud ma bezet odpocet automaticke odpovedu
	{
		if (GetElapsedTime(timeOfStart) > Config.timeout)											//Kontroluj interval
		{
			DebugOut("Dialog timeout elapsed, stopping application.");
			DialogInternal.State = DIALOG_STOP;														//Ukonci aplikaci
		}
	}
	if (Config.timeout_type == COUNTDOWN_VISIBLE)													//pokud ma byt odpocet videt, aktualizuj jej pravidelne
	{
		if ((GetElapsedTime(timeOfStart)-Config.timeout)%10==0)
		{
			DialogInternal.Screen->objects[DIALOG_TEXT_BOX].draw(&DialogInternal.Screen->objects[DIALOG_TEXT_BOX],MSG_LOWER_RIGHT);
		}
	}
}



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

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
void AppDialog(void)
{
	switch (DialogInternal.State)
	{
	case DIALOG_NOT_INITIALIZED:
		break;
	case DIALOG_INITIALIZE:
		if (dialogInitialize() !=PASSED)										//Inicializuj aplikaci
		{
			DebugOut("Dialog could not be initialized. Falling to error.\n");
			DialogInternal.State = DIALOG_FAILED;								//V pripade selhani nahlas chybu
			break;
		}
		DebugOut("Dialog initialized.\n");
		DialogInternal.State = DIALOG_READY;									//JInak prejdi do pripraveneho stavu
		break;
	case DIALOG_RESTART:
		DialogInternal.Startup();												//Proved nezbytne ulohy pred startem
		LastAnswer = NOT_ANSWERED;												//REsetuj posledni odpoved
		DialogInternal.State = DIALOG_DRAW;										//Priprav se na kresleni
		break;
	case DIALOG_DRAW:
		DialogInternal.Screen->Draw();											//Vykresli applikaci
		lastRefresh = GetTimeStamp();
		timeOfStart = GetTimeStamp();
		DialogInternal.State = DIALOG_ACTIVE;									//Prejdi do aktivniho stavu
		break;
	case DIALOG_ACTIVE:
		//ProceedSwitch();
		DialogInternal.ProceedClick();											//Zpracuj kliknuti
		break;
	case DIALOG_PROCEED_CONFIG:
		switch (Config.type)													//POdle konfigurace vyber patricne objekty
		{
		case INFO:
			DialogInternal.Screen->objects[DIALOG_BUTTON_OK].state = OBJECT_DISABLED;
			DialogInternal.Screen->objects[DIALOG_BUTTON_CANCEL].state = OBJECT_DISABLED;
			DialogInternal.Screen->objects[DIALOG_BUTTON_INFO_OK].state = OBJECT_ENABLED;
			break;
		case QUESTION:
			DialogInternal.Screen->objects[DIALOG_BUTTON_OK].state = OBJECT_ENABLED;
			DialogInternal.Screen->objects[DIALOG_BUTTON_CANCEL].state = OBJECT_ENABLED;
			DialogInternal.Screen->objects[DIALOG_BUTTON_INFO_OK].state = OBJECT_DISABLED;
			break;
		default:
			DialogInternal.State = DIALOG_FAILED;								//Pokud neni konfigurace znama, selzi
			break;
		}
		DialogInternal.State = DIALOG_RESTART;
		break;
	case DIALOG_READY:
		break;
	case DIALOG_STOP:
		DialogInternal.Stop();													//Korektni ukonceni...
		break;
	case DIALOG_FAILED:
		break;
	default:
		break;
	}
}