// ------------------------------------------------------------------------------------ //
//																						//
//	File: Asura_GUIMenu_OnScreenKeyboard.h												//
//																						//
//	Description: Header file the platform independent on screen keyboard				//
//																						//
//	Created: Steve Keen - 23/05/07														//
//																						//
//	Copyright (C) 2007 Rebellion (Derby), All Rights Reserved.							//
// ------------------------------------------------------------------------------------ //

#include "Core/Asura.h"

// This file's header
#include "GUIMenu/Asura_GUIMenu_OnScreenKeyboard.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#ifdef ASURA_USE_GUI_OSK
// Asura
#include "Core/Asura_Timers.h"
#include "Core/Memory/Asura_Mem.h"
#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "GUIMenu/Asura_GUIMenu_Element_Text.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "Interface/Asura_CommandConsole.h"

#include <wchar.h>

// ---------------------------------------------------------------------------------------

bool						Asura_GUIMenu_OnScreenKeyboard::s_bOSKSetup = false;
bool						Asura_GUIMenu_OnScreenKeyboard::s_bUpperCaseOSK;
bool						Asura_GUIMenu_OnScreenKeyboard::s_bEnableEnd = false;
Asura_Char*					Asura_GUIMenu_OnScreenKeyboard::s_pcOSKFilename;
Asura_GUIMenu_OSK_ExitType	Asura_GUIMenu_OnScreenKeyboard::s_eExitType;

Asura_Hash_ID				Asura_GUIMenu_OnScreenKeyboard::s_uLastFocusedMenu;
Asura_UnicodeChar*			Asura_GUIMenu_OnScreenKeyboard::s_pwszInternalTextBuffer;
u_int						Asura_GUIMenu_OnScreenKeyboard::s_uNumInternalTextBufferChars;
Asura_UnicodeChar*			Asura_GUIMenu_OnScreenKeyboard::s_pwszOutputTextBuffer;
u_int						Asura_GUIMenu_OnScreenKeyboard::s_uCursorPos;

u_int						Asura_GUIMenu_OnScreenKeyboard::s_uTextInputFrameNumber;

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::Initialise( Asura_UnicodeChar* wszBuffer, u_int uBufferMaxChars)
{
	Asura_Assert( s_bOSKSetup == false, "Asura_GUIMenu_OnScreenKeyboard::Initialise - OSK is already initialised.");
	Asura_Assert( wszBuffer, "Asura_GUIMenu_OnScreenKeyboard::Initialise - unicode buffer pass is NULL.");
	Asura_Assert( uBufferMaxChars > 0, "Asura_GUIMenu_OnScreenKeyboard::Initialise - uBufferMaxChars == 0");

	if( (s_bOSKSetup == false) && (wszBuffer != NULL) && (uBufferMaxChars > 0))
	{
		Reset();

		ClearLocalVariables();

		Asura_CommandConsole::AddCmd( L"Menu.OSK.ButtonClick", ConsoleCmd_OSKButtonClick, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
		Asura_CommandConsole::AddCmd( L"Menu.OSK.DeleteChar", ConsoleCmd_OSKDeleteChar, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
		Asura_CommandConsole::AddCmd( L"Menu.OSK.ToggleCase", ConsoleCmd_OSKToggleCase, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);

		Asura_CommandConsole::AddVar( L"Menu.OSK.UpperCaseMode", &s_bUpperCaseOSK, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		Asura_CommandConsole::AddVar( L"Menu.OSK.EnableEnd", &s_bEnableEnd, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		ResetOSKFilename();

		s_bOSKSetup = true;

		LoadOSKData();

		s_pwszOutputTextBuffer = wszBuffer;
		s_pwszInternalTextBuffer = new Asura_UnicodeChar[uBufferMaxChars+1];
		Asura_Mem::Set( s_pwszInternalTextBuffer, 0, sizeof( Asura_UnicodeChar) * uBufferMaxChars);

		if( (s_pwszOutputTextBuffer) && (s_pwszOutputTextBuffer[0] != 0x0000))
		{
			wcsncpy( s_pwszInternalTextBuffer, s_pwszOutputTextBuffer, uBufferMaxChars+1);
		}
		UpdateEnableEnd();

		s_uNumInternalTextBufferChars = uBufferMaxChars;

		UpdateTextDisplay();

		s_uLastFocusedMenu = Asura_GUIMenu_System::GetFocusedMenuByID();
		Asura_GUIMenu_System::OpenMenuPage( uASURA_GUIMENU_OSK_SCREEN, true, false );
		Asura_GUIMenu_Menu_Page* pxPage = Asura_GUIMenu_System::GetMenuPageByID( uASURA_GUIMENU_OSK_SCREEN);
		if( pxPage)
		{
			pxPage->Update( 0.05f);
		}

		s_uTextInputFrameNumber = Asura_Timers::GetFrameNumber();
	}
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::Update( void)
{
	if( Asura_GUIMenu_System::IsMenuPageHashActive( uASURA_GUIMENU_OSK_SCREEN))
	{
		UpdateEnableEnd();

		Asura_GUIMenu_Menu_Page* pxPage = Asura_GUIMenu_System::GetMenuPageByID( uASURA_GUIMENU_OSK_SCREEN);
		if( pxPage)
		{
			Asura_GUIMenu_Input xInput;
			xInput.m_uButtonPresses = Asura_GUIMenu_System::Handle_ControllerInput();
			pxPage->ProcessInputActivity( xInput);
		}

		Platform_Update();
	}
}

void Asura_GUIMenu_OnScreenKeyboard::UpdateEnableEnd( void )
{
	if( s_pwszInternalTextBuffer == NULL )
	{
		s_bEnableEnd = false;
		s_uCursorPos = 0;
		return;
	}
	const Asura_UnicodeChar* pwszInternalTextBufferSource = s_pwszInternalTextBuffer;
	Asura_UnicodeChar* pwszInternalTextBufferDest = s_pwszInternalTextBuffer;
	while( pwszInternalTextBufferSource[ 0 ] == ' ' )
	{
		pwszInternalTextBufferSource++;
	}
	while( pwszInternalTextBufferSource[ 0 ] != 0 )
	{
		pwszInternalTextBufferDest[ 0 ] = pwszInternalTextBufferSource[ 0 ];
		pwszInternalTextBufferDest++;
		pwszInternalTextBufferSource++;
	}
	pwszInternalTextBufferDest[ 0 ] = 0;
	s_bEnableEnd = ( s_pwszInternalTextBuffer[ 0 ] != 0 );
	s_uCursorPos = wcslen( s_pwszInternalTextBuffer );
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::Reset( void)
{
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::Shutdown( void)
{
	Asura_Assert( s_bOSKSetup == true, "Asura_GUIMenu_OnScreenKeyboard::Shutdown - OSK was never initialised.");

	if( s_bOSKSetup == true)
	{
		Asura_GUIMenu_System::CloseMenuPage( uASURA_GUIMENU_OSK_SCREEN);
		Asura_GUIMenu_System::DestroyMenuPage( uASURA_GUIMENU_OSK_SCREEN);

		if( Asura_GUIMenu_System::IsMenuPageHashActive( s_uLastFocusedMenu))
		{
			Asura_GUIMenu_System::SetFocusedMenuByID( s_uLastFocusedMenu);
		}

		s_uLastFocusedMenu = ASURA_HASH_ID_UNSET;

		Asura_CommandConsole::RemoveCmd( L"Menu.OSK.ButtonClick");
		Asura_CommandConsole::RemoveCmd( L"Menu.OSK.DeleteChar");
		Asura_CommandConsole::RemoveCmd( L"Menu.OSK.ToggleCase");

		Asura_CommandConsole::RemoveVar( L"Menu.OSK.UpperCaseMode");
		Asura_CommandConsole::RemoveVar( L"Menu.OSK.EnableEnd" );
	
		ClearOSKFilename();

		// should copy the internal buffer to this before clearing
		if( s_pwszOutputTextBuffer && s_pwszInternalTextBuffer)
		{
			wcsncpy( s_pwszOutputTextBuffer, s_pwszInternalTextBuffer, s_uNumInternalTextBufferChars+1);
		}
		s_pwszOutputTextBuffer = NULL;
		
		if( s_pwszInternalTextBuffer)
		{
			delete []s_pwszInternalTextBuffer;
			s_pwszInternalTextBuffer = NULL;
			s_uNumInternalTextBufferChars = 0;
		}
		


		s_bOSKSetup = false;
	}
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::LoadOSKData( const Asura_Char* pcFilenameOverride)
{
	Asura_Assert( s_bOSKSetup == true, "Asura_GUIMenu_OnScreenKeyboard::LoadOSKData - OSK was never initialised.");

	if( Asura_GUIMenu_System::DoesMenuPageExist( uASURA_GUIMENU_OSK_SCREEN) == false)
	{
		Asura_Char szFilename[256];

		if( pcFilenameOverride != NULL)
		{
			// -- set the override filename as default
			SetOSKFilename( pcFilenameOverride);
		}

		Asura_PrintfToBfr( szFilename, "GUIMenu\\OSK." ASURA_GUIMENU_STANDARD_FILE_EXTENSION);
		Asura_ChunkLoading_System::LoadAsuraFile( szFilename);
	}

}

// --------------------------------------------------------------------------------------- 

void Asura_GUIMenu_OnScreenKeyboard::SetOSKFilename( const Asura_Char* pcFilenameOverride)
{
	Asura_Assert( pcFilenameOverride, "Asura_GUIMenu_OnScreenKeyboard::SetOSKFilename - Pointer passed is NULL.");

	if( pcFilenameOverride)
	{
		ClearOSKFilename();

		s_pcOSKFilename = new Asura_Char[ strlen( pcFilenameOverride)+1];
		strcpy( s_pcOSKFilename, pcFilenameOverride);
	}
}

// --------------------------------------------------------------------------------------- 

void Asura_GUIMenu_OnScreenKeyboard::ResetOSKFilename( void)
{
	SetOSKFilename( "GUIMenu\\OSK." ASURA_GUIMENU_STANDARD_FILE_EXTENSION);
}

// --------------------------------------------------------------------------------------- 

void Asura_GUIMenu_OnScreenKeyboard::ClearOSKFilename( void)
{
	if( s_pcOSKFilename)
	{
		delete []s_pcOSKFilename;
		s_pcOSKFilename = NULL;
	}
}

// ---------------------------------------------------------------------------------------

Asura_GUIMenu_OSK_ExitType Asura_GUIMenu_OnScreenKeyboard::GetExitType( void)
{
	return s_eExitType;
}

// --------------------------------------------------------------------------------------- 

bool Asura_GUIMenu_OnScreenKeyboard::ConsoleCmd_OSKButtonClick( const Asura_UnicodeChar* pwCmd, bool bInterrogate, bool bHelp )
{
	if( bHelp )
	{
		Asura_CommandConsole::Printf( L"Menu.OSK.ButtonClick" );
		Asura_CommandConsole::Printf( L"    Notifies about a OSK button click." );
	}
	else if( bInterrogate )
	{
		Asura_CommandConsole::Printf( L"Menu.OSK.ButtonClick" );
		Asura_CommandConsole::Printf( L"    Notifies about a OSK button click." );
		Asura_CommandConsole::Printf( L"    value passed is the 1 or 2 characters." );
		Asura_CommandConsole::Printf( L"    the two chars are the characters for lower then upper case." );
		Asura_CommandConsole::Printf( L"    If only 1 char exists it will use that regardless." );
		Asura_CommandConsole::Printf( L"    END = close menu." );
		Asura_CommandConsole::Printf( L"    SPACE = Space character." );
	}
	else
	{
		if( Asura_Timers::GetFrameNumber() <= s_uTextInputFrameNumber+5)
		{
			return true;
		}

		s_uTextInputFrameNumber = Asura_Timers::GetFrameNumber();

		if( pwCmd)
		{
			Asura_UnicodeChar wToUse = 0;

			// (SB - 21/08/07) s_bEnableEnd checked to make sure the name is valid
			if( !wcscmp( pwCmd, L"END") && s_bEnableEnd)
			{
				// we're done, do some kind of exit thingy
				wToUse = 0;
				s_eExitType = ASURA_GUIMENU_OSK_DONE;
				return true;
			}
			else if( !wcscmp( pwCmd, L"SPACE"))
			{
				wToUse = ' ';
			}
			else
			{
				bool bMultiChar = (wcslen( pwCmd) > 1) ? true : false;
				int iIndex = (int)s_bUpperCaseOSK;

				wToUse = (bMultiChar == true) ? pwCmd[iIndex] : pwCmd[0];
			}

			if(s_pwszInternalTextBuffer)
			{
				if( wcslen( s_pwszInternalTextBuffer) < s_uNumInternalTextBufferChars)
				{
					Asura_UnicodeChar usEnteredChar[16];

					usEnteredChar[0] = wToUse;
					usEnteredChar[1] = 0x0000;

					wcscat( s_pwszInternalTextBuffer, usEnteredChar );
					UpdateEnableEnd();
					UpdateTextDisplay();
				}
			}
		}
	}

	return true;
}

// ---------------------------------------------------------------------------------------

bool Asura_GUIMenu_OnScreenKeyboard::ConsoleCmd_OSKDeleteChar( bool bHelp )
{
	if( bHelp )
	{
		Asura_CommandConsole::Printf( L"Menu.OSK.DeleteChar" );
		Asura_CommandConsole::Printf( L"    Does the equivalent of a backspace (deletes a character)." );
	}
	else
	{
		if( Asura_Timers::GetFrameNumber() <= s_uTextInputFrameNumber+5)
		{
			return true;
		}

		s_uTextInputFrameNumber = Asura_Timers::GetFrameNumber();

		if(s_pwszInternalTextBuffer)
		{
			int iLen = wcslen( s_pwszInternalTextBuffer);
			if( iLen > 0 )
			{
				s_pwszInternalTextBuffer[ iLen - 1 ] = 0x0000;
				UpdateEnableEnd();
				UpdateTextDisplay();
			}
		}
	}

	return true;
}

// ---------------------------------------------------------------------------------------

bool Asura_GUIMenu_OnScreenKeyboard::ConsoleCmd_OSKToggleCase( bool bHelp )
{
	if( bHelp )
	{
		Asura_CommandConsole::Printf( L"Menu.OSK.ToggleCase" );
		Asura_CommandConsole::Printf( L"    Toggles between upper/lower case." );
	}
	else
	{
		if( Asura_Timers::GetFrameNumber() <= s_uTextInputFrameNumber+5)
		{
			return true;
		}
		
		s_uTextInputFrameNumber = Asura_Timers::GetFrameNumber();

		s_bUpperCaseOSK ^= 1;

	}

	return true;
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::UpdateTextDisplay( void)
{
	Asura_GUIMenu_Menu_Page* pxPage = Asura_GUIMenu_System::GetMenuPageByID( uASURA_GUIMENU_OSK_SCREEN);
	if( pxPage)
	{
		Asura_GUIMenu_Root* pxRootItem = pxPage->FindContainerObject( uASURA_GUIMENU_OSK_TEXT_ENTRY);
		if( pxRootItem && pxRootItem->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT)
		{
			Asura_GUIMenu_Element_Text* pxText = static_cast<Asura_GUIMenu_Element_Text*>(pxRootItem);
			pxText->SetText( s_pwszInternalTextBuffer);
		}
	}
}

// ---------------------------------------------------------------------------------------

void Asura_GUIMenu_OnScreenKeyboard::ClearLocalVariables( void)
{
	s_bOSKSetup				= false;

	s_bUpperCaseOSK			= false;
	s_pcOSKFilename			= NULL;

	s_eExitType				= ASURA_GUIMENU_OSK_NOEXIT;

	s_uLastFocusedMenu		= ASURA_HASH_ID_UNSET;

	s_pwszInternalTextBuffer	= NULL;
	s_uNumInternalTextBufferChars = 0;
	s_uCursorPos				= 0;

	s_pwszOutputTextBuffer		= NULL;

}

// --------------------------------------------------------------------------------------- 
#endif // ASURA_USE_GUI_OSK
#endif // ASURA_USE_GUI_MENU_SYSTEM
