/****************************************************************************
	Knihovna obsahuje tridu pro spravu aplikace v OS, ktery je pouzit v teto
	diplomove praci.

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

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

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

#include "Applications.h"


/****************************************************************************
	Metoda pro registraci oblasti dane aplikace

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
RESULT TApplicationInternal::RegisterArea(void)
{
	return RegisterGraphicArea(Name,&Area);
}


/****************************************************************************
	Metoda pro odregistraci oblasti dane aplikace

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
RESULT TApplicationInternal::UnregisterArea(void)
{
	return UnregisterGraphicArea(Name);
}

/****************************************************************************
	Inicializace kontrolni struktury aplikace

	Vstup: 
		name:				jmeno aplikace
		xa, ya,				bod A obdelniku aplikace
		xc, yc				bod C obdelniku aplikace
		AppScreen:			Obrazovka aplikace
		ClickTRanslator:	prekladac kliknuti pro aplikaaci na id objektu
		useStatusBar:		flag, jestli aplikace pouziva StatusBar

	Výstup:
		neni

*****************************************************************************/
void TApplicationInternal::Init(TASK_NAME name, int xa, int ya, int xc, int yc, TScreen* AppScreen, int(*ClickTranslator)(POSITION*), ANSWER useStatusBar)
{
	//State = M_TASK_NOT_INITIALIZED; 
	Area.xA = xa;
	Area.xC = xc;
	Area.yA = ya;
	Area.yC = yc;
	ClickPosition.isFresh = NO;	
	Name = name;
	Cursor.active = NO;
	Cursor.blink = NO;
	Cursor.changed = YES;
	Screen = AppScreen;
	WaitForTask = NONE;
	StatusBar = useStatusBar;
	CursorStamp = GetTimeStamp();
	dialogShown = NO;
	this->translateClickPosition = ClickTranslator;
	TaskFillState(name,&this->State);
}


/****************************************************************************
	Metoda pro nastaveni chovani kurzoru

	Vstup: 
		active:			je kurzor aktivni
		blink:			blika kurzor

	Výstup:
		neni

*****************************************************************************/
void TApplicationInternal::SetCursor(ANSWER active, ANSWER blink)
{
	Cursor.active = active;
	Cursor.blink = blink;
	Cursor.changed = YES;
}

/****************************************************************************
	Metoda provede nezbytne akce pro spusteni aplikace

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
RESULT TApplicationInternal::Startup(void)
{
	//Registrace oblasti
	if (this->RegisterArea() != PASSED)
	{
		//v pripade neuspechu vyhlasi aplikace chybu
		this->State = M_TASK_FAILED;
		return FAILED;
	}
    //Nastaveni priority aplikace
	SetTaskPrioriry(Name,MOST);

	//Spusteni status baru
	if (this->StatusBar == YES)
	{
		if (SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_RUN)!=PASSED)
		{
			this->State = M_TASK_FAILED;
			return FAILED;
		}
	}
	
	return PASSED;
}

/****************************************************************************
	Metoda provede nezbytne ukony pri ukonceni aplikace

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void TApplicationInternal::Stop(void)
{
	//odregistrovani graficke oblasti
	this->UnregisterArea();
	this->State = M_TASK_READY;
	//Stavovy panel
	if (this->StatusBar == YES)
	{
		SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_STOP);
	}
	//Snizeni priority aplikace
    SetTaskPrioriry(Name,LEAST);
	//Aktualizace stavoveho pruhu
	StatusBarTextUpdate(0);
	return;
}


/****************************************************************************
	Metoda kontroluje, jestli aplikace, ktera byla spustena touto aplikaci
	byla ukoncena. Pokud ano, nastavi aplikaci do stavu M_TASK_RUNNING

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
TASK_NAME TApplicationInternal::TryToResume(void)
{
	TASK_NAME tmp = NONE;
	//kontrola, jestli byla aplikace ukoncena
	if (SendTaskMessage(this->WaitForTask,&DEFAULT_MSG_GET_STATE)==M_TASK_READY)
	{
		//spusteni materskeho tasku
		this->State = M_TASK_RESTART;
		if (this->RegisterArea()==FAILED)
		{
			this->State = M_TASK_FAILED;
			return NONE;
		}
		//vraci aplikaci, ze ktere se program vratil
		tmp = this->WaitForTask;
		this->WaitForTask = NONE;
		return tmp;

	}
	return NONE;
}

/****************************************************************************
	Zpracovava kliknuti, ktera aplikace prijala od OS

	Vstup: 
		neni

	Výstup:
		int:		index objektu

*****************************************************************************/
int TApplicationInternal::ProceedClick(void)
{
	int index = UNDF;
	//pokud bylo prijato kliknuti
	if (this->ClickPosition.isFresh == YES)
	{
		this->ClickPosition.isFresh = NO;
		index = UNDF;
		//pokud neni nastaven externi prekladac kliknuti
		if (translateClickPosition == 0)
		{
			DebugOut("Click translator not defined.\n");
			//vyhledej podle souradnic objekt
			for (int i = 0; i < this->Screen->object_count; i++)
			{
				if (this->Screen->objects[i].state == OBJECT_DISABLED || this->Screen->objects[i].type == BACKGROUND)
				{
					continue;
				}
				if (this->Screen->objects[i].x > this->ClickPosition.x || this->Screen->objects[i].y > this->ClickPosition.y)
				{
					continue;
				}
				if (this->Screen->objects[i].x + this->Screen->objects[i].params->width < this->ClickPosition.x)
					continue;
				if (this->Screen->objects[i].y + this->Screen->objects[i].params->height > this->ClickPosition.y)
				{
					index = i;
					break;
				}
			}
		}
		else
		{	
			//jinak pouzij prekladac kliknuti
			index = translateClickPosition(&this->ClickPosition);
		}
		if (index != UNDF )
		{
			//Pokud byl nalezen objekt, zavolej jeho callback
			if (this->Screen->objects[index].object_callback!=0)
				this->Screen->objects[index].object_callback(&this->Screen->objects[index],MSG_CLICK);
		}
	}
	return index;
}

/****************************************************************************
	Splikace se pokusi spustit jinou aplikaci

	Vstup: 
		task:		ID procesu aplikace

	Výstup:
		neni

*****************************************************************************/
RESULT TApplicationInternal::RunApplication(TASK_NAME task)
{
	//Pokud byla aplikace uspesne spustena
	if (SendTaskMessage(task,&DEFAULT_MSG_RUN) == PASSED)
	{
		//pozastav materskou aplikaci
		this->WaitForTask = task;
		this->State = M_TASK_WAITING;
		this->UnregisterArea();
		if (this->StatusBar == YES)
			SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_STOP);
		return PASSED;
	}
	else
	{
		//jinak nedelej nic
		return FAILED;
	}
}

/****************************************************************************
	ridi chovani kurzoru

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void TApplicationInternal::ProceedCursor(void)
{
	//pokud se kurzor nezmenil a nema blikat, nedelej nic
	if (Cursor.changed == NO && Cursor.blink == NO)
	{
		return;
	}
	Cursor.changed = NO;
	//pokud ma kurzor blikat
	if (Cursor.blink == YES)
	{
		//pokud uplynul cas
		if (GetElapsedTime(CursorStamp)>2000)
		{
			//prepni kurzor
			CursorStamp = GetTimeStamp();
			SwitchCursor();
		}
		return;
	}
	else
	{
		//vynuceni chovani kurzoru
		ForceCursor(Cursor.active);
	}
}

/****************************************************************************
	Metoda pro ziskani odpovedi od uzivatele pomoci dialogu

	Vstup: 
		text:		text dialogoveho okna

	Výstup:
		neni

*****************************************************************************/
ANSWER TApplicationInternal::GetAnswer(char *text)
{
	TDialogCfg cfg = {QUESTION,COUNTDOWN_NONE,100,(unsigned char*)text,30};
	MESSAGE dialogMessage = {RUN,&cfg};
	//pokud neni zobrazen dialog
	if (this->dialogShown == NO)
	{
		//zobraz jej
		this->oldState = this->State;
		if (SendTaskMessage(DIALOG,&dialogMessage) == FAILED)
		{
			this->State = M_TASK_FAILED;
			return ANSWER_ERROR;
		}
		this->State = M_TASK_DIALOG_WAITING;
		this->dialogShown = YES;
		this->UnregisterArea();
	
		if (this->StatusBar == YES)
		{
			SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_STOP);
		}


		return NOT_ANSWERED;
	}
	else
	{
		//jinak spust aplikaci
		this->Startup();
		dialogShown = NO;
		return (ANSWER)SendTaskMessage(DIALOG, &DEFAULT_MSG_GET_RESULT);
	}
}

/****************************************************************************
	Ceka na ukonceni dialogu

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void TApplicationInternal::WaitForDialogStop(void)
{
	if (SendTaskMessage(DIALOG,&DEFAULT_MSG_GET_STATE) == M_TASK_READY)
	{
		this->Startup();
		this->State = this->oldState;
	}
}
