/****************************************************************************
	Aplikace Hlavni menu

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


/****************************************************************************
	Definice globalnich fontu

*****************************************************************************/
FONT MainMenuScreenFont = {RGB_GREEN,FONT_SMALL,RGB_DARK_BLUE};
FONT MainMenuButtonFont = {RGB_CYAN,FONT_SMALL,RGB_DARK_GRAY};
FONT MainMenuSpecialObjectFont = {RGB_RED,FONT_SMALL,RGB_DARK_GRAY};


TMainMenuObject *HigherMenus[MAIN_MENU_DEPTH];							//Seznam nadrazenych urovni menu
char CurrentMenuDepth = 0;												//Aktualni uroven zanoreni
TScreen mainMenuScreen;													//Obrazovka s polozkami menu
TScreen MainMenuCommons;												//Obrazovka s ovladacimi prvky
TScreenObject MainMenuCommonObjects[MAIN_MENU_SPECIAL_OBJECTS_COUNT];	//Pole s ovladacimi prvky
TApplicationInternal MainMenuInternal;									//Ridici objekt aplikace

/****************************************************************************
	Definice objektu menu

*****************************************************************************/
TMainMenuObject MenuOptionsObjects[MENU_OPTIONS_OBJECTS_COUNT];
TMainMenuObject MenuHardwareObjects[MENU_HARDWARE_OBJECTS_COUNT];
TMainMenuObject MainMenuObjects[MAIN_MENU_OBJECTS_COUNT];

/****************************************************************************
	Definice grafickych objektu menu

*****************************************************************************/
TScreenObject MenuOptionsButtons[MENU_OPTIONS_OBJECTS_COUNT];
TScreenObject MenuHardwareButtons[MENU_HARDWARE_OBJECTS_COUNT];
TScreenObject MainMenuButtons[MAIN_MENU_OBJECTS_COUNT];
TMainMenuObject MenuStructure;
TMainMenuObject * CurrentMenuRoot = &MenuStructure;

/****************************************************************************
	Definice parametru menu

*****************************************************************************/
TScreenObjectParams MainMenuButtonParams = {MAIN_MENU_BUTTONS_WIDTH,MAIN_MENU_BUTTONS_HEIGHT,&MainMenuButtonFont};
TScreenObjectParams MainMenuSpecialObjectParams = {MAIN_MENU_SPECIAL_BUTTONS_WIDTH, MAIN_MENU_BUTTONS_HEIGHT, &MainMenuSpecialObjectFont};

/****************************************************************************
	Nazvy polozek menu

*****************************************************************************/
unsigned char *MainMenuStrings[MAIN_MENU_OBJECTS_COUNT] = {STR_REMOTE_CONTROL, STR_OPTIONS_BUTTON, STR_ABOUT};
unsigned char *OptionsMenuStrings[MENU_OPTIONS_OBJECTS_COUNT] = {STR_NET_SETUP, STR_TIME_SETUP,STR_HARDWARE_SETUP/*,STR_ITEM3*/};
unsigned char *HardwareMenuStrings[MENU_HARDWARE_OBJECTS_COUNT] = {STR_SERIAL_SETUP,STR_DISPLAY_SETUP};

/****************************************************************************
	Reakce polozky menu na kliknuti

	Vstup: 
		obj:			instance objektu
		msg:			parametr volani

	Vystup
		neni

*****************************************************************************/
void MenuObjectCallback(TScreenObject * obj, OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;
#endif
	char index = obj->id;
	if (CurrentMenuRoot->subMenus[index].isExecutable == YES)								//Pokud je polozka spustitelna
	{
		MainMenuInternal.RunApplication(CurrentMenuRoot->subMenus[index].Application);		//Spust ji prirazenou aplikaci

	}
	else
	{	
		HigherMenus[CurrentMenuDepth++] = CurrentMenuRoot;									//Jinak uloz aktualni koren menu
		CurrentMenuRoot = CurrentMenuRoot->subMenus+index;									//nastav novy koren menu
		MainMenuInternal.State = MAIN_MENU_DRAW;											//prekresli menu
	}
	
}

/****************************************************************************
	Funkce reakce ridicich polozek v menu

	Vstup: 
		obj:			instance objektu
		message:		parametr volani

	Vystup
		neni

*****************************************************************************/
void MenuSpecialObjectCallback(TScreenObject * obj, OBJECT_MESSAGE msg)
{
#ifdef FIX_ALL_WARNINGS
	msg;
#endif
	switch(obj->id)
	{
	case MAIN_MENU_BACK:										//Tlacitko Zpet
		if (CurrentMenuDepth < 1)								//Pokud nejsme na vrcholu
		{
			DebugOut("Cannot return to higher menu.\n");
			break;
		}
		CurrentMenuRoot = HigherMenus[--CurrentMenuDepth];		//Posun o jedna nahoru
		MainMenuInternal.State = MAIN_MENU_DRAW;				//Prekresleni
		break;
	default:
		DebugOut("Unknown button request.\n");
		break;
	}
}

/****************************************************************************
	Preklad kliknuti na nazev tlacitka:
		Jak je zrejme na zaatku tohoto modulu, pro aplikaci jsou pouzity dva objekty
		TScreen. Aby bylo mozne rozlisit, ve kterem klikani probiha, je hodnota
		indexu vracena kladne pro polozky v menu a zaporne pro ridici polozky.

	Vstup: 
		pos:		Ukazatel na pozici kliku

	Vystup
		neni

*****************************************************************************/
static int translateClickPosition(POSITION * pos)
{
	int maxStdPosition = MAIN_MENU_BUTTONS_TOP+(CurrentMenuRoot->subCount-1)*MAIN_MENU_BUTTONS_DISTANCE + MAIN_MENU_BUTTONS_HEIGHT;
	char tmp;
	if (pos->y < MAIN_MENU_BUTTONS_TOP)
	{
		DebugOut("Click too high...\n");
		return -126;
	}
	if ((pos->y > maxStdPosition && pos->y < MAIN_MENU_SPECIAL_BUTTONS_TOP) || pos->y > MAIN_MENU_SPECIAL_BUTTONS_TOP+MAIN_MENU_BUTTONS_HEIGHT)
	{
		DebugOut("Click to dead area.\n");

		return -126;
	}
	if (pos->y > MAIN_MENU_SPECIAL_BUTTONS_TOP && pos->y < MAIN_MENU_SPECIAL_BUTTONS_TOP+MAIN_MENU_BUTTONS_HEIGHT)
	{
		DebugOut("Click to special area.\n");
		tmp = (char)integerDiv(pos->x - MAIN_MENU_SPECIAL_BUTTONS_LEFT,MAIN_MENU_SPECIAL_BUTTONS_DISTANCE);
		if ((pos->x - MAIN_MENU_SPECIAL_BUTTONS_LEFT - tmp*MAIN_MENU_SPECIAL_BUTTONS_DISTANCE)> MAIN_MENU_SPECIAL_BUTTONS_WIDTH)
		{
			DebugOut("Click between special buttons.\n");
			return -126;
		}
		
		return -tmp-1;
	}


	if ((pos->x < MAIN_MENU_BUTTONS_LEFT) || (pos->x > (MAIN_MENU_BUTTONS_LEFT + MAIN_MENU_BUTTONS_WIDTH)))
	{
		DebugOut("Click too left/right\n");
		return -126;
	}
	tmp = (char)integerDiv(pos->y-MAIN_MENU_BUTTONS_TOP,MAIN_MENU_BUTTONS_DISTANCE);
	if ((pos->y-MAIN_MENU_BUTTONS_TOP - tmp*MAIN_MENU_BUTTONS_DISTANCE)> MAIN_MENU_BUTTONS_HEIGHT)
	{
		DebugOut("Click between buttons.\n");
		return -126;
	}
	DebugOut("Click OK\n");
	return tmp;
}


/****************************************************************************
	Inicializacni metoda

	Vstup: 
		neni

	Vystup
		neni

*****************************************************************************/
RESULT MainMenuInitialize(void)
{
	char i = 0;

	/****************************************************************************
		Inicializace struktury menu z logickeho hlediska (aplikace, podmenu...)

	*****************************************************************************/
	MenuStructure.InitSub(MainMenuButtons, MainMenuObjects,MAIN_MENU_OBJECTS_COUNT);
	MenuStructure.subMenus[MAIN_MENU_REMOTE_DESKTOP].InitApp(CONNECTOR);
	MenuStructure.subMenus[MAIN_MENU_SETUP].InitSub(MenuOptionsButtons,MenuOptionsObjects,MENU_OPTIONS_OBJECTS_COUNT);
	MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_NET_SETUP].InitApp(NET_SETUP);
	MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_TIME_SETUP].InitApp(TIME_SETUP);
	MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_HARDWARE_SETUP].InitSub(MenuHardwareButtons,MenuHardwareObjects,MENU_HARDWARE_OBJECTS_COUNT);
	//MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_HARDWARE_SETUP].subMenus[MENU_HARDWARE_WIFI_SETUP].InitApp(NONE);
	MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_HARDWARE_SETUP].subMenus[MENU_HARDWARE_SERIAL_SETUP].InitApp(SERIAL_SETUP);
	MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_HARDWARE_SETUP].subMenus[MENU_HARDWARE_DISPLAY_SETUP].InitApp(BACKLIGHT_SETUP);
	//MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_ITEM3].InitApp(KEYBOARD);
	MenuStructure.subMenus[MAIN_MENU_ABOUT].InitApp(ABOUT);
	

	mainMenuScreen.Init(MAIN_MENU_OBJECTS_COUNT,&MainMenuScreenFont);										//Inicializace obrazovky menu
	MainMenuCommons.Init(MAIN_MENU_SPECIAL_OBJECTS_COUNT,MainMenuCommonObjects,&MainMenuScreenFont,FALSE);	//Inicializace ridicich prvku obrazu

	MainMenuInternal.Init(MAIN_MENU,MAIN_MENU_XA, MAIN_MENU_YA, MAIN_MENU_XC, MAIN_MENU_YC,&mainMenuScreen,0,YES);	//Inicializace ridici struktury aplikace
	if (MainMenuInternal.Screen == 0)
		return FAILED;

	if (MenuStructure.subObjects == 0)
		return FAILED;

	/****************************************************************************
		Inicializace objektu menu

	*****************************************************************************/
	for (i = 0; i < MAIN_MENU_OBJECTS_COUNT; i++)
	{
		MenuStructure.subObjects[i].Init(MAIN_MENU_BUTTONS_LEFT,MAIN_MENU_BUTTONS_TOP+i*MAIN_MENU_BUTTONS_DISTANCE,BUTTON,i,MainMenuStrings[i],OBJECT_ENABLED,&MainMenuButtonParams,&MenuObjectCallback,&DrawButton);
	}

	for (i = 0; i < MENU_OPTIONS_OBJECTS_COUNT; i++)
	{
		MenuStructure.subMenus[MAIN_MENU_SETUP].subObjects[i].Init(MAIN_MENU_BUTTONS_LEFT,MAIN_MENU_BUTTONS_TOP+i*MAIN_MENU_BUTTONS_DISTANCE,BUTTON,i,OptionsMenuStrings[i],OBJECT_ENABLED,&MainMenuButtonParams,&MenuObjectCallback,&DrawButton);
	}

	for (i = 0; i < MENU_HARDWARE_OBJECTS_COUNT; i++)
	{
		MenuStructure.subMenus[MAIN_MENU_SETUP].subMenus[MENU_OPTIONS_HARDWARE_SETUP].subObjects[i].Init(MAIN_MENU_BUTTONS_LEFT,MAIN_MENU_BUTTONS_TOP+i*MAIN_MENU_BUTTONS_DISTANCE,BUTTON,i,HardwareMenuStrings[i],OBJECT_ENABLED,&MainMenuButtonParams,&MenuObjectCallback,&DrawButton);
	}
	CurrentMenuRoot = &MenuStructure;

	MainMenuCommons.objects[MAIN_MENU_BACK].Init(MAIN_MENU_SPECIAL_BUTTONS_LEFT, MAIN_MENU_SPECIAL_BUTTONS_TOP,BUTTON,MAIN_MENU_BACK,STR_CANCEL,OBJECT_ENABLED,&MainMenuSpecialObjectParams,&MenuSpecialObjectCallback,&DrawButton);
	
	return PASSED;
}



/****************************************************************************
	POstovni schranka aplikace

	Vstup: 
		msg:		Zprava pro aplikaci

	Vystup
		neni

*****************************************************************************/
RESULT MMMsgBox(MESSAGE *msg)
{
	POSITION* tmpPosition = 0;
	switch (msg->msg)
	{
	case RUN:
		DebugOut("Main Menu RUN command received.\n");
		if (MainMenuInternal.State == MAIN_MENU_READY)					//POkud je aplikace zinicializovana
		{
			MainMenuInternal.State = MAIN_MENU_RESTART;					//Proved jeji spusteni
			return PASSED;
		}
		break;
	case INIT:
		if (MainMenuInternal.State == MAIN_MENU_NOT_INITIALIZED)		//POkud neni aplikace zinicializovana
		{
			DebugOut("Main Menu INIT command received.\n");
			MainMenuInternal.State = MAIN_MENU_INITIALIZE;				//Proved inicializaci
			return PASSED;
		}
		break;
	case GET_STATE:
		DebugOut("Main Menu GET_STATE command received.\n");
		return (RESULT)MainMenuInternal.State;							//Vraci stav aplikace
		break;
	case APP_CLICK:
		MainMenuInternal.ClickPosition.isFresh = YES;					//Po prijeti kliku pro aplikaci
		tmpPosition = (POSITION*)msg->data;								//Zkopiruj info o kliknuti
		MainMenuInternal.ClickPosition.x = tmpPosition->x;
		MainMenuInternal.ClickPosition.y = tmpPosition->y;
		return PASSED;
	default:
		break;
		
	}
	return FAILED;
}


/****************************************************************************
	Hlavni stavovy automat aplikace

	Vstup:
		neni

	Vystup:
		neni

*****************************************************************************/
void AppMainMenu(void)
{
	int index = -1;
	switch(MainMenuInternal.State)
	{
	case MAIN_MENU_NOT_INITIALIZED:
		break;
	case MAIN_MENU_INITIALIZE:
		if (MainMenuInitialize() == FAILED)									//Proved inicializaci
			MainMenuInternal.State = MAIN_MENU_ERROR;
		MainMenuInternal.State = MAIN_MENU_READY;							//prejdi do dalsiho stavu
		DebugOut("Main menu initialized.\n");
		break;
	case MAIN_MENU_RESTART:
		MainMenuInternal.Startup();											//ulohy nezbytne pro spusteni
		MainMenuInternal.State = MAIN_MENU_DRAW;
		//StatusBarTextUpdate(STR_MAIN_MENU);
		break;
	case MAIN_MENU_DRAW:
		SendTaskMessage(STATUS_BAR,&DEFAULT_MSG_REFRESH);					//Refresh StatusBaru
		MainMenuInternal.Screen->objects = CurrentMenuRoot->subObjects;		//prirazeni spravnych podobjektu pro kresleni
		MainMenuInternal.Screen->object_count = CurrentMenuRoot->subCount;	//nastaveni poctu objektu
		MainMenuInternal.Screen->Draw();									//Vykresleni obou obrazovek pres sebe
		MainMenuCommons.Draw();
		MainMenuInternal.State = MAIN_MENU_ACTIVE;							//Prejdi do aktivniho stavu
		DebugOut("Main menu draw.\n");
		break;
	case MAIN_MENU_ACTIVE:
		if (MainMenuInternal.ClickPosition.isFresh == YES)									//Pokud byl prijat dotyk
		{
			MainMenuInternal.ClickPosition.isFresh = NO;									//Odeber ho
			index = (int)translateClickPosition(&MainMenuInternal.ClickPosition);			//Proved preklad na index objektu
			if (index == -126 || CurrentMenuRoot->subCount <= index || index < -MAIN_MENU_SPECIAL_OBJECTS_COUNT)
			{
				DebugOut("Ignoring click.\n");
				break;																		//Kliknuti na neexistujici objekt
			}
			else if (index < 0)																//Pokud je index < 0
			{

				MainMenuCommons.objects[-index-1].object_callback(&MainMenuCommons.objects[-index-1],MSG_CLICK);	//je kliknuto na ridici tlacitko
				DebugOut("Special click proceeded.\n");
			}
			else
				CurrentMenuRoot->subObjects[index].object_callback(&CurrentMenuRoot->subObjects[index],MSG_CLICK);	//Jinak je kliknuto na polozku menu
			
		}
		break;
	case MAIN_MENU_WAITING:
		MainMenuInternal.TryToResume();			//cekani na ukonceni aplikace, je jedno z ktere
		break;
	case MAIN_MENU_READY:
		break;
	case MAIN_MENU_ERROR:
		break;
	default:
		MainMenuInternal.State = MAIN_MENU_ERROR;
		DebugOut("Main menu unknown state, falling to error.\n");
		break;
	}
}
