/* Zdrojovy soubor pro utivatelske rozhrani mistniho ovladani - menu */

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include <stddef.h>
#include "stm32f10x.h"
#include "menu.h"
#include "menu-texty.h"
#include "LCD_HD44780.h"
#include "PIN_config.h"
#include "My_usart.h"

//#define DEBUG

extern uint8_t AktualniUroven[MENU_MAX_UROVEN] = {MENU_NEALOKOVANO,
												  MENU_NEALOKOVANO,
												  MENU_NEALOKOVANO,
												  MENU_NEALOKOVANO,
												  MENU_NEALOKOVANO};	// Aktualni uroven zanoreni s informaci o vybranych predchozich nadurovnich
static uint8_t PoziceRotace[MENU_DISPLAY_LINE]={0,0};

/* --------------------------------------------------------------
 Funkce pro zobrazeni dane urovne menu. Vraci id polozky na ktere
 bylo stisknuto tlacitko pro vstup do ni.
 ------------------------------------------------------------- */
uint8_t Menu_Run(uint8_t MenuID)
{
	uint8_t PocetPolozek;											// Pocet polozek ve vybrane urovni menu
	uint8_t PoziceUkazatele = 0;									// Pozice ukazatele vybrane polozky ">"
	uint8_t PoziceUkazateleNaObrazovce = 0;
	uint8_t i, temp;
	uint8_t ID_PrvniRadek = 0;
	uint8_t ID_DruhyRadek = 0;

	PocetPolozek = Menu_GetItemCount();								// Zjisteni poctu polozek ve vybrane urovni menu
	#ifdef DEBUG
		USART1_Send("Pocet polozek: ",0);
		USART1_SendNumber(PocetPolozek);
		USART1_Send_Enter();
	#endif	
	if(PocetPolozek==0)
	{
		#ifdef DEBUG
			USART1_Send("Zadna zobrazitelna polozka!\r\n> UP",1);
		#endif
		PoziceRotace[0]=0;
		PoziceRotace[1]=0;
		temp=Menu_GetUroven(); 
		if(temp!=0)
		{
			temp--;
			AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu
			return(MENU_UROVEN_ZPET);
		}
		else
		{
			AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu
			return(MENU_UROVEN_EXIT);
		}
	}
	if(PocetPolozek==MENU_NEALOKOVANO)
	{
		#ifdef DEBUG
			USART1_Send("Neexistujici podmenu!\r\n> UP",1);
		#endif
		PoziceRotace[0]=0;
		PoziceRotace[1]=0;
		temp=Menu_GetUroven(); 
		if(temp!=0)
		{
			temp--;
			AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu
			return(MENU_UROVEN_ZPET);
		}
		else
		{
			AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu
			return(MENU_UROVEN_EXIT);
		}
		
	}
	while(1)
	{
		ID_PrvniRadek=Menu_GetItemID(ID_PrvniRadek+0,MENU_DIR_NEXT);// Vrati ID nasledujici polozky k zobrazeni na 1. radku
		ID_DruhyRadek=Menu_GetItemID(ID_PrvniRadek+1,MENU_DIR_NEXT);// Vrati ID nasledujici polozky k zobrazeni na 2. radku
		
		// Vykresleni Textu prvniho a druheho radku
		if(ID_PrvniRadek==MENU_NEALOKOVANO)							// Overeni jstli je nalezene ID radku platne nebo jestli dalsi zaznam v tabulce neexistuje
		{
			LCD_HD44780_GoTo(MENU_LEFTSPACE,0);						// Vykresli prazdny radek
			for(i=MENU_LEFTSPACE;i<MENU_TEXTVISIBLE;i++)
			{
				LCD_HD44780_PutChar(' ');
			}
		}
		else
		{
			if(PoziceUkazateleNaObrazovce==0)
			{
				Menu_TextRotate(MenuLabel[ID_PrvniRadek],0,1);
			}
			else
			{
				Menu_TextRotate(MenuLabel[ID_PrvniRadek],0,0);
			}
		}
		if(ID_DruhyRadek==MENU_NEALOKOVANO)							// Overeni jstli je nalezene ID radku platne nebo jestli dalsi zaznam v tabulce neexistuje
		{
			LCD_HD44780_GoTo(MENU_LEFTSPACE,1);						// Vykresli prazdny radek
			for(i=MENU_LEFTSPACE;i<MENU_TEXTVISIBLE;i++)
			{
				LCD_HD44780_PutChar(' ');
			}
		}
		else
		{
			if(PoziceUkazateleNaObrazovce==1)
			{
				Menu_TextRotate(MenuLabel[ID_DruhyRadek],1,1);
			}
			else
			{
				Menu_TextRotate(MenuLabel[ID_DruhyRadek],1,0);
			}
		}

		/* Zobrazeni ukazatele vybrane polozky **********************/
		LCD_HD44780_GoTo(0,PoziceUkazateleNaObrazovce);
		LCD_HD44780_PutChar(MENU_UKAZATEL);
		LCD_HD44780_PutChar(' ');
		if(PoziceUkazateleNaObrazovce==0)
		{
			LCD_HD44780_GoTo(0,1);
			LCD_HD44780_PutChar(' ');
			LCD_HD44780_PutChar(' ');
		}
		else if(PoziceUkazateleNaObrazovce!=0)
		{
			LCD_HD44780_GoTo(0,0);
			LCD_HD44780_PutChar(' ');
			LCD_HD44780_PutChar(' ');
		}
	
		/* Zjisteni odezvy od tlacitek ******************************/
		for(i=0;i<MENU_RYCHLOSTROTACE;i++)
		{
			if(TL_NAHORU_Read_0())										// Obsluha tlacitka NAHORU
			{
				PEZO_BEEP();
				vTaskDelay(30*portTICK_FOR_1MS);
				while(TL_NAHORU_Read_0()) vTaskDelay(1*portTICK_FOR_1MS);								// Cekani na uvolneni tlacitka
				vTaskDelay(30*portTICK_FOR_1MS);
				// Zadost o posun v menu nahoru
				PoziceRotace[PoziceUkazateleNaObrazovce]=MENU_TEXTVISIBLE-MENU_LEFTSPACE-1;
				if(PoziceUkazateleNaObrazovce==0)						// Ukazatel je na horni pozici -> nutno prekreslit
				{														// menu a posunout o jednu polozku nahoru
					temp = ID_PrvniRadek;								// Zaloha aktualniho ID prvniho radku
					ID_PrvniRadek=Menu_GetItemID(ID_PrvniRadek-1,MENU_DIR_PREW);	// Nalezeni predchozi polozky
					if(ID_PrvniRadek==MENU_NEALOKOVANO)
					{
						ID_PrvniRadek=temp;
					}
				}
				else													// Ukazatel je na dolni pozici -> neni nutnu 
				{														// prekreslovat menu, jen posunout ukazatel
					PoziceUkazateleNaObrazovce=0;
				}				
				if(PoziceUkazatele!=0)									// Osetreni posouvani ID vybrane polozky aby
				{														// nepretekla pres 0
					PoziceUkazatele--;
					PoziceRotace[0]=0;
					PoziceRotace[1]=0;
				}
				i=254;
				#ifdef DEBUG
					USART1_Send("Pozice ukazatele: ",0);
					USART1_SendNumber(PoziceUkazatele);
					USART1_Send_Enter();
					USART1_Send("Pozice LCD: ",0);
					USART1_SendNumber(PoziceUkazateleNaObrazovce);
					USART1_Send_Enter();
				#endif
			}
			else if(TL_DOLU_Read_0())									// Obsluha tlacitka DOLU
			{
				PEZO_BEEP();
				vTaskDelay(30*portTICK_FOR_1MS);
				while(TL_DOLU_Read_0()) vTaskDelay(1*portTICK_FOR_1MS);								// Cekani na uvolneni tlacitka
				vTaskDelay(30*portTICK_FOR_1MS);
				// Zadost o posun v menu dolu
				PoziceRotace[PoziceUkazateleNaObrazovce]=MENU_TEXTVISIBLE-MENU_LEFTSPACE-1;
				if(PoziceUkazateleNaObrazovce==1)						// Ukazatel je na horni pozici -> nutno prekreslit
				{														// menu a posunout o jednu polozku nahoru
					temp=Menu_GetItemID(ID_DruhyRadek+1,MENU_DIR_NEXT);	// Nalezeni nasledujici polozky
					if(temp!=MENU_NEALOKOVANO)
					{
						ID_PrvniRadek=Menu_GetItemID(ID_PrvniRadek+1,MENU_DIR_NEXT);	// Nalezeni nasledujici polozky
					}
				}
				else													// Ukazatel je na dolni pozici -> neni nutnu 
				{														// prekreslovat menu, jen posunout ukazatel
					PoziceUkazateleNaObrazovce=1;
				}
				if(PoziceUkazatele<(PocetPolozek-1))						// Osetreni posouvani ID vybrane polozky aby
				{														// nepretekla pres celkovy pocet polozek v menu
					PoziceUkazatele++;
					PoziceRotace[0]=0;
					PoziceRotace[1]=0;
				}
				i=254;
				#ifdef DEBUG
					USART1_Send("Pozice ukazatele: ",0);
					USART1_SendNumber(PoziceUkazatele);
					USART1_Send_Enter();
					USART1_Send("Pozice LCD: ",0);
					USART1_SendNumber(PoziceUkazateleNaObrazovce);
					USART1_Send_Enter();
				#endif			
			}
			else if(TL_OK_Read_0())										// Obsluha tlacitka OK
			{
				PEZO_BEEP();
				vTaskDelay(30*portTICK_FOR_1MS);
				while(TL_OK_Read_0()) vTaskDelay(1*portTICK_FOR_1MS);									// Cekani na uvolneni tlacitka
				vTaskDelay(30*portTICK_FOR_1MS);
		    
				PoziceRotace[0]=0;
				PoziceRotace[1]=0;
				temp=Menu_GetUroven(); 

				if(temp<(MENU_MAX_UROVEN))
				{
					AktualniUroven[temp]=PoziceUkazatele+1;
				}
				
				#ifdef DEBUG
					USART1_Send("AktualniUroven: ",0);
					USART1_SendNumber(AktualniUroven[0]);
					USART1_Write('>');
					USART1_SendNumber(AktualniUroven[1]);
					USART1_Write('>');
					USART1_SendNumber(AktualniUroven[2]);
					USART1_Write('>');
					USART1_SendNumber(AktualniUroven[3]);
					USART1_Write('>');
					USART1_SendNumber(AktualniUroven[4]);
					USART1_Send_Enter();
				#endif
				return(PoziceUkazatele+1);											// Vrati poradove ID polozky ktera byla vybrana
			}
			else if(TL_ZPET_Read_0())									// Obsluha tlacitka Zpet
			{
				PEZO_BEEP();
				vTaskDelay(30*portTICK_FOR_1MS);
				while(TL_ZPET_Read_0()) vTaskDelay(1*portTICK_FOR_1MS);								// Cekani na uvolneni tlacitka
				vTaskDelay(30*portTICK_FOR_1MS);
		    
				PoziceRotace[0]=0;
				PoziceRotace[1]=0;
				temp=Menu_GetUroven(); 
				if(temp!=0)
				{
					temp--;
					AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu					
					#ifdef DEBUG
						USART1_Send("AktualniUroven: ",0);
						USART1_SendNumber(AktualniUroven[0]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[1]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[2]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[3]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[4]);
						USART1_Send_Enter();
					#endif
					return(MENU_UROVEN_ZPET);
				}
				else
				{
					AktualniUroven[temp]=MENU_NEALOKOVANO;		// Smazani zaznamu i vybranem ID v aktualni urovni menu
					#ifdef DEBUG
						USART1_Send("AktualniUroven: ",0);
						USART1_SendNumber(AktualniUroven[0]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[1]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[2]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[3]);
						USART1_Write('>');
						USART1_SendNumber(AktualniUroven[4]);
						USART1_Send_Enter();
					#endif
					return(MENU_UROVEN_EXIT);
				}				
				
			}
			vTaskDelay(1*portTICK_FOR_1MS);
		}
	}
}

/* --------------------------------------------------------------
 Funkce pro rotujici vypis textu polozek v menu. Pri kazdem
 zavolani vykresli na dany radek polozku textu a pokud je
 to nutne o jeden znak ji zarotuje smerem doleva
 ------------------------------------------------------------- */
void Menu_TextRotate(const uint8_t *text, uint8_t radek, uint8_t rotovat)
{
	uint8_t delka = Menu_GetTextLen(text);
	uint8_t i,j,k;														// i ... promenna pro odpocitani znaku ktere se vejdou na LCD
																		// j ... index pro pohyb v poli textu

	/* Zobrazovani s pripadnou rotaci */
	if(delka>(MENU_TEXTVISIBLE-MENU_LEFTSPACE))							// Kontrola jestli se text nevejde na radek bez nutnosti
	{																	// rotace
		if(rotovat==0)
		{
			PoziceRotace[radek]=MENU_TEXTVISIBLE-MENU_LEFTSPACE-1;		// Pokud text nema rotovat, tak je zobrazeny od prvniho znaku (bez povatecnich mezer slouzicich k hezci rotaci)
		}
		if(PoziceRotace[radek]<(MENU_TEXTVISIBLE-MENU_LEFTSPACE))
		{
			LCD_HD44780_GoTo((MENU_TEXTVISIBLE-1-PoziceRotace[radek]),radek);
			k=MENU_TEXTVISIBLE-MENU_LEFTSPACE-1-PoziceRotace[radek];
			j=MENU_IDLENGTH;
			if(PoziceRotace[radek]==0)
			{
				/* Smazani radku */
				LCD_HD44780_GoTo(MENU_LEFTSPACE,radek);
				for(i=MENU_LEFTSPACE;i<(MENU_TEXTVISIBLE-MENU_LEFTSPACE);i++)
				{
					LCD_HD44780_PutChar(' ');
				}
			}
		}
		else
		{
			LCD_HD44780_GoTo(MENU_LEFTSPACE,radek);
			k=0;
			j=PoziceRotace[radek]-(MENU_TEXTVISIBLE-MENU_LEFTSPACE-1)+MENU_IDLENGTH;
		}		
		for(i=0;i<(MENU_TEXTVISIBLE-MENU_LEFTSPACE-k);i++)
		{
			if(j<(delka+MENU_IDLENGTH))
			{
				LCD_HD44780_PutChar(text[j++]);							// Normalni vypis textu
			}
			else
			{
				LCD_HD44780_PutChar(' ');								// Vypis mezer do doby nez text "zmizi" za levym okrajem LCD
			}
		}
		if(rotovat==1)
		{
			PoziceRotace[radek]++;										// Posun o jeden znak - rotace
		}		
		if(PoziceRotace[radek]>(delka+(MENU_TEXTVISIBLE-MENU_LEFTSPACE)))// Kontrola jestli se pri dalsi rotaci nevleze zbytek
		{																// textu na radek. Pokud ano, zacne se rotovat odzacatku
			PoziceRotace[radek]=0;
		}
	}
	else																// Radek neni treba rotovat
	{
		LCD_HD44780_GoTo(MENU_LEFTSPACE,radek);
		for(i=MENU_IDLENGTH;i<(delka+MENU_IDLENGTH);i++)					// Vypsani celeho textu bez rotace
		{
			LCD_HD44780_PutChar(text[i]);
		}
		for(;i<(MENU_TEXTVISIBLE+MENU_LEFTSPACE+1);i++)
		{
			LCD_HD44780_PutChar(' ');
		}
	}
}

/* --------------------------------------------------------------
 Funkce vrati pocet polozek v aktualne vybranem menu 
 (dle obsahu AktualniUroven[x])
 ------------------------------------------------------------- */
uint8_t Menu_GetItemCount(void)
{
	uint8_t i, j, faze, pocet=0;
	uint8_t HloubkaZanoreni=Menu_GetUroven();							// Zjisteni v jake urovni menu se uzivatel nachazu => pocet hledanych shodnych ID bytu

	for(j=0;j<MENU_ITEMCOUNT;j++)										// Prochazeni vsech zaznamu v tabulce textu
	{
		faze=0;															// Vynulovani poctu shodnych bytu
		if(HloubkaZanoreni!=0)
		{
			for(i=0;i<HloubkaZanoreni;i++)									// Prochazeni ID udaju v jednotlivych zaznamech
			{
				if(MenuLabel[j][i]==AktualniUroven[i])						// ID se rovnaji
				{
					faze++;													// Zvyseni poctu shodnych ID bytu
				}
				else														// ID se nerovnaji
				{
					faze=0;													// Vyresetovani informace o tom, kolik bytu je shodnych
					break;
				}
			}
			if(faze==HloubkaZanoreni)										// Kontrola jestli se shoduji vsechny ID byty
			{
				if((MenuLabel[j][i]!=0)&(MenuLabel[j][i+1]==0))				// Osetreni aby se vynechala nadrazena polozka a polozky jinych podmenu se stejnou nadrazenou polozkou
				{
					pocet++;
				}
			}
		}
		else															// Pokud je uroven zanoreni 0->Hlavni menu, tak porovnavat jen druhy byte [1] jestli je nulovy
		{
			if(MenuLabel[j][1]==0)										// ID se rovnaji
			{
				pocet++;													// Zvyseni poctu shodnych ID bytu
			}
		}
	}
	if(pocet!=0)
	{
		return(pocet);
	}
	else
	{
		return(MENU_NEALOKOVANO);
	}
}

/* --------------------------------------------------------------
 Funkce vrati pocet polozek v aktualne vybranem menu 
 (dle obsahu AktualniUroven[x])
 ------------------------------------------------------------- */
uint8_t Menu_GetItemID(uint8_t start, uint8_t direction)
{
	uint8_t i, j, faze;
	uint8_t HloubkaZanoreni=Menu_GetUroven();							// Zjisteni v jake urovni menu se uzivatel nachazu => pocet hledanych shodnych ID bytu

	if(start>=MENU_ITEMCOUNT)											// Zabraneni preteceni za oba okraje pole (horni i dolni)
	{
		return(MENU_NEALOKOVANO);
	}

	if(direction==MENU_DIR_NEXT)
	{
		for(j=start;j<MENU_ITEMCOUNT;j++)										// Prochazeni vsech zaznamu v tabulce textu
		{
			faze=0;															// Vynulovani poctu shodnych bytu
			if(HloubkaZanoreni!=0)
			{
				for(i=0;i<HloubkaZanoreni;i++)									// Prochazeni ID udaju v jednotlivych zaznamech
				{
					if(MenuLabel[j][i]==AktualniUroven[i])						// ID se rovnaji
					{
						faze++;													// Zvyseni poctu shodnych ID bytu
					}
					else														// ID se nerovnaji
					{
						faze=0;													// Vyresetovani informace o tom, kolik bytu je shodnych
						break;
					}
				}
				if(faze==(HloubkaZanoreni))									// Kontrola jestli se shoduji vsechny ID byty
				{
					if((MenuLabel[j][i]!=0)&(MenuLabel[j][i+1]==0))			// Osetreni aby se vynechala nadrazena polozka a polozky jinych podmenu se stejnou nadrazenou polozkou
					{
						return(j);
					}
				}
			}
			else
			{
				if(MenuLabel[j][1]==0)										// ID se rovnaji
				{
					return(j);												// Vrati ID odpovidajiciho zaznamu
				}	
			}
		}
	}
	else if(direction==MENU_DIR_PREW)
	{
		for(j=start;(j<255);j--)										// Prochazeni vsech zaznamu v tabulce textu
		{
			faze=0;															// Vynulovani poctu shodnych bytu
			if(HloubkaZanoreni!=0)
			{
				for(i=0;i<HloubkaZanoreni;i++)									// Prochazeni ID udaju v jednotlivych zaznamech
				{
					if(MenuLabel[j][i]==AktualniUroven[i])						// ID se rovnaji
					{
						faze++;													// Zvyseni poctu shodnych ID bytu
					}
					else														// ID se nerovnaji
					{
						faze=0;													// Vyresetovani informace o tom, kolik bytu je shodnych
						break;
					}
				}
				if(faze==(HloubkaZanoreni))									// Kontrola jestli se shoduji vsechny ID byty
				{
					if((MenuLabel[j][i]!=0)&(MenuLabel[j][i+1]==0))			// Osetreni aby se vynechala nadrazena polozka a polozky jinych podmenu se stejnou nadrazenou polozkou
					{
						return(j);
					}
				}
			}
			else
			{
				if(MenuLabel[j][1]==0)										// ID se rovnaji
				{
					return(j);												// Vrati ID odpovidajiciho zaznamu
				}	
			}
		}
	}
	return(MENU_NEALOKOVANO);
}

/* --------------------------------------------------------------
 Funkce vrati pocet znaku textu dane polozky v menu
 ------------------------------------------------------------- */
uint8_t Menu_GetTextLen(const uint8_t *text)
{
	uint8_t i;
	for(i=MENU_IDLENGTH;i<MENU_TEXTLENGTH;i++)
	{
		if(text[i]==0)
		{
			if(i!=0)
			{
				return(i-MENU_IDLENGTH);
			}
		}
	}
	return(0);
}

/* --------------------------------------
 Funkce vrati cislo aktualni urovne
 ------------------------------------- */
uint8_t Menu_GetUroven(void)
{
	uint8_t i;
	for(i=0;i<MENU_MAX_UROVEN;i++)
	{
		if(AktualniUroven[i]==MENU_NEALOKOVANO)
		{
			return(i);
		}
	}
	return(0);
}

/* --------------------------------------
 Funkce vrati ID polozky v aktualni urovni
 ------------------------------------- */
uint8_t Menu_GetIDUroven(void)
{
	uint8_t i;
	for(i=0;i<MENU_MAX_UROVEN;i++)
	{
		if(AktualniUroven[i]==MENU_NEALOKOVANO)
		{
			return(AktualniUroven[i]);
		}
	}
	return(0);
}

/* --------------------------------------
 Funkce vrati cislo urovne bezprostredne
 nad aktualne vybranou
 ------------------------------------- */
uint8_t Menu_GetUrovenUP(void)
{
	uint8_t i;
	for(i=0;i<MENU_MAX_UROVEN;i++)
	{
		if(AktualniUroven[i]==MENU_NEALOKOVANO)
		{
			if(i==0)
			{
				return(i);
			}
			else
			{
				return(i-1);
			}
		}
	}
	return(0);
}

/* --------------------------------------------------------------
 Funkce vrati ID polozky urovne bezprostredne nad aktualne
 vybranou
 ------------------------------------------------------------- */
uint8_t Menu_GetIDUrovenUP(void)
{
	uint8_t i;
	for(i=0;i<MENU_MAX_UROVEN;i++)
	{
		if(AktualniUroven[i]==MENU_NEALOKOVANO)
		{
			if(i==0)
			{
				return(AktualniUroven[i]);
			}
			else
			{
				return(AktualniUroven[i-1]);
			}
		}
	}
	return(0);
}

/* --------------------------------------------------------------
 Funkce inicializuje (smaze) zasobnik pro uchovavani ID 
 zvolenych v jednotlivych urovnich menu
 ------------------------------------------------------------- */
void Menu_UrovneInit(void)
{
	uint8_t i;
	for(i=0;i<MENU_MAX_UROVEN;i++)
	{
		AktualniUroven[i]=MENU_NEALOKOVANO;
	}
	for(i=0;i<MENU_DISPLAY_LINE;i++)
	{
		PoziceRotace[i]=0;
	}
	
}

/* Konec souboru */
