/****************************************************************************
	Knihovna pro praci s grafickym displejem - obsahuje funkce pro vypis textu
	a jeho spravne formatovani do zadaneho obdelniku na displeji. 

	Podporuje vypis v ruznych barvach znaku, aktualne jsou implementovany dve 
	znakove sady - FONT_MINIMAL, FONT_SMALL

	Pisma jsou prevzata ze systemu Windows - byla provedena konverze pomoci
	programu CHARSET GENERATOR V2.0 spolecnosti Fujitsu.

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


#include "stdafx.h"
#include <stdio.h>
#include "GLCD.h"
#include "extra.h"
#include "GLCD_fonts.h"





RGB_COLORS Console_color_list[] = {RGB_BLACK, RGB_RED, RGB_GREEN, RGB_YELLOW, RGB_BLUE, RGB_VIOLET, RGB_CYAN, RGB_WHITE};

char BG_redraw_flag = TRUE;		//when drawing characters, flag enables background redrawing
char LineHeight = FONT_MINIMAL_HEIGHT;
char CurrentFontHeight = FONT_MINIMAL_HEIGHT;
char CurrentFontWidth = FONT_MINIMAL_WIDTH;
char FontHeightDifference = 0;
char isInverted = 0;
char linesCount = 0;
CURSOR_INFO CursorPosition;
FONT_SIZE Font = FONT_MINIMAL;
int x_min = 0;
int x_max = MAX_X;
int y_min = 0;
int y_max = MAX_Y;
int txt_X = 0;
int txt_Y = 0;

RGB_COLORS RGB_DEFAULT_TEXT = RGB_WHITE;

RGB_COLORS RGB_BACKGROUND = RGB_BLACK;

/****************************************************************************
	Funkce pro povoleni prekreslovani pozadi pri vypisovani textu

	Vstup: 
		enable:		suda hodnota povoli prekreslovani

	Výstup:
		neni

*****************************************************************************/
void LCD_enable_redrawing(char enable)
{
	BG_redraw_flag = enable%2;
}

/****************************************************************************
	Funkce povoli invertovane vypisovani

	Vstup: 
		enable:		povoli vypis invertovane

	Výstup:
		neni

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

void LCD_enable_inverted(char enable)
{
	isInverted = enable%2;
}


/****************************************************************************
	Prekresli kurzor na pozici

	Vstup: 
		visible		Je kurzor viditelny?

	Výstup:
		neni

*****************************************************************************/
void drawCursor(ANSWER visible)
{
	//ULozeni stavu modulu pred zmenou nastaveni pro vykresleni kurzoru
	int tmp_txt_x = txt_X;
	int tmp_txt_y = txt_Y;
	TRect tmp_roi; 
	tmp_roi.xA = x_min;
	tmp_roi.yA = y_min;
	tmp_roi.xC = x_max;
	tmp_roi.yC = y_max;
	char tmp_lineHeight = LineHeight;
	FONT tmp_font;
	txt_X = CursorPosition.x;
	txt_Y = CursorPosition.y;
	LineHeight = CursorPosition.lineHeight;
	tmp_font.size = Font;
	tmp_font.color = RGB_DEFAULT_TEXT;
	tmp_font.bg_color = RGB_BACKGROUND;
	LCD_Set_ROI(&CursorPosition.roi);
	LCD_Set_Font(&CursorPosition.font);
	if (visible == YES)
		isInverted = 1;
	//vykresli kurzor
	LCD_putchar(CursorPosition.C);
	isInverted = 0;
	LCD_Set_Font(&tmp_font);
	txt_X = tmp_txt_x;
	txt_Y = tmp_txt_y;
	LCD_Set_ROI(&tmp_roi);
	LineHeight = tmp_lineHeight;

}

/****************************************************************************
	Metoda vykresli textovou ikonu

	Vstup: 
		x,y:		souradnice ikony
		c			id ikony
		color:		barva

	Výstup:
		neni

*****************************************************************************/
void LCD_icon(int x, int y, unsigned char c, RGB_COLORS color)
{
	int u = 0, v = 0;

	//pro vsechny pixely proved polozeni pixelu
	for (u = 0; u < ICON_SMALL_WIDTH; u++)
			{
				for (v = 0; v < ICON_SMALL_HEIGHT; v++)
				{
					unsigned short value = (Icons[c][v]&(1<<((ICON_SMALL_WIDTH)-u)));	
					LCD_put_pix(x+u,y+v, (value!=0?color:RGB_BACKGROUND));

				}
			}
	}





/****************************************************************************
	Vytiskne symbol na danou pozici na displeji

	Vstup: 
		x, y:		pozice symbolu
		C			znak
		color:		barva
		size:		velikost symbolu

	Výstup:
		neni

*****************************************************************************/
void LCD_char(int x, int y, unsigned char C, RGB_COLORS color, FONT_SIZE size)
{
	int u = 0, v = 0;
	unsigned char c = C;
	
	switch (size)
	{
	case FONT_MINIMAL:
		//minimalni velikost fontu
		for (u = 0; u < FONT_MINIMAL_WIDTH+1; u++)
			{
				for (v = 0; v < FONT_MINIMAL_HEIGHT-2; v++)
				{
					//ziskani symbolu z definicni tabulky a polozeni jednotlivych bodu
					unsigned short value = (Terminal6[c-' '][v]&(1<<((FONT_MINIMAL_WIDTH-u)+3)));
					if (isInverted == 0)
						LCD_put_pix(x+u,y+v, (value!=0?color:RGB_BACKGROUND));
					else
						LCD_put_pix(x+u,y+v, (value!=0?RGB_BACKGROUND:color));

				}
			}
		break;
	case FONT_SMALL:
		if (isInverted == 0)
		{

#ifdef SIMPLE_FORMAT
			//jednoduche vykreslovani - nepouziva se
			for (u = 0; u < FONT_SMALL_WIDTH/2; u++)
			{
				for (v = 0; v < FONT_SMALL_HEIGHT/2; v++)
				{
					unsigned char value = (CHARACTERS_SMALL[c-' '][u]&(1<<v));	
					LCD_put_pix(x+2*u,y+2*v, (value!=0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u,y+2*v+1, (value!=0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u+1,y+2*v, (value!=0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u+1,y+2*v+1, (value!=0?color:RGB_BACKGROUND));
				}
			}
#else
			//vykresleni fontem Courier
			for (u = 0; u < FONT_SMALL_WIDTH+2; u++)
			{
				for (v = 0; v < FONT_SMALL_HEIGHT; v++)
				{
					unsigned short value = (Courier15[c-' '][v]&(1<<((FONT_SMALL_WIDTH+4)-u)));	
					LCD_put_pix(x+u,y+v, (value!=0?color:RGB_BACKGROUND));

				}
			}
#endif
		}
		else 
		{//...viz text

#ifdef SIMPLE_FORMAT
			for (u = 0; u < integerDiv(FONT_SMALL_WIDTH,2); u++)
			{
				for (v = 0; v < integerDiv(FONT_SMALL_HEIGHT,2); v++)
				{

					unsigned char value = (CHARACTERS_SMALL[c-' '][u]&(1<<v));	
					LCD_put_pix(x+2*u,y+2*v, (value==0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u,y+2*v+1, (value==0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u+1,y+2*v, (value==0?color:RGB_BACKGROUND));
					LCD_put_pix(x+2*u+1,y+2*v+1, (value==0?color:RGB_BACKGROUND));

				}
			}
#else
			for (u = 0; u < FONT_SMALL_WIDTH+2; u++)
			{
				for (v = 0; v < FONT_SMALL_HEIGHT; v++)
				{
					unsigned short value = (Courier15[c-' '][v]&(1<<((FONT_SMALL_WIDTH+4)-u)));		
					LCD_put_pix(x+u,y+v, (value==0?color:RGB_BACKGROUND));

				}
			}
#endif
		}
		break;
	case FONT_MEDIUM:
		//TODO
		break;
	case FONT_BIG:
		//TODO
		break;
	case FONT_HUGE:
		//TODO
		break;
	default:
		break;
	}
}


/****************************************************************************
	Nastaveni velikosti fontu a konfigurace knihovny pro tisk timto fontem

	Vstup: 
		font:		velikost pisma

	Výstup:
		FONT_SIZE:	puvodni font

*****************************************************************************/
FONT_SIZE LCD_Set_Font_Size(FONT_SIZE font)
{
	char prevLineHeight = LineHeight;
	FONT_SIZE old = Font;
	Font = font;
	//pro kazdy pripad velikosti fontu nastav vysku a sirku fontu
	switch(font)
	{
		case FONT_MINIMAL:
			CurrentFontHeight = FONT_MINIMAL_HEIGHT;
			if (FONT_MINIMAL_HEIGHT > prevLineHeight)
				LineHeight = FONT_MINIMAL_HEIGHT;
			CurrentFontWidth = FONT_MINIMAL_WIDTH;
			break;
		case FONT_SMALL:
			CurrentFontHeight = FONT_SMALL_HEIGHT;
			if (FONT_SMALL_HEIGHT > prevLineHeight)
				LineHeight = FONT_SMALL_HEIGHT;
			CurrentFontWidth = FONT_SMALL_WIDTH;
			break;
		case FONT_MEDIUM:
			CurrentFontHeight = FONT_MEDIUM_HEIGHT;
			if (FONT_MEDIUM_HEIGHT > prevLineHeight)
				LineHeight = FONT_MEDIUM_HEIGHT;
			CurrentFontWidth = FONT_MEDIUM_WIDTH;
			break;
		case FONT_BIG:
			CurrentFontHeight = FONT_BIG_HEIGHT;
			if (FONT_BIG_HEIGHT > prevLineHeight)
				LineHeight = FONT_BIG_HEIGHT;
			CurrentFontWidth = FONT_BIG_WIDTH;
			break;
		case FONT_HUGE:
			CurrentFontHeight = FONT_HUGE_HEIGHT;
			if (FONT_HUGE_HEIGHT > prevLineHeight)
				LineHeight = FONT_HUGE_HEIGHT;
			CurrentFontWidth = FONT_HUGE_WIDTH;
			break;
		default:
			CurrentFontHeight = CurrentFontHeight;
			WARNING_OUT("Invalid_font");
			break;
	}
	CurrentFontWidth +=(char)(Font+1);
	return old;
}

/****************************************************************************
	Nastaveni barvy fontu

	Vstup: 
		color:		barva

	Výstup:
		neni

*****************************************************************************/
void LCD_Set_Font_Color(RGB_COLORS color)
{
	RGB_DEFAULT_TEXT = color;

}

/****************************************************************************
	Vraci vysku fontu v pixelech

	Vstup: 
		font:		velikost fontu

	Výstup:
		char:		vyska

*****************************************************************************/
char LCD_get_font_height(FONT_SIZE font)
{
	switch (font)
	{
	case FONT_MINIMAL:
		return FONT_MINIMAL_HEIGHT;
	case FONT_SMALL:
		return FONT_SMALL_HEIGHT;
	case FONT_MEDIUM:
		return FONT_MEDIUM_HEIGHT;
	case FONT_BIG:
		return FONT_BIG_HEIGHT;
	case FONT_HUGE:
		return FONT_HUGE_HEIGHT;
	default:
		return 0;
	}
}

/****************************************************************************
	Vraci sirku daneho fontu

	Vstup: 
		font:		velikost fontu

	Výstup:
		char:		sirka znaku

*****************************************************************************/
char LCD_get_font_width(FONT_SIZE font)
{
	switch (font)
	{
	case FONT_MINIMAL:
		return FONT_MINIMAL_WIDTH;
	case FONT_SMALL:
		return FONT_SMALL_WIDTH;
	case FONT_MEDIUM:
		return FONT_MEDIUM_WIDTH;
	case FONT_BIG:
		return FONT_BIG_WIDTH;
	case FONT_HUGE:
		return FONT_HUGE_WIDTH;
	default:
		return 0;
	}
}

/****************************************************************************
	Presun aktualni tiskaci pozica na souradnice x,y

	Vstup: 
		x, y:		souradnice

	Výstup:
		neni

*****************************************************************************/
void LCD_Goto_XY(int x, int y)
{
	txt_X = x%MAX_X;
	txt_Y = y%MAX_Y;
	LineHeight = CurrentFontHeight;
}

/****************************************************************************
	Vymaze okno

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void LCD_ClrScr(void)
{
	for (int x = 0; x < MAX_X; x++)
	{
		for (int y = 0; y < MAX_Y; y++)
		{
			LCD_put_pix(x,y,RGB_BACKGROUND);		
		}
	}
	txt_X = 0;
	txt_Y = 0;
}

/****************************************************************************
	Prechod na novy radek

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
inline void newLine(void)
{
	txt_X = x_min;
	txt_Y += LineHeight;
	LineHeight = CurrentFontHeight;
	if (txt_Y+CurrentFontHeight >= y_max)
		txt_Y = y_min;

}

/****************************************************************************
	Vytiskne prazdny znak

	Vstup: 
		neni

	Výstup:
		neni

*****************************************************************************/
void LCD_putchar_empty(void)
{
		//pokud se znak nevejde pred konec radku
		if(txt_X+CurrentFontWidth >= x_max)
		{
			//úrechod na novy radek
			newLine();
		}
		//posun (znak je jakoby vytisknut)
		txt_X+= CurrentFontWidth;
}

/****************************************************************************
	Vytiskne znak

	Vstup: 
		C:		znak

	Výstup:
		char:	vytisknuty znak

*****************************************************************************/
char LCD_putchar(unsigned char c)
{
	int diff = (LineHeight-CurrentFontHeight) > 0? LineHeight-CurrentFontHeight:0;
	switch(c)
	{
	case '\n':
		newLine();
		break;
	case '\r':
		newLine();
		break;
	case '\0':
		break;
	default:
		//Pokud se znak nevejde pred konec radku, vytiskni ho na novy radek
		if(txt_X+CurrentFontWidth >= x_max)
		{
			newLine();
		}
		//vytiskni znak
		LCD_char(txt_X,txt_Y+diff,c,RGB_DEFAULT_TEXT,Font);
		txt_X+= CurrentFontWidth;
		break;
		
	}
	return c;
}

/****************************************************************************
	Pocitadlo radku

	Vstup: 
		neni

	Výstup:
		char	pocet radku

*****************************************************************************/
char LCD_get_lines_count(void)
{
	char tmp = linesCount;
	linesCount = 0;
	return tmp;
}

/****************************************************************************
	Ulozi stav knihovny v souvislosti s kurzorem

	Vstup: 
		z:		znak

	Výstup:
		neni

*****************************************************************************/
void LCD_Save_cursor_pos(char z)
{
	CursorPosition.x = txt_X;
	CursorPosition.y = txt_Y;
	CursorPosition.C = z;
	CursorPosition.font.size = Font;
	CursorPosition.font.color = RGB_DEFAULT_TEXT;
	CursorPosition.font.bg_color = RGB_BACKGROUND;
	CursorPosition.lineHeight = LineHeight;
	CursorPosition.roi.xA = x_min;
	CursorPosition.roi.yA = y_min;
	CursorPosition.roi.xC = x_max;
	CursorPosition.roi.yC = y_max;
}

/****************************************************************************
	funkce pro tisk retezce s kurzorem

	Vstup: 
		start:		odkud se ma tisknout
		input:		retezec
		curPos:		vytiskne kurzor, pokud je pozice mezi tisknutymi znaky

	Výstup:
		short:		vraci pocet vytisknutych znaku

*****************************************************************************/
short LCD_cprintf(int start, unsigned char * input, int curPos)
{
	short i = 0,j = 0;
	short charsToEnd = 0;
	unsigned char* text = input + start;
	int cursor = curPos - start;
	int newLine = txt_Y;
	if (input == 0)
		return -1;
	while(text[i]!=0)
	{
		//hledej konec nasledujiciho slova
		charsToEnd = 0;
		while(text[i+charsToEnd]!=' ' && text[i+charsToEnd]!='\0' && text[i+charsToEnd]!='\n'&& text[i+charsToEnd]!='\r')
		{
			charsToEnd++;
		}
		charsToEnd++;
		//pokud se slovo nevejde na radek
		if (charsToEnd*CurrentFontWidth+txt_X >= x_max)
		{	
			//prejdi na novy radek
			LCD_putchar('\n');
		}
		else
		{
			//jinak zkontroluj, jestli netisknes moc dolu
			for (j = i; j< i+charsToEnd; j++)
			{
				if (txt_Y > newLine)
					newLine = txt_Y;
				if (txt_Y < newLine)
					return j;
				if (j == cursor)
				{
					//pokud tiskneme na pozici kurzoru, uloz stav knihovny
					LCD_Save_cursor_pos(text[j]);
					//invertuj znaky
					isInverted = 1;
				}
				//vytiskni znaky
				LCD_putchar(text[j]);
				isInverted = 0;
			}
			//posun se v retezci
			i+=charsToEnd;
		}
		//pokud text skoncil, konci
		if (text[i-1] == 0)
			break;
	}
	return i;
}


/****************************************************************************
	Tiskne retezec bez jakehokoli formatovani

	Vstup: 
		text:		text na vytisknuti

	Výstup:
		neni

*****************************************************************************/
void LCD_printf(unsigned char * text)
{
	int i = 0;
	if (text == 0)
		return;
	while(text[i]!=0)
	{
		LCD_putchar(text[i++]);
	}
}


/****************************************************************************
	Vytiskne formatovany text z konzole (neni formatovan)

	Vstup: 
		text:		text
		length:		delka retezce
		curpos:		pozice kurzoru

	Výstup:
		neni

*****************************************************************************/
void LCD_console_printf(FORMATED_CHAR * text, int length, int curpos)
{
	int i = 0;

	for (i = 0; i < length; i++)
	{
		
		if (text[i].dataAttrs & (1 << ATTR_INVERSE))
		{
			isInverted = 1;
		}
		else
		{
			isInverted = 0;
		}
		if (i == curpos)
		{
			LCD_Save_cursor_pos(text[i].data == 0? ' ':text[i].data);
		}
		//preparuje barvu pozadi a znaku
		LCD_Set_BG_Color(Console_color_list[(240&text[i].dataColors)>>4]);
		LCD_Set_Font_Color(Console_color_list[(15&text[i].dataColors)]);
		//tiskne znak
		LCD_putchar(text[i].data == 0? ' ':text[i].data);
	}
	isInverted = 0;
}

/****************************************************************************
	Nastavi Region Of Interrest

	Vstup: 
		R:		obdelnik

	Výstup:
		neni

*****************************************************************************/
void LCD_Set_ROI(TRect * R)
{
	x_min = ((R->xA > 0) && (R->xA < MAX_X))?R->xA:0;
	y_min = ((R->yA > 0) && (R->yA < MAX_Y))?R->yA:0;
	x_max = ((R->xC > x_min) && (R->xC < MAX_X))?R->xC:(MAX_X-1);
	y_max = ((R->yC > y_min) && (R->yC < MAX_Y))?R->yC:(MAX_Y-1);
	txt_X = txt_X < x_min?x_min:txt_X;
	txt_Y = txt_Y < y_min?y_min:txt_Y;
}

/****************************************************************************
	Nastavei barvu pozadi

	Vstup: 
		current:		barva

	Výstup:
		neni

*****************************************************************************/
void LCD_Set_BG_Color(RGB_COLORS current)
{
	RGB_BACKGROUND = current;
}


/****************************************************************************
	Nastavi barvu textu

	Vstup: 
		current:		barva

	Výstup:
		neni

*****************************************************************************/
void LCD_Set_Text_Color(RGB_COLORS current)
{
	RGB_DEFAULT_TEXT = current;
}

/****************************************************************************
	Nastavi font

	Vstup: 
		font:		struktura obsahujici parametry fontu

	Výstup:
		neni

*****************************************************************************/
void LCD_Set_Font(FONT* font)
{
	RGB_DEFAULT_TEXT = font->color;
	RGB_BACKGROUND = font->bg_color;
	LCD_Set_Font_Size(font->size);
}