/*********************************************************************
*	TextBox
*	SOURCE FILE
*	Autor:	Michal Jirouš
*	Datum: 2.7.2008
*	Soubor: textbox.cpp
*	Popis: Textove pole s animovanym posouvanim textu. Umoznuje vkladat
*			a mazat text pomoci klavesnice.
**********************************************************************/

#include "gfg.h"
#include "mathematic.h"
//inicializace
TextBox::TextBox( float w, float h )
{
	if( h < GFG_TEXT_BOX_MIN_HEIGHT ) 
		h = GFG_TEXT_BOX_MIN_HEIGHT;

	baseInit( w, h );
	setPaddingLeft( GFG_STANDARD_PADDING );
	setPaddingRight( GFG_STANDARD_PADDING );
	m_iCursorPos = 0;
	m_iCursorIndex = 0;
	m_fTranslate = 0;
	m_fAnimateTranslation = m_fTranslate;
	setCaption("");
	m_bCursorVisible = true;
	m_iCursorFlickerTime = GFG_TEXTBOX_CURSOR_FLICKER_TIME;
	m_iLastFlickerTime = 0;
	m_iObjectType = GFG_TEXTBOX;
	m_ColorBackGround = GFG_COLOR_TEXTBOX_TEXT;
	m_iMaxLenght = 0;
}

void TextBox::setMaxLenght( size_t lenght )
{
	if( lenght > GFG_TEXTBOX_MAX_POSIBLE_LENGHT )
		return;

	if( getCaption().length() > lenght )
		setCaption( getCaption().substr(0, lenght ) );
	m_iMaxLenght = lenght;

}


void TextBox::draw( ScissorBox &scissorBox )
{
	if( !m_bVisible )
		return;

	glPushAttrib( GL_ENABLE_BIT | GL_CURRENT_BIT | GL_SCISSOR_BIT );
	glEnable(GL_BLEND);
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glPushMatrix();
	float offset = m_fWidth - m_fWidth * GFG_OUTLINE_MULTIPLICATOR;
	if( m_bMouseOver || m_bFocused )
	{
		glBegin( GL_LINES );
			setColor( GFG_COLOR_TEXTBOX_END_LINE_MOUSEOVER );
			glVertex2f( m_fGlobalXpos, m_fGlobalYpos );
			setColor( GFG_COLOR_TEXTBOX_START_LINE_MOUSEOVER );
			glVertex2f( m_fGlobalXpos + m_fWidth - offset , m_fGlobalYpos );
		glEnd();
		glBegin( GL_LINES );
			setColor( GFG_COLOR_TEXTBOX_END_LINE_MOUSEOVER );
			glVertex2f( m_fGlobalXpos + m_fWidth, m_fGlobalYpos + m_fHeight );
			setColor( GFG_COLOR_TEXTBOX_START_LINE_MOUSEOVER );
			glVertex2f( m_fGlobalXpos + offset  , m_fGlobalYpos + m_fHeight );
		glEnd();
	}
	else
	{
		glBegin( GL_LINES );
			setColor( GFG_COLOR_SKIN_END_LINE );
			glVertex2f( m_fGlobalXpos, m_fGlobalYpos );
			setColor( GFG_COLOR_SKIN_START_LINE );
			glVertex2f( m_fGlobalXpos + m_fWidth - offset, m_fGlobalYpos );
		glEnd();
		glBegin( GL_LINES );
			setColor( GFG_COLOR_SKIN_END_LINE );
			glVertex2f( m_fGlobalXpos + m_fWidth , m_fGlobalYpos + m_fHeight );
			setColor( GFG_COLOR_SKIN_START_LINE );
			glVertex2f( m_fGlobalXpos + offset , m_fGlobalYpos + m_fHeight );

		glEnd();
	}

		
	ScissorBox intersected = m_ScissorBox.intersection( scissorBox );
	glScissor( (GLint)intersected.x, (GLint)intersected.y, (GLint)(intersected.w+1), (GLint)intersected.h );
	
	//posunuti dle animace
	glTranslatef( -m_fAnimateTranslation, 0, 0 );

	setColor( m_ColorBackGround );
	//vykresleni textu
	m_dsCaption.draw( m_ScissorBox.x, m_ScissorBox.y + m_ScissorBox.h/2 );
	
	if( m_bFocused && m_bCursorVisible && m_bEnabled && !m_bTemporaryDisabled)
	{	//a kurzoru
		setColor( GFG_COLOR_TEXTBOX_CURSOR );	
		glBegin( GL_LINES );
			glVertex2f( m_ScissorBox.x + m_iCursorPos, m_ScissorBox.y);
			glVertex2f( m_ScissorBox.x + m_iCursorPos, m_ScissorBox.y + m_ScissorBox.h);
		glEnd();
	}
	glPopMatrix();
	glPopAttrib();

}

bool TextBox::inputController( int type, float x, float y, int param1, int param2 )
{
	if( !m_bVisible || !m_bEnabled )
		return false;

	Font *pFont = m_dsCaption.m_pFont;
	if( m_dsCaption.empty() )
		return false;
	fontLibrary::DString::TextLine *line = &m_dsCaption.m_pLineList->front();
	unsigned char cCharacter = (unsigned char)param1;

	if( type == GFG_GOT_FOCUS )
		m_bFocused = true;
	else if( type == GFG_LOST_FOCUS )
		m_bFocused = false;
	else if( type & GFG_KEYBOARD_DOWN )
	{
		if( !pFont )
			return false;

		switch( param1 )
		{
			case GFG_KEY_BACKSPACE:	//klavesa BACKSPACE
				if( m_iCursorIndex > 0 )
				{
					//sirka pismena rped kurzorem
					int width = pFont->getCharacterWidth( line->m_sText.at( m_iCursorIndex - 1 ) );
					line->width -= width;
					
					//odstraneni pismene a prekompilovani
					line->m_sText = line->m_sText.substr(0, m_iCursorIndex - 1 ) + line->m_sText.substr( m_iCursorIndex, line->m_sText.length() );
					line->compile( FONT_ALIGN_LEFT, pFont );
					m_iCursorIndex--;
					m_iCursorPos -= width;
					m_bCursorVisible = true;
					m_iLastFlickerTime = clock();
					update();	//translation update
				}
				return true;
			case GFG_KEY_DELETE:	//klavesa DEL
				if( m_iCursorIndex < line->m_sText.length() )
				{
					//sirka pismene za kurzorem
					int width = pFont->getCharacterWidth( line->m_sText.at( m_iCursorIndex  ) );
					line->width -= width;
					
					//odstraneni pismene a prekompilovani
					line->m_sText = line->m_sText.substr(0, m_iCursorIndex  ) + line->m_sText.substr( m_iCursorIndex + 1, line->m_sText.length() );
					line->compile( FONT_ALIGN_LEFT, pFont );
					m_bCursorVisible = true;
					m_iLastFlickerTime = clock();
					update();	//translation update
				}
				return true;
			case GFG_KEY_ENTER:	//TAB enter apod. ignorujeme
			case GFG_KEY_TAB:
			case '\n':
				break;
			default:	//normalni text
				//sirka pismene
				if( !m_iMaxLenght || line->m_sText.length() < m_iMaxLenght )
				{
					int iCharacterWidth = pFont->getCharacterWidth( cCharacter );
					
					string character;
					character += cCharacter;
					m_iCursorIndex++;
					m_iCursorPos += iCharacterWidth;
					
					//pridani pismene za kurzor a zkompilovani
					line->width += iCharacterWidth;
					line->m_sText.insert( m_iCursorIndex - 1, character );
					line->compile( FONT_ALIGN_LEFT, pFont );
					m_bCursorVisible = true;
					m_iLastFlickerTime = clock();
					update();	//translation update
				}
				return true;
		}
	}
	else if( type & GFG_SPECIAL_KEY_DOWN )
	{
		if( !pFont )
			return false;
		if( param1 == GFG_KEY_LEFT )	//posun kurzoru doleva
		{
			if( m_iCursorIndex > 0 )
			{
				int width = pFont->getCharacterWidth( line->m_sText.at( m_iCursorIndex - 1 ) );
				m_iCursorPos -= width;
				m_iCursorIndex--;
				m_bCursorVisible = true;
				m_iLastFlickerTime = clock();
				update();	//translation update
			}
			return true;
		}
		else if( param1 == GFG_KEY_RIGHT )	//posun kurzoru doprava
		{
			if( m_iCursorIndex < line->m_sText.length() )
			{
				int width = pFont->getCharacterWidth( line->m_sText.at( m_iCursorIndex ) );
				m_iCursorPos += width;
				m_iCursorIndex++;
				m_bCursorVisible = true;
				m_iLastFlickerTime = clock();
				update();	//translation update
			}
			return true;
		}
	}
	else if( type & GFG_MOUSE_BUTTON && param2 == GFG_DOWN)	//kliknuti mysi
	{
		if( !pFont )
			return false;
		bool onArea = checkMouseArea( x, y );
		if( onArea )
		{
			x += m_fTranslate;	//uprava dle posunuti
			//glutSetCursor(GLUT_CURSOR_TEXT);
			int width = 0;
			for( size_t i = 0; i < line->m_sText.size(); i++ )
			{
				//je treba nalezt pismeno, na ktere uzivatel klikl
				int iCharacterWidth = pFont->getCharacterWidth( (unsigned char)line->m_sText.at( i ) );
				if( x < m_ScissorBox.x + width + iCharacterWidth )
				{
					//kdyz vim pismeno, tak jeste musim rozhodnout, jestli dam
					//kurzor za nebo pred nej..a to podle poloviny sirky pismena
					float iCurrentWidth = m_ScissorBox.x + width + iCharacterWidth / 2;
					if( x <= iCurrentWidth )
					{
						m_iCursorIndex = i ;
						m_iCursorPos = width;
					}
					else
					{
						m_iCursorIndex = i + 1;
						m_iCursorPos = width + iCharacterWidth;
					}
					m_bCursorVisible = true;
					m_iLastFlickerTime = clock();
					update();
					return true;
				}
				width += iCharacterWidth;
			}
			
			//jinak nastavim kurzor za posledni pismeno
			m_iCursorIndex = line->m_sText.length();
			m_iCursorPos = width;
			m_bCursorVisible = true;
			m_iLastFlickerTime = clock();
			
			return true;
		}
	}
	else if( type & GFG_MOUSE_OVER )
	{
		bool onArea = checkMouseArea( x, y ) && param1;
		m_bMouseOver = onArea;
		//if( onArea )
		//	glutSetCursor(GLUT_CURSOR_TEXT);

	}	

	return false;
}


void TextBox::setFont( Font *pFont )
{
	if( pFont )
	{
		setCaption( getCaption(), pFont );
	}
}

//nastaveni textu
void TextBox::setCaption( string text )
{
	textCorrection( text );
	m_dsCaption = fontLibrary::DString( text, "REGULAR", FONT_ALIGN_LEFT );
	resetCursor();
}

void TextBox::setCaption( string text, string font )
{
	textCorrection( text );
	m_dsCaption = fontLibrary::DString( text, font, FONT_ALIGN_LEFT );
	resetCursor();
}

void TextBox::setCaption( string text, Font *font )
{
	if( font )
	{
		textCorrection( text );
		m_dsCaption = fontLibrary::DString( text, font, FONT_ALIGN_LEFT );
		resetCursor();
	}
}

//uprava textu...lze pouzit jen prvni radek
void TextBox::textCorrection( string &text )
{
	size_t i = text.find_first_of( '\n' );

	if( i < text.length() )
		text = text.substr(i);

	if( text.length() > m_iMaxLenght )
		text = text.substr(0,m_iMaxLenght);
}

//reset kurzoru...na konec textu
void TextBox::resetCursor()
{
	if( m_dsCaption.m_pLineList && !m_dsCaption.m_pLineList->empty() )
	{
		m_iCursorPos = m_dsCaption.m_pLineList->front().width;
		m_iCursorIndex = m_dsCaption.m_pLineList->front().m_sText.length();
	}
}

string TextBox::getCaption()
{
	if( !m_dsCaption.empty() )
		return m_dsCaption.m_pLineList->front().m_sText;
	else
		return EMPTY_STRING;
}

//beh - zde se provadi animace blikani kurzoru a pohyb kurzoru
void TextBox::run()
{
	if( m_bFocused )
	{
		if( m_iLastFlickerTime + m_iCursorFlickerTime < clock() )
		{
			m_bCursorVisible ^= 1;
			m_iLastFlickerTime = clock();
		}
	}

	if( m_fAnimateTranslation < m_fTranslate)
		m_fAnimateTranslation += getFromRange( 6.0f, 0.0f, m_fTranslate - m_fAnimateTranslation );
	else if( m_fAnimateTranslation > m_fTranslate )
		m_fAnimateTranslation -= getFromRange( 6.0f, 0.0f, m_fAnimateTranslation - m_fTranslate );
}

void TextBox::onScissorBoxResize( float w_offset, float h_offset )
{
	update();
}

void TextBox::update()
{
	if( m_dsCaption.empty() )
		return;
	float fCenter = m_ScissorBox.x + m_ScissorBox.w / 2.0f;
	
	fontLibrary::DString::TextLine *line = &m_dsCaption.m_pLineList->front();
	//if( line->width < m_ScissorBox.w / 2.0f )
	//	return;

	//if( m_iCursorPos + m_ScissorBox.w / 2.0f < line->width && m_iCursorPos - m_ScissorBox.w / 2.0f > 0)
	//{
		m_fTranslate = getFromRange( (float)m_iCursorPos - m_ScissorBox.w / 2.0f, 0.0f, line->width - m_ScissorBox.w);
	//	return;
	//}


	if( (float)m_iCursorPos - m_fTranslate > m_ScissorBox.w )
		m_fTranslate = (float)m_iCursorPos - m_ScissorBox.w  ;
	else if( (float)m_iCursorPos - m_fTranslate < 0 )
		m_fTranslate = (float)m_iCursorPos;
}

//nastaveni textu ( jedne radky )
void TextBox::setCaption( fontLibrary::DString &str )
{
	if( !str.empty() )
	{
		setCaption( str.m_pLineList->front().m_sText  );
	}

}

//nastaveni textu ( jedne radky )
void TextBox::setTextLine( fontLibrary::DString::TextLine &line )
{
	setCaption( line.m_sText );
}
