/****************************************************************************
	Knihovna obsahuje jadro operacniho systemu, jenz je zakladem celeho zarizeni.

	OS je navrzen tak, aby bylo snadne jeho debuggovani v prostredi Visual Studio

	a bez jakychkoli zmen bezel i v prostredi CrossWorks.

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

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



TASK *TaskTable[MAX_TASKS];				//Tabulka uloh
unsigned char TaskCount = 0;			//Pocet uloh v tabulce

POSITION clickPosition = {0, 0, NO};	//Pozice kliknuti

/****************************************************************************
	Výchozí zpravy posilane jednotlivym uloham
*****************************************************************************/
MESSAGE DEFAULT_MSG_RUN = {RUN,0};									//Spustit aplikaci
MESSAGE DEFAULT_MSG_STOP = {STOP,0};								//Zastavit aplikaci
MESSAGE DEFAULT_MSG_INIT = {INIT,0};								//Inicializovat aplikaci
MESSAGE DEFAULT_MSG_GET_STATE = {GET_STATE,0};						//Zjistit stav aplikace
MESSAGE DEFAULT_MSG_WAIT = {WAIT,0};								//Nastavit aplikaci do stavu Wait
MESSAGE DEFAULT_MSG_NUMERIC_ONLY = {SET_NUMERIC_MODE,0};			//Nastavit numericky mod aplikaci
MESSAGE DEFAULT_MSG_REFRESH = {FORCE_REFRESH,0};					//Prekresleni okna aplikace
MESSAGE DEFAULT_MSG_GET_RESULT = {GET_RESULT,0};					//Ziskani vysledku po ukonceni aplikace
MESSAGE DEFAULT_MSG_APP_CLICK = {APP_CLICK,(char*)&clickPosition};	//Odeslat aplikaci o udalosti kliknuti

TRect DefaultRect = {0,0,0,0};

/****************************************************************************
	Funkce pro inicializaci pole úloh

	Vstup: 
		není

	Výstup:
		není

*****************************************************************************/
void initTasks(void)
{
	int i = 0;
	for (i = 0; i< MAX_TASKS; i++)
		TaskTable[i] = 0;
}


/****************************************************************************
	Vytvoreni ulohy v operacinim systemu

	Vstup: 
		ptr:		Callback aplikace (hlavni funkce)
		task_name:	Jmeno aplikace
		prior:		Priorita aplikace
		stat:		stav aplikace
		Type:		Rezim spousteni aplikace
		msg:		Ukazatel na schranku aplikace (mailbox)

	Výstup:
		RESULT:		Vysledek operace

*****************************************************************************/
RESULT TaskCreate(	void(*ptr)(void),
					TASK_NAME task_name,
					PRIORITY prior, 
					STATE stat, 
					TASK_TYPE Type, 
					RESULT(*msgBox)(MESSAGE *msg))
{
	//Vytvoreni nove struktury s aplikaci
	TaskTable[TaskCount] = (TASK*)calloc(1,sizeof(TASK));
	if (TaskTable[TaskCount] == 0)
		return FAILED;
	//Inicializace vytvorene struktury
	TaskTable[TaskCount]->task = ptr;
	TaskTable[TaskCount]->priority = prior;
	TaskTable[TaskCount]->state = stat;
	TaskTable[TaskCount]->remaining = (unsigned char)prior;
	TaskTable[TaskCount]->name = task_name;
	TaskTable[TaskCount]->type = Type;
	TaskTable[TaskCount]->msgBox = msgBox;
	TaskTable[TaskCount]->LCD_area = 0;
	TaskCount++;
	return PASSED;
}




/****************************************************************************
	Lokalizace ulohy v tabulce uloh

	Vstup: 
		task:		ID aplikace

	Výstup:
		int:		index ulohy v tabulce

*****************************************************************************/
int taskFind(TASK_NAME task)
{
	int taskNum = 0;
	char found = 0;

	//pro vsechny ulohy v tabulce proved
	for (taskNum = 0; taskNum < TaskCount; taskNum++)
	{
		//pokud odpovida ID, ukonci vyhledavani
		if (TaskTable[taskNum]->name == task)
		{
			found = 1;
			break;
		}
	}
	if (found == 0)
		return -1;
	else
		return taskNum;
}

/****************************************************************************
	Inicializace ukazatele na interni stav aplikace (ulohy)

	Vstup: 
		Name:		ID ulohy
		inState:	Interni stav ulohy

	Výstup:
		RESULT:		info o uspesnosti operace

*****************************************************************************/
RESULT TaskFillState(TASK_NAME Name, char* inState)
{
	int item = taskFind(Name);
	if (item < 0)
		return FAILED;
	TaskTable[item]->internalState = inState;
	return PASSED;
}

/****************************************************************************
	Vraci interni stav aplikace

	Vstup: 
		Name:		ID ulohy

	Výstup:
		char:		Stav ulohy

*****************************************************************************/
char TaskGetState(TASK_NAME Name)
{
	int item = taskFind(Name);
	if (item < 0)
		return -1;
	else
		return *TaskTable[item]->internalState;
}

/****************************************************************************
	Vymaze ulohu z tabulky uloh

	Vstup: 
		Name:		ID ulohy

	Výstup:
		RESULT:		Uspesnost operace

*****************************************************************************/
RESULT TaskDelete(TASK_NAME Name)
{
	int taskNum = 0;
	char found = 0;
	//Vyhledani ulohy v tabulce uloh
	for (taskNum = 0; taskNum < TaskCount; taskNum++)
	{
		if (TaskTable[taskNum]->name == Name)
		{
			found = 1;
			break;
		}
	}
	if (found == 0)
		return FAILED;
	//vymazani ulohy
	free(TaskTable[taskNum]);
	//Preskladani uloh v tabulce (odstraneni prazdneho mista)
	for (taskNum; taskNum < TaskCount-1; taskNum++)
	{
		TaskTable[taskNum] = TaskTable[1+taskNum];
	}
	TaskTable[taskNum] = 0;
	TaskCount--;
	
	return PASSED;
}

/****************************************************************************
	Nastavi prioritu ulohy v OS

	Vstup: 
		name:		ID ulohy
		prior:		priorita ulohy

	Výstup:
		RESULT:		uspesnost operace

*****************************************************************************/
RESULT SetTaskPrioriry(TASK_NAME Name, PRIORITY prior)
{
  int taskNum = 0;
  char found = 0;
  //Vyhledani ulohy v tabulce
  for (taskNum = 0; taskNum < TaskCount; taskNum++)
  {
          if (TaskTable[taskNum]->name == Name)
          {
                  found = 1;
                  break;
          }
  }
  if (found == 0)
          return FAILED;
  //nastaveni priority
  TaskTable[taskNum]->priority = prior;
  return PASSED;
  
}

/****************************************************************************
	Logika pro spusteni ulohy

	Vstup: 
		index:		ID ulohy

	Výstup:
		není

*****************************************************************************/
void TaskRun(unsigned char index)
{
	TASK* thisTask = TaskTable[index];
	//Pokud je stav ulohy STOPPED, konec
	if (thisTask->state == STOPPED)
		return;
	//dekrementace pocitadla pro spusteni
	if(--thisTask->remaining == 0)
	{
		//Pokud je 0, proved spusteni callbacku ulohy
		thisTask->task();
		//Pokud se ma uloha spustit jednou, vymaz ji
		if (thisTask->type == RUN_ONCE)
		{
			TaskDelete(thisTask->name);
		}
		else
		{
			//jinak reinicializuj pocitadlo
			thisTask->remaining = (unsigned char)thisTask->priority;
		}
	}
}

/****************************************************************************
	Smycka OS

	Vstup: 
		není

	Výstup:
		není

*****************************************************************************/
void RunOS(void)
{
	unsigned char currentTask = 0;
	//Pokud neexistuje zadna uloha, ukonci OS
	if (TaskCount == 0 && TimerCount == 0)
		return;
	while(TaskCount>0)
	{	
		//Pro kazdou ulohu proved pokus o spusteni
		for(currentTask = 0; currentTask < TaskCount; currentTask++)
		{
			TaskRun(currentTask);
		}
		//Pro kazdy existujici timer proved kontrolu, jestli se ma spustit
		for(currentTask = 0; currentTask < TimerCount; currentTask++)
		{
			TimerRun(currentTask);
		}
		//Pokud bylo prijato kliknuti, proved jeho zpracovani
		if (clickPosition.isFresh == YES)
		{
			ProceedClickEvent();
			clickPosition.isFresh = NO;
		}
	}
}


/****************************************************************************
	Odesli uloze zpravu

	Vstup: 
		task:		ID ulohy
		message:	zprava

	Výstup:
		RESULT:		uspesnost

*****************************************************************************/
RESULT SendTaskMessage(TASK_NAME task, MESSAGE *message)
{
	int taskNum = 0;
	char found = 0;
	//vyhledani ulohy
	for (taskNum = 0; taskNum < TaskCount; taskNum++)
	{
		if (TaskTable[taskNum]->name == task)
		{
			found = 1;
			break;
		}
	}
	if (found == 0)
		return FAILED;
	//pokud nema uloha definovanou schranku, konec
	if (TaskTable[taskNum]->msgBox == 0)
	{
		return FAILED;
	}
	//posli zpravu
	return TaskTable[taskNum]->msgBox(message);
}

//makro - obsahuje obdelnik zadany bod?
#define isInside(rect,X,Y) (X>=rect->xA && X <= rect->xC && Y >= rect->yA && Y <= rect->yC)

/****************************************************************************
	Vraci info, jestli se dva obdelniky prekryvaji (pokud ano, ma jeden z 
	nich bod uvnitr druheho)

	Vstup: 
		r1:			prvni obdelnik
		r2:			druhy obdelnik

	Výstup:
		RESULT:		vysledek

*****************************************************************************/
RESULT isOverlap(TRect * r1, TRect *r2)
{
	if (isInside(r1,r2->xA,r2->yA) || isInside(r1,r2->xA,r2->yC) || isInside(r1,r2->xC,r2->yA) || isInside(r1,r2->xC,r2->yC) ||
		isInside(r2,r1->xA,r1->yA) || isInside(r2,r1->xA,r1->yC) || isInside(r2,r1->xC,r1->yA) || isInside(r2,r1->xC,r1->yC))
	{
		return PASSED;
	}
	return FAILED;
}


/****************************************************************************
	Registrace graficke oblasti na displeji pro udalost kliknuti

	Vstup: 
		task:		ID ulohy
		rect:		pozadovana oblast

	Výstup:
		RESULT		vysledek

*****************************************************************************/
RESULT RegisterGraphicArea(TASK_NAME task, TRect * rect)
{
	int i = 0;
	//vyhledani ulohy
	int taskNum = taskFind(task);

	if (taskNum < 0)
	{
		DebugOut("Graphic area could not be registered, process not found.");
		return FAILED;
	}

	//kontrola, jestli oblast koliduje s jinou ulohou
	for (i = 0; i < TaskCount; i++)
	{
		if (TaskTable[i]->LCD_area == 0)
			continue;
		if (isOverlap(TaskTable[i]->LCD_area,rect)==PASSED  && i != taskNum)
		{	
			DebugOut("Graphic area could not be registered. Positive overlap detected.\n");
			return FAILED;
		}
	}
	//Proved registraci oblasti
	TaskTable[taskNum]->LCD_area = rect;
	return PASSED;
}


/****************************************************************************
	Odregistruje oblast displeje z OS

	Vstup: 
		task:		ID ulohy

	Výstup:
		RESULT:		vysledek

*****************************************************************************/
RESULT UnregisterGraphicArea(TASK_NAME task)
{
	int taskNum = -1;
	//najdi ulohu
	taskNum = taskFind(task);

	if (taskNum < 0)
	{
		DebugOut("Graphic area could not be unregistered, process not found.");
		return FAILED;
	}
	else
	{
		//zrus asociaci
		TaskTable[taskNum]->LCD_area = 0;
		DebugOut("Graphic area unregistered.\n");
		return PASSED;
	}
}


/****************************************************************************
	Zpracuje udalost kliknuti:
		1. vyhleda ulohu, ktere patri kliknuti
		2. odesle zpravu o kliknuti

	Vstup: 
		neni

	Výstup:
		není

*****************************************************************************/
RESULT ProceedClickEvent(void)
{
	int i = 0;
	//vyhledani ulohy
	for (i = 0; i < TaskCount; i++)
	{
		if (TaskTable[i]->LCD_area == 0)
			continue;
		if (isInside(TaskTable[i]->LCD_area,clickPosition.x, clickPosition.y))
		{
			//odeslani zpravy
			SendTaskMessage(TaskTable[i]->name,&DEFAULT_MSG_APP_CLICK);
			return PASSED;
		}
	}
	DebugOut("Could not find receiver of click.\n");
	return FAILED;
}

