// ------------------------------------------------------------------------------------ //
//																						//
//	File: Asura_GUIMenu_System.cpp														//
//																						//
//	Description: Game API for data driven menu system and HUD							//
//																						//
//	Created: Steve Keen - 9/11/06														//
//																						//
//	Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.							//
// ------------------------------------------------------------------------------------ //

#include "Core/Asura.h"

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

#ifdef ASURA_USE_GUI_MENU_SYSTEM

#ifndef ASURA_SUPPORT_COMMAND_CONSOLE
#error Asura_GUIMenu_System now requires the command console.
#endif

// Asura
#include "Camera/Asura_Camera.h"
#include "ChunkSystem/Asura_Chunk_Loaders.h"
#include "Core/Asura_Graph.h"
#include "Core/Asura_HashedLocalisedText.h"
#include "Core/Asura_LocalisedText.h"
#include "Core/Asura_Maths.h"
#include "Core/Asura_String.h"
#include "Core/Asura_Timers.h"
#include "Core/Memory/Asura_Mem.h"
#include "Debugging/Asura_DebugText.h"
#include "Debugging/Asura_Debug_Timers.h"
#include "Debugging/Asura_Logfile.h"

#include "GUIMenu/Asura_GUIMenu_Animator.h"
#include "GUIMenu/Asura_GUIMenu_Audio.h"
#include "GUIMenu/Asura_GUIMenu_Element_Animation.h"
#include "GUIMenu/Asura_GUIMenu_Element_FMV.h"
#include "GUIMenu/Asura_GUIMenu_Element_Path.h"
#include "GUIMenu/Asura_GUIMenu_Element_StatusText.h"
#include "GUIMenu/Asura_GUIMenu_Message.h"
#include "GUIMenu/Asura_GUIMenu_MessagePump.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_Widget_AnimatingImage.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Base.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Button.h"
#include "GUIMenu/Asura_GUIMenu_Widget_CheckBox.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Group.h"
#include "GUIMenu/Asura_GUIMenu_Widget_ListBox.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Numeric.h"
#include "GUIMenu/Asura_GUIMenu_Widget_ProgressBar.h"
#include "GUIMenu/Asura_GUIMenu_Widget_Slider.h"
#include "GUIMenu/Asura_GUIMenu_Widget_TextBox.h"
#include "GUIMenu/Asura_GUIMenu_Widget_TextListBox.h"
#include "GUIMenu/Asura_Profiling_GUIMenu.h"
#ifdef ASURA_USE_GUI_MODAL_SYSTEM
#include "GUIMenu/Asura_GUIModal_System.h"
#endif
#ifdef ASURA_USE_CONTROLMAP_MANAGER
#include "Input/Asura_ControlManager.h"
#endif // ASURA_USE_CONTROLMAP_MANAGER
#include "Input/Asura_ControlMap.h"
#include "Interface/Asura_CommandConsole.h"
#include "Interface/Asura_Cursor.h"
#include "Network/Asura_Network.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Viewport.h"
#include "Sound/Asura_Dynamic_Music_System.h"

// Tools
#ifdef ASURA_TOOLS
#include "GUIMenu/Tools_GUIMenu_PreviewOverlay.h"
#include "GUIMenu/Tools_GUIMenu_System.h"
#include "GUIMenu/Tools_Mode_GUIMenu.h"
#include "Misc/Tools_Timed_Messages.h"
#include "PC/FileSystem/Tools_FileSystem.h"
#include "Tools_System.h"
#endif

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

bool						Asura_GUIMenu_System::s_bInitialised = false;
bool						Asura_GUIMenu_System::s_bLoadGenericAudioDataDuringInitialisation = true;

bool						Asura_GUIMenu_System::s_bShouldUpdateControls = true;
Asura_ControlMap*			Asura_GUIMenu_System::s_pxMenuControlMaps;
u_int						Asura_GUIMenu_System::s_uControlMapIndexInUse;

//Asura_ControlMap			Asura_GUIMenu_System::s_xMenuControlMap;
bool						Asura_GUIMenu_System::s_bControlMapOnStack;
u_int						Asura_GUIMenu_System::s_uTextInputID;
float						Asura_GUIMenu_System::s_fLastHAxisValue = 0.0f;
float						Asura_GUIMenu_System::s_fLastVAxisValue = 0.0f;

u_int						Asura_GUIMenu_System::s_uButtonInput;
Asura_GUIMenu_Menu_Page*	Asura_GUIMenu_System::s_apxMenuPages[ASURA_GUIMENU_MAX_MENU_PAGES];
u_char						Asura_GUIMenu_System::s_aucMenuPageUsageFlags[ASURA_GUIMENU_MAX_MENU_PAGES];
u_int						Asura_GUIMenu_System::s_uMenuPageCount = 0;
int							Asura_GUIMenu_System::s_iSelectedMenuIndex = -1;
u_int						Asura_GUIMenu_System::s_uNumMenusFadingOut;
Asura_GUIMenu_Menu_Page*	Asura_GUIMenu_System::s_apxMenuPagesFadingOut[ASURA_GUIMENU_MAX_MENU_PAGES_FADING_OUT];
Asura_GUIMenu_System::ExternMessageOverrideCallbackFunction* Asura_GUIMenu_System::s_pfMessageCallback = NULL;

Asura_String64				Asura_GUIMenu_System::s_xUniqueName;
u_int						Asura_GUIMenu_System::s_uUniqueMenuNumber;
u_int						Asura_GUIMenu_System::s_uUniqueWidgetNumber;
u_int						Asura_GUIMenu_System::s_uUniqueElementNumber;

int			 				Asura_GUIMenu_System::s_iConsoleVar_ActiveWidget;
int			 				Asura_GUIMenu_System::s_iConsoleVar_LastActiveWidget;
int			 				Asura_GUIMenu_System::s_iConsoleVar_FocusedPage;

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
bool						Asura_GUIMenu_System::s_bRenderDebugInfo = false;
bool						Asura_GUIMenu_System::s_bRenderDebugBounds = false;
bool						Asura_GUIMenu_System::s_bRenderSafetyBorder = false;
#endif // ASURA_DEBUG_VARIABLE_SYSTEM

bool						Asura_GUIMenu_System::s_bUseCursor = false;
bool						Asura_GUIMenu_System::s_bAllowCursorDeselect = false;

bool						Asura_GUIMenu_System::s_bAutoMenuSizesSet = false;
Asura_Vector_2				Asura_GUIMenu_System::s_xAutoMenuSizeDims;
Asura_Vector_2				Asura_GUIMenu_System::s_xAutoMenuOffsetDims( 0.0f, 0.0f );
Asura_Vector_2				Asura_GUIMenu_System::s_xVirtualResolution( 0.0f, 0.0f );
Asura_Vector_2				Asura_GUIMenu_System::s_xVirtualScreenScale( 0.0f, 0.0f );

int							Asura_GUIMenu_System::s_iLanguage;
bool						Asura_GUIMenu_System::s_bAllowBack;

#ifdef ASURA_TOOLS
Asura_TemplateHashTree<Asura_String> Asura_GUIMenu_System::s_xMenuTextFilenames;
#endif

#ifdef ASURA_TOOLS

Asura_Char*					Asura_GUIMenu_System::s_pcToolControlNames[ASURA_GUIMENU_CONTROL_MAX];
#endif

#ifdef ASURA_GUIMENU_ENABLE_METRICS
Asura_GUIMenu_Metrics		Asura_GUIMenu_System::s_xMetrics;
bool						Asura_GUIMenu_System::s_bUpdateMetrics;	
#endif
Asura_Hash_ID				Asura_GUIMenu_System::s_uPageHandlingInput = ASURA_HASH_ID_UNSET;

Asura_TemplateHashTree<Asura_GUIMenu_Menu_Widget_Match>	Asura_GUIMenu_System::s_xFastWidgetLookUpTree;
const Asura_GUIMenu_Menu_Page* Asura_GUIMenu_System::s_pxLoadingMenu = 0;
Asura_GUIMenu_System::ProjectCallbackFunction* Asura_GUIMenu_System::s_pfnProjectPostInitialiseCallback(NULL);
Asura_GUIMenu_System::ProjectCallbackFunction* Asura_GUIMenu_System::s_pfnProjectPreResetCallback(NULL);
Asura_GUIMenu_System::ProjectCallbackFunction* Asura_GUIMenu_System::s_pfnProjectPreShutdownCallback(NULL);

float Asura_GUIMenu_System::s_fMenuSystemSpeed = 1.0f;

bool Asura_GUIMenu_System::s_bRenderWidescreenBarsThisFrame = false;

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

void Asura_GUIMenu_System::Initialise( void)
{	
	ASURA_CPU_PROFILE_SCOPED_TIMER( "Asura_GUIMenu_System::Initialise" );

	// KOR - not a problem?
	//Asura_Assert(s_xMenuTextFilenames.GetNumberOfNodes() == 0, "Already have menu text filenames?");

	//Load the text here for now. This will almost certainly have to be moved to project code , since it unlikely
	//that the correct language will have been selected by this point.
	//RAR 13/02/2007
	// (MH - 27.02.2007) moved it to before Tools_GUIMenu_System::Initialise() so that text is available when loading.
	LoadMenuText("Menu\\Menu", uASURA_HASHEDTEXTPAGE_MENU);

	ASURA_GUIMENU_PROFILE_INITIALISE();

	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__GUIMENU_SYSTEM,sizeof(Asura_GUIMenu_System));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__GUIMENU_ROOT,sizeof(Asura_GUIMenu_Root));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__GUIMENU_PAGE,sizeof(Asura_GUIMenu_Menu_Page));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_ANIMATION,sizeof(Asura_GUIMenu_Element_Animation));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_BASE,sizeof(Asura_GUIMenu_Element_Base));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_IMAGE,sizeof(Asura_GUIMenu_Element_Image));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_PATH,sizeof(Asura_GUIMenu_Element_Path));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_STATUSTEXT,sizeof(Asura_GUIMenu_Element_StatusText));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_TEXT,sizeof(Asura_GUIMenu_Element_Text));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__ELEMENT_FMV,sizeof(Asura_GUIMenu_Element_FMV));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_ANIMATINGIMAGE,sizeof(Asura_GUIMenu_Widget_AnimatingImage));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_BASE,sizeof(Asura_GUIMenu_Widget_Base));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_BUTTON,sizeof(Asura_GUIMenu_Widget_Button));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_CHECKBOX,sizeof(Asura_GUIMenu_Widget_CheckBox));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_GROUP,sizeof(Asura_GUIMenu_Widget_Group));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_LISTBOX,sizeof(Asura_GUIMenu_Widget_ListBox));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_NUMERIC,sizeof(Asura_GUIMenu_Widget_Numeric));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_PROGRESSBAR,sizeof(Asura_GUIMenu_Widget_ProgressBar));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_SLIDER,sizeof(Asura_GUIMenu_Widget_Slider));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_TEXTBOX,sizeof(Asura_GUIMenu_Widget_TextBox));
	ASURA_GUIMENU_PROFILE_CLASSSIZE(ASURA_GUIMENU_COUNTER__WIDGET_TEXTLISTBOX,sizeof(Asura_GUIMenu_Widget_TextListBox));

	// GUIMenu system is a static class so just count it one. It has not constructor
	ASURA_GUIMENU_PROFILE_COUNTINSTANCE(ASURA_GUIMENU_COUNTER__GUIMENU_SYSTEM);

	Asura_GUIMenu_Animator_Storage::Initialise();

	Asura_GUIMenu_Audio::Initialise();
	if(s_bLoadGenericAudioDataDuringInitialisation)
	{
		LoadGenericAudioData();
	}

	Reset();

	ClearLocalVariables();

	Asura_GUIMenu_FMV_System::Initialise();

#if defined(ASURA_TOOLS)
	Tools_GUIMenu_System::Initialise();
#endif

#ifdef ASURA_USE_GUI_MODAL_SYSTEM
	Asura_GUIModal_System::Initialise();
#endif

	Asura_GUIMenu_MessagePump::Initialise();

	Platform_InitInputMappings();

	//Add console vars
	Asura_CommandConsole::AddVar( L"GUIMenu.ActiveWidget",  &s_iConsoleVar_ActiveWidget, INT_MIN, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
	Asura_CommandConsole::AddVar( L"GUIMenu.LastActiveWidget",  &s_iConsoleVar_LastActiveWidget, INT_MIN, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
	Asura_CommandConsole::AddVar( L"GUIMenu.FocusedPage",  &s_iConsoleVar_FocusedPage, INT_MIN, INT_MAX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
	Asura_CommandConsole::AddCmd( L"GUIMenu.OpenPage", &ConsoleCmd_OpenMenuPage, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::AddCmd( L"GUIMenu.ChangePage", &ConsoleCmd_ChangeMenuPage, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::AddCmd( L"GUIMenu.PlayMusicTrack", &ConsoleCmd_PlayMusicTrack, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::AddCmd( L"GUIMenu.StopMusic", &ConsoleCmd_StopMusic, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);

	Asura_CommandConsole::AddVar( L"GUIMenu.Lang",  &s_iLanguage, ASURA_LT_L_ENGLISH, ASURA_LT_L_NUM_LANGUAGES-1, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::MakeVarReadOnly( L"GUIMenu.Lang");
	Asura_CommandConsole::AddVar( L"GUIMenu.AllowBack",  &s_bAllowBack, Asura_CommandConsole::REMOVE_AT_SHUTDOWN);
	Asura_CommandConsole::MakeVarReadOnly( L"GUIMenu.AllowBack");

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	Asura_CommandConsole::AddVar( L"GUIMenu.RenderDebugInfo",  &s_bRenderDebugInfo, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
	Asura_CommandConsole::AddVar( L"GUIMenu.RenderDebugBounds",  &s_bRenderDebugBounds, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
	Asura_CommandConsole::AddVar( L"GUIMenu.RenderSafetyBorder",  &s_bRenderSafetyBorder, Asura_CommandConsole::REMOVE_AT_SHUTDOWN  );
#endif // ASURA_DEBUG_VARIABLE_SYSTEM


	s_xFastWidgetLookUpTree.Reset();

	if( s_pfnProjectPostInitialiseCallback )
	{
		(*s_pfnProjectPostInitialiseCallback)();
	}

	s_bInitialised = true;
}

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

void Asura_GUIMenu_System::Reset( void)
{
	Asura_GUIMenu_FMV_System::Reset();

	if( s_pfnProjectPreResetCallback )
	{
		(*s_pfnProjectPreResetCallback)();
	}
	
	Asura_GUIMenu_MessagePump::Reset();
	ReleaseAllMenuPages();
	Asura_GUIMenu_Animator_Storage::Reset();
#ifdef ASURA_USE_GUI_MODAL_SYSTEM
	Asura_GUIModal_System::Reset();
#endif

	s_xFastWidgetLookUpTree.Reset();
}

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

void Asura_GUIMenu_System::Shutdown( void)
{
	if( s_pfnProjectPreShutdownCallback )
	{
		(*s_pfnProjectPreShutdownCallback)();
	}

	Asura_GUIMenu_FMV_System::Shutdown();

	s_xFastWidgetLookUpTree.Reset();

#ifdef ASURA_TOOLS
	s_xMenuTextFilenames.Reset();
#endif

	Platform_ShutdownInputMappings();

	ReleaseAllMenuPages();
#ifdef ASURA_USE_GUI_MODAL_SYSTEM
	Asura_GUIModal_System::Shutdown();
#endif
	Asura_GUIMenu_Animator_Storage::Shutdown();
	Asura_GUIMenu_Audio::Shutdown();

	Asura_GUIMenu_MessagePump::Shutdown();

#ifdef ASURA_TOOLS
	Tools_GUIMenu_System::Shutdown();

	u_int u;

	for( u=0; u<ASURA_GUIMENU_CONTROL_MAX; u++)
	{
		if( s_pcToolControlNames[u] != NULL)
		{
			delete []s_pcToolControlNames[u];
			s_pcToolControlNames[u] = NULL;
		}
	}
#endif

	s_bInitialised = false;
}

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

void Asura_GUIMenu_System::Update( void)
{
	ASURA_GUIMENU_PROFILE_START_SECTION(ASURA_GUIMENU_PROFILE__UPDATE);
	ASURA_GUIMENU_PROFILE_START_TASK(ASURA_GUIMENU_PROFILE__GUIMENU_SYSTEM);

	Asura_GUIMenu_FMV_System::Update();

	s_uPageHandlingInput = ASURA_HASH_ID_UNSET;
	s_bAllowBack = false;

	if( s_iSelectedMenuIndex != -1)
	{
		if( s_apxMenuPages[s_iSelectedMenuIndex])
		{
			s_bAllowBack = s_apxMenuPages[s_iSelectedMenuIndex]->CanBackOutOfThisMenu();
		}
	}

	s_uButtonInput = (Platform_ShouldUpdateControls() && s_bShouldUpdateControls) ? Handle_ControllerInput() : 0;
	Handle_MenuPageUpdate( s_uButtonInput );

	if (!s_bShouldUpdateControls) s_bShouldUpdateControls = true;

	ASURA_GUIMENU_PROFILE_END_TASK();
	ASURA_GUIMENU_PROFILE_END_SECTION();
}

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

void Asura_GUIMenu_System::Render( void)
{
	ASURA_GUIMENU_PROFILE_START_SECTION(ASURA_GUIMENU_PROFILE__RENDER);
	ASURA_GUIMENU_PROFILE_START_TASK(ASURA_GUIMENU_PROFILE__GUIMENU_SYSTEM);

	s_bRenderWidescreenBarsThisFrame = false;

	// Update the global time for the animation sequence system.
	Asura_GUIMenu_Animator_Sequence::Update();

	Platform_BeginRender();
	{
#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
#if defined(ASURA_USE_DEBUG_TEXT)
		// TODO - consolevar for render debug info
		if(s_bRenderDebugInfo)
		{
			u_int uRow = 12;
			u_int uCol = 3;
			Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Menu page count: %u", s_uMenuPageCount));
			Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Selected menu: %i", s_iSelectedMenuIndex));
			for( int i=0; i<(int)s_uMenuPageCount; i++)
			{
				if( IsMenuPageActive( i) )
				{
#ifdef ASURA_GUIMENU_STORE_NAMES
					const char* szName = s_apxMenuPages[i]->GetNameAsChar();
					Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Active menu %i: %s", i, szName));
#else 
					Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Active menu %i: 0x%x", i, s_apxMenuPages[i]->GetID()));
#endif 
				}
			}

			uRow++;
			Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Number menus fading out: %u", s_uNumMenusFadingOut));
			for (u_int u = 0; u < s_uNumMenusFadingOut; ++u)
			{
#ifdef ASURA_GUIMENU_STORE_NAMES
				const char* szName = s_apxMenuPages[u]->GetNameAsChar();
				Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Fading out menu %u: %s", u, szName));
#else 			
				Asura_DebugTextPrint(( uCol, uRow++, 0xffffffff, 0, "Fading out menu %u: 0x%x", u, s_apxMenuPagesFadingOut[u]->GetID()));
#endif 
			}
		}
#endif	// defined(ASURA_USE_DEBUG_TEXT)
#endif // ASURA_DEBUG_VARIABLE_SYSTEM

		if (Platform_ShouldRenderMenuPages())
		{
			for( int i=0; i<(int)s_uMenuPageCount; i++)
			{
				if( (IsMenuPageActive( i) == true) && (!s_apxMenuPages[i]->IsFadingOut() ) && (i != s_iSelectedMenuIndex))
				{
					s_apxMenuPages[i]->Render( 0xffffffff);	// parameter is ignored
					Asura_Render::FlushDisplay();
#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
					if( s_bRenderDebugBounds)
					{
						s_apxMenuPages[i]->RenderDebugBounds();
						Asura_Render::FlushDisplay();
					}
#endif // ASURA_DEBUG_VARIABLE_SYSTEM
				}
			}

			// render fading out menus, or if nothing is fading out, the selected one
			if (IsMenuFadingOut())
			{
				for (u_int u = 0; u < s_uNumMenusFadingOut; ++u)
				{
					Asura_Assert(s_apxMenuPagesFadingOut[u]->IsFadingOut(), "menu in fade out list is not fading");
					s_apxMenuPagesFadingOut[u]->Render( 0xffffffff);	// parameter is ignored
					Asura_Render::FlushDisplay();
				}
			}
			else
			{
				// render selected menu
				if( (s_iSelectedMenuIndex != -1) && (s_iSelectedMenuIndex < (int)s_uMenuPageCount) && IsMenuPageActive( s_iSelectedMenuIndex))
				{
					s_apxMenuPages[s_iSelectedMenuIndex]->Render( 0xffffffff);	// parameter is ignored
					Asura_Render::FlushDisplay();
#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
					if( s_bRenderDebugBounds)
					{
						s_apxMenuPages[s_iSelectedMenuIndex]->RenderDebugBounds();
						Asura_Render::FlushDisplay();
					}
#endif // ASURA_DEBUG_VARIABLE_SYSTEM
				}
			}
		}

		if (IsDoingTextInput())
		{
			Platform_RenderTextInput();
		}
	}


	if ( s_bRenderWidescreenBarsThisFrame == true )
	{
		RenderWidescreenBars();
	}

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	if(s_bRenderSafetyBorder)
	{
		Platform_RenderSafetyBorder();
	}
#endif //  ASURA_DEBUG_VARIABLE_SYSTEM

	ASURA_GUIMENU_PROFILE_END_TASK();
	ASURA_GUIMENU_PROFILE_END_SECTION();

	ASURA_GUIMENU_PROFILE_DISPLAYCOUNTERS();
	ASURA_GUIMENU_PROFILE_DISPLAYPROFILEDATA();

	Platform_EndRender();
}

void Asura_GUIMenu_System::RenderWidescreenBars(void)
{
#ifdef ASURA_GUI_MENU_ALWAYS_WIDESCREEN
	// Render wide screen bars
	if ( HasVirtualResolution() == true )
	{
		// Hard coded wide screen res. yuck!
		float fWideScreenAspectRatio = 16.0f / 9.0f;

		if ( fWideScreenAspectRatio <= (Asura_Camera::GetPhysicalScreenAspectRatio()-0.001f) || 
			fWideScreenAspectRatio >= (Asura_Camera::GetPhysicalScreenAspectRatio()+0.001f))
		{
			float fBarSize = Asura_Camera::GetPhysicalScreenAspectRatio() / fWideScreenAspectRatio;

			fBarSize = 1.0f - fBarSize;

			fBarSize = (fBarSize * Asura_Viewport::GetHeight()) * 0.5f;

			// fBarSize now contains the height in pixels of the widescreen bar
			Asura_Render::Overlay.Colour			= 0xff000000;
			Asura_Render::Overlay.m_bGouraudShaded	= false;
			Asura_Render::Overlay.TextureIndex		= ASURA_TEXTURE_NONE;			        
			Asura_Render::Overlay.TranslucencyMode	= ASURA_TRANSLUCENCY_NORMAL;	
			Asura_Render::Overlay.m_bNonRotated = true;

			Asura_Render::Overlay.SetRectXY( 0.0f, 0.0f, static_cast<float>(Asura_Viewport::GetWidth()), fBarSize);

			Asura_Render::Overlay.Render();

			Asura_Render::Overlay.SetRectXY( 0.0f, static_cast<float>(Asura_Viewport::GetHeight()) - fBarSize, 
				static_cast<float>(Asura_Viewport::GetWidth()), fBarSize);

			Asura_Render::Overlay.Render();
		}
	}
#endif // ASURA_GUI_MENU_ALWAYS_WIDESCREEN
}

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

void Asura_GUIMenu_System::Handle_MenuPageUpdate( u_int uButtons)
{
	ASURA_GUIMENU_PROFILE_START_TASK(ASURA_GUIMENU_PROFILE__HANDLE_MENUPAGE_UPDATE);

	int i;
	float fTimeUpdate = Asura_GUIMenu_System::GetFrameTime();

	FlushMessagePump();

	// update all the active menus
	const int iActiveMenu = s_iSelectedMenuIndex;
	for( i=0; i<(int)s_uMenuPageCount; i++)
	{
		if( (IsMenuPageActive( i) == true) || (s_apxMenuPages[i]->IsFadingOut()) )
		{
			if( i == iActiveMenu && !IsDoingTextInput())
			{
				Asura_GUIMenu_Input xInput;
				xInput.m_uButtonPresses = uButtons;
				#ifdef ASURA_USE_CURSOR
				xInput.m_bUseCursor = false;
				if(s_bUseCursor)
				{
					if (Asura_Cursor::GetTimeSpentStatic() < 0.25f
						|| (uButtons & (ASURA_GUIMENU_ACTION_BUTTON_CLICK | ASURA_GUIMENU_ACTION_BUTTON_CLICK_HELD)) != 0)
					{
						xInput.m_bUseCursor = true;
						int iX,iY;
						Asura_Cursor::GetScreenSpaceCoords(iX,iY);
						xInput.m_xCursorPos.x = (float) iX;
						xInput.m_xCursorPos.y = (float) iY;
					}
				}
				#else
				Asura_Assert(!s_bUseCursor,"Cursor support not enabled");
				#endif //ASURA_USE_CURSOR
						
				s_apxMenuPages[i]->ProcessInputActivity( xInput);
			}

			s_apxMenuPages[i]->Update( fTimeUpdate);
		}
	}

	// update the text input code
	if (IsDoingTextInput())
	{
		Platform_UpdateTextInput();
		if (Platform_IsTextInputFinished())
		{
			Platform_EndTextInput();
			// let the calling object know
			Asura_GUIMenu_Root* pxCaller = FindRootObjectByID( s_uTextInputID );
			Asura_Assert(pxCaller, "failed to find GUIMenu object");
			if (pxCaller)
			{
				pxCaller->TextInputEnded();
			}
			s_uTextInputID = ASURA_HASH_ID_UNSET;
		}
	}

	ASURA_GUIMENU_PROFILE_END_TASK();
}

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

u_int Asura_GUIMenu_System::Handle_ControllerInput( void)
{
	u_int uButtonAction = 0;
// -- must disable all updates if using the control manager.
// -- the control manager does the updating.
#ifndef ASURA_USE_CONTROLMAP_MANAGER
	//s_xMenuControlMap.Update();
#endif

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_UP) << ASURA_GUIMENU_ACTION_BITSHIFT_UP;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_DOWN) << ASURA_GUIMENU_ACTION_BITSHIFT_DOWN;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_LEFT) << ASURA_GUIMENU_ACTION_BITSHIFT_LEFT;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_RIGHT) << ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT;

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ACCEPT) << ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT1) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT2) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT3) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT4) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT5) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT6) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT7) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT8) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT9) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9;

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_CANCEL) << ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL;

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_UP_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_UP_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_DOWN_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_DOWN_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_LEFT_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_LEFT_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_RIGHT_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT_HELD;

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ACCEPT_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ACCEPT_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT1_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT1_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT2_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT2_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT3_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT3_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT4_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT4_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT5_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT5_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT6_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT6_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT7_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT7_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT8_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT8_HELD;
	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_ALT_ACCEPT9_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9_HELD;

	uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_CANCEL_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_CANCEL_HELD;

	if(s_bUseCursor)
	{
		uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_CLICK) << ASURA_GUIMENU_ACTION_BITSHIFT_CLICK;
		uButtonAction |= IsActionRequested( ASURA_GUIMENU_CONTROL_CLICK_HELD) << ASURA_GUIMENU_ACTION_BITSHIFT_CLICK_HELD;
	}

	float fHAxisValue = s_pxMenuControlMaps[s_uControlMapIndexInUse].GetValue(ASURA_GUIMENU_CONTROL_AXIS_H);
	float fVAxisValue = s_pxMenuControlMaps[s_uControlMapIndexInUse].GetValue(ASURA_GUIMENU_CONTROL_AXIS_V);

	if (fHAxisValue > 0.5f)
	{
		uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT_HELD;
		if (s_fLastHAxisValue < 0.5f)
		{
			uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_RIGHT;
		}
	}
	else if (fHAxisValue < -0.5f)
	{
		uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_LEFT_HELD;
		if (s_fLastHAxisValue > -0.5f)
		{
			uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_LEFT;
		}
	}

	if (fVAxisValue > 0.5f)
	{
		uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_DOWN_HELD;
		if (s_fLastVAxisValue < 0.5f)
		{
			uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_DOWN;
		}
	}
	else if (fVAxisValue < -0.5f)
	{
		uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_UP_HELD;
		if (s_fLastVAxisValue > -0.5f)
		{
			uButtonAction |= 1 << ASURA_GUIMENU_ACTION_BITSHIFT_UP;
		}
	}

	s_fLastHAxisValue = fHAxisValue;
	s_fLastVAxisValue = fVAxisValue;

#ifdef ASURA_USE_CONTROLMAP_MANAGER
	if( IsActionRequested( ASURA_GUIMENU_CONTROL_DVS_ACTIVATE))
	{
#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
		Asura_DebugVariableSystem::OpenDisplayDVS();
#endif
	}
#endif

	return uButtonAction;
}

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

bool Asura_GUIMenu_System::IsActionRequested(const MenuControls eMapping)
{
	bool bRetVal = false;

	if( s_pxMenuControlMaps)
	{
		return (s_pxMenuControlMaps[s_uControlMapIndexInUse].GetValue(eMapping) != 0.0f); 
	}

	return bRetVal;
}

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

void Asura_GUIMenu_System::RegisterControlEntry( u_int uControllerIndex, MenuControls eControl, int iKeyID, const Asura_ControlMapping::KeyHoldType eHoldType, Asura_Char* pcName)
{
	if( s_pxMenuControlMaps)
	{
		Asura_Assert( uControllerIndex < Platform_GetNumControlMaps(), "Asura_GUIMenu_System::RegisterControlEntry - Attempting to add a mapping for a controller index thats not supported.");
		if( uControllerIndex < Platform_GetNumControlMaps())	
		{
			s_pxMenuControlMaps[uControllerIndex].AddKeyMapping( eControl, iKeyID, eHoldType);
		}
	}

#ifdef ASURA_TOOLS
	if( eControl < ASURA_GUIMENU_CONTROL_MAX)
	{
		if( (s_pcToolControlNames[eControl] != NULL) && (pcName != NULL))
		{
			delete []s_pcToolControlNames[eControl];
			s_pcToolControlNames[eControl] = NULL;
		}

		if( pcName != NULL)
		{
			s_pcToolControlNames[eControl] = new Asura_Char[strlen( pcName)+1];
			strcpy( s_pcToolControlNames[eControl], pcName);
		}
	}
#endif // ASURA_TOOLS
}

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

#ifdef ASURA_TOOLS
Asura_Char** Asura_GUIMenu_System::GetMenuControlTextStrings( void)
{
	return &s_pcToolControlNames[0];
}
#endif

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// -- Menu Page specific functions ---------------------------------------------------------
// ---------------------------------------------------------------------------------------

void	Asura_GUIMenu_System::GenerateUniqueMenuName( void)
{
	Asura_Char acArray[256];

	Asura_PrintfToBfr( &acArray[0], "MenuPage_%04d", 255, true, s_uUniqueMenuNumber);
	s_xUniqueName = acArray;
	s_uUniqueMenuNumber++;
}

// ---------------------------------------------------------------------------------------
#ifdef ASURA_TOOLS

void Asura_GUIMenu_System::AddTextureToExportList(int iTextureIndex,void* pJunk)
{
	Tools_Level_Export::AddTextureToGUIMenuList(iTextureIndex);
}

void Asura_GUIMenu_System::AddAllTexturesToExportList( void)
{
	TraverseUsedTextures(AddTextureToExportList,0);
}

void Asura_GUIMenu_System::AddTexturesToExportList(Asura_GUIMenu_Menu_Page* pxMenuItem)
{
	Asura_Assert(pxMenuItem,"");

	pxMenuItem->TraverseUsedTextures(AddTextureToExportList,0);
}

void Asura_GUIMenu_System::TraverseUsedTextures(void (*pfnCallback)(int iTextureID,void* pUserData),void* pUserData)
{
	Asura_Assert(pfnCallback,"Need a callback function");
	for(u_int u = 0; u < s_uMenuPageCount; ++u)
	{
		s_apxMenuPages[u]->TraverseUsedTextures(pfnCallback,pUserData);
	}
}

void Asura_GUIMenu_System::AddFilesToExportList(Asura_GUIMenu_Menu_Page* pxMenuItem)
{
	Asura_Assert(pxMenuItem,"");

	pxMenuItem->AddFilesToExportList();
}

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

void Asura_GUIMenu_System::RestoreResizedSettings( void)
{
}
#endif
// ---------------------------------------------------------------------------------------

void	Asura_GUIMenu_System::GenerateUniqueWidgetName( u_int uType)
{
	Asura_Char acArray[256];
	Asura_String xType;

	switch( uType)
	{
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_NONE:
		default:
			xType = "Unknown";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_BUTTON:
			xType = "Button";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_CHECKBOX:
			xType = "CheckBox";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_SLIDER:
			xType = "Slider";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_TEXTBOX:
			xType = "TextBox";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_TEXTLISTBOX:
			xType = "TextListBox";
			break;
		
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP:
			xType = "Group";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_ANIMATINGIMAGE:
			xType = "AnimImage";			
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_PROGRESSBAR:
			xType = "ProgressBar";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_NUMERIC:
			xType = "Numeric";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOX:
			xType = "ListBox";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOXENTRY:
			xType = "ListBoxEntry";
			break;
	}

	if( (uType >= Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_PROJECT_SPECIFIC_WIDGET_BEGIN) &&
		(uType <= Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_PROJECT_SPECIFIC_ELEMENT_BEGIN))
	{
		xType = "Project";
	}

	Asura_PrintfToBfr( &acArray[0], "Widget_%s_%04d", 255, true, xType.GetString(), s_uUniqueWidgetNumber);
	s_xUniqueName = acArray;
	s_uUniqueWidgetNumber++;
}

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

void Asura_GUIMenu_System::GenerateUniqueElementName( u_int uType)
{
	Asura_Char acArray[256];
	Asura_String xType;

	switch( uType )
	{

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_NONE:
		default:
			xType = "Unknown";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_IMAGE:
			xType = "Image";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH:
			xType = "Path";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT:
			xType = "Text";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_STATUSTEXT:
			xType = "StatusText";
			break;

		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_FMV:
			xType = "FMV";
			break;
	}

	Asura_PrintfToBfr( &acArray[0], "Element_%s_%04d", 255, true, xType.GetString(), s_uUniqueElementNumber);
	s_xUniqueName = acArray;
	s_uUniqueElementNumber++;
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::Create( u_int uType, const Asura_Bounding_Rectangle& xRect)//Asura_Vector_3& vPos)
{
	Asura_GUIMenu_Root* pxItem = NULL;

	switch( uType )
	{
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE			: pxItem = new Asura_GUIMenu_Menu_Page; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_BUTTON		: pxItem = new Asura_GUIMenu_Widget_Button; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_CHECKBOX	: pxItem = new Asura_GUIMenu_Widget_CheckBox; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_SLIDER		: pxItem = new Asura_GUIMenu_Widget_Slider; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_TEXTBOX	: pxItem = new Asura_GUIMenu_Widget_TextBox; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_TEXTLISTBOX : pxItem = new Asura_GUIMenu_Widget_TextListBox; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_GROUP		: pxItem = new Asura_GUIMenu_Widget_Group; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_ANIMATINGIMAGE: pxItem = new Asura_GUIMenu_Widget_AnimatingImage; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_PROGRESSBAR: pxItem = new Asura_GUIMenu_Widget_ProgressBar; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_NUMERIC	: pxItem = new Asura_GUIMenu_Widget_Numeric; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_IMAGE		: pxItem = new Asura_GUIMenu_Element_Image; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT		: pxItem = new Asura_GUIMenu_Element_Text; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH		: pxItem = new Asura_GUIMenu_Element_Path; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_ANIMATION	: pxItem = new Asura_GUIMenu_Element_Animation; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_STATUSTEXT: pxItem = new Asura_GUIMenu_Element_StatusText; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOX	: pxItem = new Asura_GUIMenu_Widget_ListBox; break;
		case Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_FMV		: pxItem = new Asura_GUIMenu_Element_FMV; break;
		default: break;
	}

	InitTypeInstance( uType, pxItem, xRect );

	return pxItem;
}

Asura_GUIMenu_Element_Text* Asura_GUIMenu_System::CreateTextElementArray( u_int uCount )
{
	Asura_GUIMenu_Element_Text* pxItems = new Asura_GUIMenu_Element_Text[uCount];
	Asura_Bounding_Rectangle xRect(0.0f, 0.0f, 0.0f, 0.0f);
	for (u_int u = 0; u < uCount; ++u)
	{
		InitTypeInstance( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT, &pxItems[u], xRect );
	}
	return pxItems;
}


void Asura_GUIMenu_System::InitTypeInstance( u_int uType, Asura_GUIMenu_Root* pxItem, const Asura_Bounding_Rectangle& xRect )
{
	Asura_Assertf( pxItem, ("Failed to create menu item of type '%d'",uType) );
	if( pxItem )
	{
		pxItem->SetUnscaledLocalBounds(xRect);
		if( (uType > Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_BEGIN) 
		 && (uType < Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_END) )
		{
			GenerateUniqueWidgetName( uType );
			pxItem->SetName( s_xUniqueName.GetString() );
			if (uType == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOX)
			{
				Asura_GUIMenu_Widget_ListBox* pxList = static_cast<Asura_GUIMenu_Widget_ListBox*>(pxItem);
				pxList->GetEntryTemplate().SetUnscaledLocalBounds(xRect);
			}
		}
		else if( (uType > Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_BEGIN) 
			  && (uType < Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_END) )
		{
			GenerateUniqueElementName( uType );
			pxItem->SetName( s_xUniqueName.GetString() );
			if (uType == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_IMAGE)
			{
				// NY - 03 September 2008 - turn this on by default for new images, as it's more intuitive than the older behaviour
				pxItem->ChangeFlag(Asura_GUIMenu_Element_Image::ASURA_GUIMENU_ELEMENT_IMAGE_LOCAL_FLAG_POST_ROTATE_SCALE, true);
			}
		}
		else if( uType == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE ) 
		{
			Asura_GUIMenu_Menu_Page* pxMenu = static_cast<Asura_GUIMenu_Menu_Page*>(pxItem);

			GenerateUniqueMenuName();
			pxMenu->SetName( s_xUniqueName.GetString() );

			AddToMenuList( pxMenu );
		}
	}
}

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateCopy( Asura_GUIMenu_Root* pxDestParent,const Asura_GUIMenu_Root* pxSource,const char* const szDestName )
{
	Asura_GUIMenu_Root* pxCopy(NULL);

	if( pxSource )
	{
		// special case for list-box-entries
		if( pxDestParent && (pxSource->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOXENTRY) )
		{
			//Listbox entries are automatically generated by the listbox.
			//Don't want to create a new one , but instead try to find the existing
			//entry so that the rest of the copying can be done.
			Asura_GUIMenu_Root* pxRoot(NULL);

			for( u_int u(0);u<pxDestParent->GetContainerCount();++u )
			{
				pxRoot = pxDestParent->GetContainerItem(u);

				if( pxRoot && (pxRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_LISTBOXENTRY) )
				{
					pxCopy = pxRoot;
					break;
				}
			}

			Asura_Assert( pxCopy,"Failed to find existing listbox entry to copy over" );
		}
		else
		{
			pxCopy = Asura_GUIMenu_System::Create( static_cast<Asura_GUIMenu_Root::Asura_GUIMenu_Object_Type>(pxSource->GetType()),Asura_Bounding_Rectangle(0.0f,0.0f,0.0f,0.0f) );

			if(pxCopy)
			{
				if( szDestName )
				{
					pxCopy->SetName(szDestName);
				}
				else
				{	
					// copy name from source if its unique within parent, else generate random name
					if( pxDestParent && pxDestParent->FindContainerItemByLocalNameHash( pxSource->GetNameHash() ) )
					{
						Asura_Char szBuffer[128];
						
						#ifdef ASURA_GUIMENU_STORE_NAMES
						Asura_PrintfToBfr( szBuffer,"%s_%u",128,true,pxSource->GetNameAsChar(),pxDestParent->GetContainerCount() );
						pxCopy->SetName( szBuffer );
						#else
						Asura_PrintfToBfr( szBuffer,"_%u",128,true,pxDestParent->GetContainerCount() );
						pxCopy->SetNameHash( Asura_ConcatenateHashID( pxSource->GetNameHash(),szBuffer ) );
						#endif // ASURA_GUIMENU_STORE_NAMES	
					}
					else
					{
						#ifdef ASURA_GUIMENU_STORE_NAMES
						pxCopy->SetName(pxSource->GetNameAsChar());
						#else
						pxCopy->SetNameHash( pxSource->GetNameHash() );
						#endif // ASURA_GUIMENU_STORE_NAMES	
					}
				}

				// attempt to add it to the menu
				if( pxDestParent && !pxDestParent->AddToThisContainer(pxCopy) )
				{
					Asura_Assert( false,"Failed to add GuiMenu object to parent" );
					delete pxCopy;
					pxCopy = NULL;
				}

#ifdef ASURA_TOOLS
				// not sure what to do here as Menupages don't have a concept of file name in retail - NDB 200208
				if( pxCopy && (pxCopy->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE) )
				{
					// set the filename in the new menu
					Asura_GUIMenu_Menu_Page* pxCopyPage( static_cast<Asura_GUIMenu_Menu_Page*>(pxCopy) );
					const Asura_GUIMenu_Menu_Page* pxSourcePage( static_cast<const Asura_GUIMenu_Menu_Page*>(pxSource) );

					pxCopyPage->SetFilename( pxSourcePage->GetFilename() );
				}
#endif // ASURA_TOOLS
				
				if( pxCopy )
				{
					pxCopy->GenerateHashID();
				}
								
			}
		}
	
		if(pxCopy)
		{
			// recursively call this method to create copies of any children
			for( u_int u(0);u<pxSource->GetContainerCount();++u )
			{
				CreateCopy( pxCopy,pxSource->GetContainerItem(u) );
			}

			pxCopy->Copy(pxSource);
		}
	}

	return pxCopy;
}


// ---------------------------------------------------------------------------------------
// -- Element specific functions ---------------------------------------------------------
// ---------------------------------------------------------------------------------------

// ----------------------------------------------------------------------------------------------------
// SK 28.02.07 - This is a compatibility function to allow old type calls.  This is bad because
// Asura_String is a char* internally...hence no foreign text.
Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateTextElement( const Asura_String& xText, const Asura_String& xFontName, const Asura_Bounding_Rectangle& xRect, const Asura_RGBA* pxColour)
{
	Asura_GUIMenu_Root* pxRoot = NULL;
	
	Asura_UnicodeChar* pwszUnicodeString = new Asura_UnicodeChar[xText.GetLength()+1];
	if( pwszUnicodeString)
	{
		// -- convert the Asura_String to a unicode string.
		Asura_PrintfToBfr( pwszUnicodeString, L"%s", xText.GetLength()+1, true, xText.GetString());

		pxRoot = CreateTextElement( pwszUnicodeString, xFontName, xRect, pxColour);

		delete []pwszUnicodeString;
	}

	return pxRoot;
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateTextElement( const Asura_UnicodeChar* pwszText, const Asura_String& xFontName, const Asura_Bounding_Rectangle& xRect, const Asura_RGBA* pxColour)
{
	Asura_GUIMenu_Root* pxRoot;
	Asura_GUIMenu_Element_Text* pxText = NULL;

	pxRoot = Create( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT, xRect);
	if( pxRoot)
	{
		pxText = static_cast<Asura_GUIMenu_Element_Text*>(pxRoot);
		pxText->SetText( pwszText);
		pxText->SetFontByName( xFontName);

		if( pxColour != NULL)
		{	pxText->SetColour( pxColour);	}
	}

	return pxRoot;
}

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

void Asura_GUIMenu_System::FlushMessagePump()
{
	const Asura_Message_GUIMenu_Notify* pxMessage;
	bool bMessageHandled = false;

	// flush the message pump
	while( (pxMessage = Asura_GUIMenu_MessagePump::GetNextMessage()) != NULL)
	{
		if( pxMessage->uToID == ASURA_GUIMENU_EXTERNAL_REQUEST)
		{
			SendExternalMessage( pxMessage);
			continue;
		}

		for( int i=0; i<(int)s_uMenuPageCount; i++)
		{
			bMessageHandled = s_apxMenuPages[i]->Whisper( pxMessage);

			if( (bMessageHandled == true) && (pxMessage->uToID != ASURA_GUIMENU_ID_ALL))
			{	
				break;	
			}
		}
	}
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateStatusTextElement( const Asura_String& xFontName, const Asura_Bounding_Rectangle& xRect, const Asura_RGBA* pxColour)
{
	Asura_GUIMenu_Root* pxRoot;
	Asura_GUIMenu_Element_StatusText* pxText = NULL;

	pxRoot = Create( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_STATUSTEXT, xRect);
	if( pxRoot)
	{
		pxText = static_cast<Asura_GUIMenu_Element_StatusText*>(pxRoot);

		pxText->SetFontByName( xFontName);

		if( pxColour != NULL)
		{	pxText->SetColour( pxColour);	}
	}

	return pxRoot;
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateImageElement( const Asura_String& xTexture, const Asura_Bounding_Rectangle& xRect, const Asura_RGBA* pxColour)
{
	Asura_GUIMenu_Root* pxRoot;
	Asura_GUIMenu_Element_Image* pxImage;

	pxRoot = Create( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_IMAGE, xRect);
	if( pxRoot)
	{
		pxImage = static_cast<Asura_GUIMenu_Element_Image*>(pxRoot);
#ifdef SIMP_CREATE_NEW_HUD_DATA
		pxImage->SetTexture( xTexture, true);
#else
#ifdef SIMP_CREATE_MENU_DATA
		pxImage->SetTexture( xTexture, true);
#else
		pxImage->SetTexture( xTexture);
#endif // SIMP_CREATE_MENU_DATA
#endif // SIMP_CREATE_NEW_HUD_DATA

		if( pxColour != NULL)
		{	pxImage->SetColour( pxColour);	}

	}

	return pxRoot;
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreatePathElement( const Asura_Vector_2* pxPointArray, u_int uPointCount, const Asura_RGBA* pxColour)
{
	Asura_GUIMenu_Root* pxRoot;
	Asura_GUIMenu_Element_Path* pxPath;
	Asura_Bounding_Rectangle xRect;

	xRect.MinX = xRect.MinY = 
	xRect.MaxX = xRect.MaxY = 0.0f;

	pxRoot = Create( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH, xRect);
	if( pxRoot)
	{
		pxPath = static_cast<Asura_GUIMenu_Element_Path*>(pxRoot);
		pxPath->SetPointArray( pxPointArray, uPointCount);

		if( pxColour != NULL)
		{	pxPath->SetColour( pxColour);	}
	}

	return pxRoot;
}

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

void Asura_GUIMenu_System::SendExternalMessage( const Asura_Message_GUIMenu_Notify* pxMessage)
{
	#ifdef ASURA_TOOLS
	//Let tools handle any messages that are sent while previewing menus
	//RAR 13/02/2007
	if(Tools_Mode_GUIMenu::IsPreview())
	{
		Tools_Mode_GUIMenu::MenuPreview_ProcessMessage(pxMessage);
		return;
	}
	#endif
	
	if( s_pfMessageCallback != NULL)
	{
		// -- sends an extern message direct to the registered callback --
		s_pfMessageCallback( pxMessage);
	}

}

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

void Asura_GUIMenu_System::RegisterExternalMessageCallback( ExternMessageOverrideCallbackFunction* pfCallback)
{
	Asura_Assert( pfCallback != NULL, "Asura_GUIMenu_System::RegisterExternalMessageCallback - pointer passed is NULL");
	
	s_pfMessageCallback = pfCallback;
}

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// -- Widget specific functions ---------------------------------------------------------

// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// -- Menu Page specific functions ---------------------------------------------------------

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateMenuPage( const Asura_String& xMenuName, float fPosX, float fPosY, float fWidth, float fHeight)
{
	Asura_Bounding_Rectangle xRect;

	xRect.MinX = fPosX;
	xRect.MinY = fPosY;
	xRect.MaxX = xRect.MinX + fWidth;
	xRect.MaxY = xRect.MinY + fHeight;

	return CreateMenuPage( xMenuName, xRect);
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::CreateMenuPage( const Asura_String& xMenuName, const Asura_Bounding_Rectangle& xBoundingRect)
{
	Asura_GUIMenu_Root* pxRoot = NULL;
	Asura_GUIMenu_Menu_Page* pxMenuPage = NULL;

	pxRoot = Create( Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE, xBoundingRect);
	if( pxRoot != NULL)
	{
		pxMenuPage = static_cast<Asura_GUIMenu_Menu_Page*>(pxRoot);
		Asura_Assertf( !DoesMenuPageExist(Asura_GetHashID(xMenuName.GetString())), ("menu %s already exists", xMenuName.GetString()));
		pxMenuPage->SetName( xMenuName);
		
		// the AddToMenuList function is called in the create function above.
	}

	return pxRoot;
}

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

bool Asura_GUIMenu_System::DestroyMenuPage( Asura_Hash_ID uMenuPageID, bool bForceDelete)
{
bool bRetVal = false;
Asura_GUIMenu_Menu_Page* pxPage = GetMenuPageByID( uMenuPageID);

	if( pxPage)
	{
		bRetVal = DestroyMenuPage( pxPage, bForceDelete);
	}

	return bRetVal;
}

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

bool Asura_GUIMenu_System::DestroyMenuPage( Asura_GUIMenu_Menu_Page* pxMenuPage, bool bForceDelete)
{
	bool bRet = false;
	u_int i;

	// -- store off the current focused menu page --
	Asura_Hash_ID uFocusedMenu = GetFocusedMenuHashID();

	if( pxMenuPage )
	{
		if( IsSpecificMenuFadingOut( pxMenuPage))
		{
			EndMenuFadingOut( pxMenuPage);
		}

		Asura_GUIMenu_MessagePump::DeleteMessagesForMenu( pxMenuPage->GetID());
#ifdef ASURA_TOOLS

		// just using this here to keep tally, it's not necessary for tools
		// as we're never going to delete the menu in tools unless it's the designer
		// removing it via the editor.
		if( pxMenuPage->GetRefCount() > 1)
		{
			pxMenuPage->DecRefCount();
		}

		// This is so the tools code works correctly.
		//
		if( bForceDelete == true)
		{
			RemoveFromMenuList( pxMenuPage);
			delete pxMenuPage;
			bRet = true;
		}
#else
		// In retail mode, reference counting is in place.
		// The object wont be deleted unless it's ref count drops to zero.
		pxMenuPage->DecRefCount();

		if( (pxMenuPage->GetRefCount() == 0) || (bForceDelete == true))
		{
			RemoveFromMenuList( pxMenuPage);
			delete pxMenuPage;
			bRet = true;
		}
#endif
	}		

	// -- try and find the current focused menu, it may have shifted in the list --
	s_iSelectedMenuIndex = -1;
	for( i=0; i<s_uMenuPageCount; i++)
	{
		if( s_apxMenuPages[i] && ( s_apxMenuPages[i]->GetID() == uFocusedMenu) )
		{
			s_iSelectedMenuIndex = i;
			break;	
		}
	}

	return bRet;
}

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

void Asura_GUIMenu_System::ReleaseAllMenuPages( void)
{
	s_xFastWidgetLookUpTree.Reset();
	// -- this removes any input focus on menus
	// -- and more importantly 'pops' the menu control off the control stack.
	SetFocusedMenuByID( ASURA_HASH_ID_UNSET);

	// -- force a close of all menu pages here, if they're open --
	for( u_int u=0; u<s_uMenuPageCount; u++)
	{
		if( IsMenuPageActive( u))
		{
			CloseMenuPage(s_apxMenuPages[u]->GetID());
		}
	}


	// -- now free all the menu pages --
	while (s_uMenuPageCount)
	{
		u_int u = --s_uMenuPageCount;
		if( s_apxMenuPages[u] )
		{
			delete s_apxMenuPages[u];
			s_apxMenuPages[u] = NULL;
		}

		// -- ensures that all menu page flags will be cleared out.
		s_aucMenuPageUsageFlags[u] = 0;
	}

	// Also clear the fading-out menu list. This should be sufficient.
	s_uNumMenusFadingOut = 0;
}

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

void Asura_GUIMenu_System::DestroyAllMenuPages( void)
{
	s_xFastWidgetLookUpTree.Reset();
	// -- this removes any input focus on menus
	// -- and more importantly 'pops' the menu control off the control stack.
	SetFocusedMenuByID( ASURA_HASH_ID_UNSET);

	// -- _ReleaseAllMenuPages() should not be called here in tools mode.
	// -- this is a safe guard in case a project calls DestroyAllMenuPages() in tools mode.
	// -- This is ok, but the function should not destroy the menu data for tools.
#ifndef ASURA_TOOLS
	ReleaseAllMenuPages();
#endif // ASURA_TOOLS
}

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

void Asura_GUIMenu_System::FlagMenuPageAsCodeDrivenByID( Asura_Hash_ID uHashID, bool bTF)
{
	u_int i;

	for( i=0; i<s_uMenuPageCount; i++)
	{
		if( s_apxMenuPages[i] != NULL)
		{
			if( s_apxMenuPages[i]->GetID() == uHashID)
			{
				FlagMenuPageAsCodeDriven( i, bTF);
				break;
			}
		}
	}
}

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

void Asura_GUIMenu_System::FlagMenuPageAsCodeDriven( int iMenuPageIndex, bool bTF)
{
	if( (iMenuPageIndex >= 0) || (iMenuPageIndex < (int)s_uMenuPageCount))
	{
		if( bTF)
		{
			s_aucMenuPageUsageFlags[iMenuPageIndex] |= ASURA_GUIMENU_MENU_USAGE_FLAG_CODE_UPATE_AND_RENDER;
		}
		else
		{
			s_aucMenuPageUsageFlags[iMenuPageIndex] &= (0xff - ASURA_GUIMENU_MENU_USAGE_FLAG_CODE_UPATE_AND_RENDER);
		}
	}
}

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

void Asura_GUIMenu_System::SetMenuPageActive( int iMenuPageIndex, bool bTF)
{
	if( (iMenuPageIndex >= 0) || (iMenuPageIndex < (int)s_uMenuPageCount))
	{
		if( bTF)
		{
			s_aucMenuPageUsageFlags[iMenuPageIndex] |= ASURA_GUIMENU_MENU_USAGE_FLAG_ACTIVE;
		}
		else
		{
			s_aucMenuPageUsageFlags[iMenuPageIndex] &= (0xff - ASURA_GUIMENU_MENU_USAGE_FLAG_ACTIVE);
		}
	}
}

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

void Asura_GUIMenu_System::SetMenuPageActiveByID( Asura_Hash_ID uHashID, bool bTF)
{
	u_int i;

	for( i=0; i<s_uMenuPageCount; i++)
	{
		if( s_apxMenuPages[i] != NULL)
		{
			if( s_apxMenuPages[i]->GetID() == uHashID)
			{
				SetMenuPageActive( i, bTF);
				break;
			}
		}
	}
}

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

bool Asura_GUIMenu_System::IsMenuPageActive( int iMenuPageIndex)
{
	bool bRet = false;

	if( (iMenuPageIndex >= 0) && (iMenuPageIndex < (int)s_uMenuPageCount))
	{
		bRet = ((s_aucMenuPageUsageFlags[iMenuPageIndex]&ASURA_GUIMENU_MENU_USAGE_FLAG_ACTIVE) != 0);
	}

	return bRet;
}

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

bool Asura_GUIMenu_System::IsMenuPageHashActive( Asura_Hash_ID uHashMenuPageID)
{
	u_int u;
	bool bRet = false;

	for( u=0; u<s_uMenuPageCount; u++)
	{
		if( s_apxMenuPages[u] != NULL)
		{
			if( s_apxMenuPages[u]->GetID() == uHashMenuPageID)
			{
				bRet = IsMenuPageActive( u);
				break;
			}
		}
	}

	return bRet;
}

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

bool Asura_GUIMenu_System::DoesMenuPageExist( Asura_Hash_ID uHashID)
{
	u_int i;
	bool bRet = false;

	for( i=0; i<s_uMenuPageCount; i++)
	{
		if( s_apxMenuPages[i] != NULL)
		{
			if( s_apxMenuPages[i]->GetID() == uHashID)
			{
				bRet = true;
				break;
			}
		}
	}
	
	return bRet;
}

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

bool Asura_GUIMenu_System::DoesWidgetExistOnMenuPage( Asura_Hash_ID uHashMenuPageID, Asura_Hash_ID uHashWidgetID)
{
	Asura_GUIMenu_Root* pxItem = NULL;
	bool bRet = false;

	if( DoesMenuPageExist( uHashMenuPageID))
	{
		pxItem = FindWidgetObjectByID( uHashWidgetID);
		if( pxItem)
		{
			Asura_GUIMenu_Root* pxParentRoot = pxItem->FindOwnerMenu();
			if( pxParentRoot)
			{
				if( pxParentRoot->GetID() == uHashMenuPageID)
				{
					bRet = true;
				}
			}
		}
	}

	return bRet;
}

// ---------------------------------------------------------------------------------------
// SK - 14.03.07 - Eventually, i'd like to phase this function out completely.
// It's potentially dangerous, if we start loading and deleting menu pages during the game.
// Preferably all code should use teh SetFocusedMenuByID() function.

int Asura_GUIMenu_System::SetFocusedMenuByIndex( int iFocusedMenu)
{
	Asura_Hash_ID uHashID = ASURA_HASH_ID_UNSET;

	if( (iFocusedMenu > -1) && (iFocusedMenu < (int)s_uMenuPageCount))
	{
		uHashID = s_apxMenuPages[iFocusedMenu]->GetID();
	}

	return SetFocusedMenuByID( uHashID);
}

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

int Asura_GUIMenu_System::SetFocusedMenuByID( Asura_Hash_ID uHashID)
{
	u_int i;
	int iOldFocus = s_iSelectedMenuIndex;
	
#ifdef ASURA_USE_CONTROLMAP_MANAGER
	bool bFound = false;
#endif
	for( i=0; i<s_uMenuPageCount; i++)
	{
		Asura_Assert(s_apxMenuPages[i], "menu page pointer is NULL");
		if( s_apxMenuPages[i] && s_apxMenuPages[i]->GetID() == uHashID)
		{
			SetMenuPageActive( i, true);
			s_iSelectedMenuIndex = i;
			Asura_GUIMenu_System::SetFocusedPageConsoleVar(uHashID);
#ifdef ASURA_USE_CONTROLMAP_MANAGER
			bFound = true;		
#endif
			break;
		}
	}
#ifdef ASURA_USE_CONTROLMAP_MANAGER
	if( (bFound == true) && (s_bControlMapOnStack == false))
	{
		Asura_ControlManager::PushOverrideControls( &s_pxMenuControlMaps[s_uControlMapIndexInUse] );
		IgnoreControlsThisUpdate();
		s_bControlMapOnStack = true;
	}
#endif
	if( uHashID == ASURA_HASH_ID_UNSET)
	{
		s_iSelectedMenuIndex = -1;
#ifdef ASURA_USE_CONTROLMAP_MANAGER
		if( s_bControlMapOnStack == true)
		{
			Asura_ControlManager::RemoveOverrideControls( &s_pxMenuControlMaps[s_uControlMapIndexInUse] );
			s_bControlMapOnStack = false;
		}
#endif
	}

	return iOldFocus;
}

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

int Asura_GUIMenu_System::GetFocusedMenuIndex( void)
{
	return s_iSelectedMenuIndex;
}

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

bool Asura_GUIMenu_System::AnyMenuPageHasFocus()
{
	if( (s_iSelectedMenuIndex != -1) && (s_iSelectedMenuIndex < ASURA_GUIMENU_MAX_MENU_PAGES))
	{
		return true;
	}
	return false;
}

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

Asura_Hash_ID Asura_GUIMenu_System::GetFocusedMenuHashID( void )
{
	Asura_Hash_ID uHashID = ASURA_HASH_ID_UNSET;

	Asura_GUIMenu_Menu_Page* pxPage = GetFocusedMenu();
	if(pxPage)
	{
		uHashID = pxPage->GetID();
	}
	
	return uHashID;
}

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

Asura_GUIMenu_Menu_Page* Asura_GUIMenu_System::GetFocusedMenu( void )
{
	if( (s_iSelectedMenuIndex != -1) && (s_iSelectedMenuIndex < ASURA_GUIMENU_MAX_MENU_PAGES))
	{
		if( IsMenuPageActive( s_iSelectedMenuIndex ) == true)
		{
			Asura_Assert(s_apxMenuPages[s_iSelectedMenuIndex], "no menu at that index");
			if (s_apxMenuPages[s_iSelectedMenuIndex])
			{
				return(s_apxMenuPages[s_iSelectedMenuIndex]);
			}
		}
	}

	return NULL;
}

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

void Asura_GUIMenu_System::StartMenuFadingOut( Asura_GUIMenu_Menu_Page* pxMenu )
{
	// double-check that the pxMenu pointer isn't in the array already ...
	if (s_uNumMenusFadingOut > 0)
	{
		for (u_int u = 0; u < s_uNumMenusFadingOut; ++u)
		{
			if (s_apxMenuPagesFadingOut[u] == pxMenu)
			{
				// already present!
				Asura_Assert(false, "Trying to add a menupage for fading-out twice?");
				return;
			}
		}
	}

	Asura_Assertf(s_uNumMenusFadingOut < ASURA_GUIMENU_MAX_MENU_PAGES_FADING_OUT, ("too many menus fading out (%d versus %d)", s_uNumMenusFadingOut, ASURA_GUIMENU_MAX_MENU_PAGES_FADING_OUT));
	if (s_uNumMenusFadingOut < ASURA_GUIMENU_MAX_MENU_PAGES_FADING_OUT)
	{
		s_apxMenuPagesFadingOut[s_uNumMenusFadingOut++] = pxMenu;
	}
}

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

void Asura_GUIMenu_System::EndMenuFadingOut( const Asura_GUIMenu_Menu_Page* pxMenu )
{
	for (u_int u = 0; u < s_uNumMenusFadingOut; ++u)
	{
		if (s_apxMenuPagesFadingOut[u] == pxMenu)
		{
			// swap with last - we lose the ordering, but does it matter?
			s_apxMenuPagesFadingOut[u] = s_apxMenuPagesFadingOut[s_uNumMenusFadingOut-1];
			s_apxMenuPagesFadingOut[s_uNumMenusFadingOut-1] = NULL; // just for safety
			s_uNumMenusFadingOut--;
			return;
		}
	}
	Asura_Assert(false, "failed to find fading out menu in list");
}

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

bool Asura_GUIMenu_System::IsSpecificMenuFadingOut( const Asura_GUIMenu_Menu_Page* pxMenu )
{
	u_int u;
	bool bRet = false;

	for ( u = 0; u < s_uNumMenusFadingOut; ++u)
	{
		if (s_apxMenuPagesFadingOut[u] == pxMenu)
		{
			bRet = true;
			break;
		}
	}

	return bRet;
}

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

bool Asura_GUIMenu_System::OpenMenuPage( Asura_Hash_ID uHashMenuPage, float fWidth, float fHeight, bool bGiveControlFocus, bool bSetBackLink)
{
	bool bSuccess = false;

	bSuccess = OpenMenuPageOnWidget( uHashMenuPage, ASURA_HASH_ID_UNSET, bGiveControlFocus, bSetBackLink );
	if( bSuccess)
	{
		ResizeMenuPage( uHashMenuPage, fWidth, fHeight);
	}

	return bSuccess;
}

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

bool Asura_GUIMenu_System::OpenMenuPage( Asura_Hash_ID uHashMenuPage, bool bGiveControlFocus, bool bSetBackLink)
{
	return OpenMenuPageOnWidget( uHashMenuPage, ASURA_HASH_ID_UNSET, bGiveControlFocus, bSetBackLink );
}

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

bool Asura_GUIMenu_System::OpenMenuPageOnWidget( Asura_Hash_ID uHashMenuPage, Asura_Hash_ID uHashWidget, bool bGiveControlFocus, bool bSetBackLink)
{
	bool bRet = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uHashMenuPage);
	if (pxMenuPage)
	{
		// only allow the menu page to be opened this way if the code update & render flag isn't set.
		if( (pxMenuPage->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY) == 0)
		{
			if( (uHashWidget == ASURA_HASH_ID_UNSET) || DoesWidgetExistOnMenuPage( uHashMenuPage, uHashWidget))
			{
				if( bSetBackLink && pxMenuPage->CanBackOutOfThisMenu())
				{
					if( (s_iSelectedMenuIndex != -1) 
					&& (s_apxMenuPages[s_iSelectedMenuIndex] != NULL) )
					{
						pxMenuPage->SetBackMenuHash( s_apxMenuPages[s_iSelectedMenuIndex]->GetID(), s_apxMenuPages[s_iSelectedMenuIndex]->GetActiveWidgetHash());
					}
					else
					{
						pxMenuPage->SetBackMenuHash( ASURA_HASH_ID_UNSET);
					}
				}

				if( IsMenuPageHashActive( uHashMenuPage) == false)
				{

					Asura_GUIMenu_MessagePump::PostMessage( uHashMenuPage, 0, ASURA_GUIMENU_UI_MSG_ON_INIT, 0);

					if( uHashWidget != ASURA_HASH_ID_UNSET )
					{				
						pxMenuPage->SetStartupOverrideWidgetID( uHashWidget);
					}

					bRet = true;
				}

				if( bGiveControlFocus == true)
				{
					Asura_GUIMenu_System::SetFocusedMenuByID( uHashMenuPage);
					// ARC - 23 August 2007 14:28:23 - If the menu page is already open, it will have skipped the IsMenuPageHashActive() clause above and bRet won't get set.
					bRet = true;
				}
			}
		}
		else
		{
			Asura_Assert( 0, "Asura_GUIMenu_System::OpenMenuPageOnWidget - The code driven flag is set on this menu.\nThis means that this menu cannot be opened using this function.\nUse InitMenuPageData() instead.");
		}
	
		pxMenuPage->ApplyDisplayConditionSettings();
	}
	return bRet;

}

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

bool Asura_GUIMenu_System::CloseMenuPage( Asura_Hash_ID uHashMenuPage)
{
	bool bRet = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uHashMenuPage);
	if (pxMenuPage)
	{
		// only allow the menu page to be closed this way if the code update & render flag isn't set.
		if( (pxMenuPage->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY) == 0)
		{
			if( IsMenuPageHashActive( uHashMenuPage) == true)
			{
				Asura_GUIMenu_MessagePump::PostMessage( uHashMenuPage, 0, ASURA_GUIMENU_UI_MSG_ON_DEINIT, 0);

				bRet = true;
			}
		}
		else
		{
			Asura_Assert( 0, "Asura_GUIMenu_System::CloseMenuPage - The code driven flag is set on this menu.\nThis means that this menu cannot be opened using this function.\nUse DeInitMenuPageData() instead.");
		}

	}	
	return bRet;
}

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

bool Asura_GUIMenu_System::InitMenuPageData( Asura_Hash_ID uMenuPageHash, bool bGiveControlFocus)
{
	bool bRet = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uMenuPageHash);
	if (pxMenuPage)
	{
		// only allow the menu page to be opened this way if the code update & render flag is set.
		if( (pxMenuPage->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY) != 0)
		{
			Asura_GUIMenu_MessagePump::PostMessage( uMenuPageHash, 0, ASURA_GUIMENU_UI_MSG_ON_INIT, 0);

			if( bGiveControlFocus == true)
			{
				Asura_GUIMenu_System::SetFocusedMenuByID( uMenuPageHash);
			}

			bRet = true;
		}
		else
		{
			Asura_Assert( 0, "Asura_GUIMenu_System::InitMenuPageData - The code driven flag isn't set on this menu.\nThis means that this menu cannot be opened using this function.\nUse OpenMenuPage() instead.");
		}

	}
	return bRet;
}

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

bool Asura_GUIMenu_System::DeInitMenuPageData( Asura_Hash_ID uHashMenuPage)
{
	bool bRet = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uHashMenuPage);
	if (pxMenuPage)
	{
		// only allow the menu page to be closed this way if the code update & render flag is set.
		if( (pxMenuPage->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY) != 0)
		{

			Asura_GUIMenu_MessagePump::PostMessage( uHashMenuPage, 0, ASURA_GUIMENU_UI_MSG_ON_DEINIT, 0);

			bRet = true;
		}
		else
		{
			Asura_Assert( 0, "Asura_GUIMenu_System::DeInitMenuPageData - The code driven flag isn't set on this menu.\nThis means that this menu cannot be closed using this function.\nUse CloseMenuPage() instead.");
		}

	}	
	return bRet;
}

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

bool Asura_GUIMenu_System::SetMenuPageDefaultPos( Asura_Hash_ID uMenuPageID, Asura_Vector_2& xPos)
{
	bool bSuccess = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uMenuPageID);
	if( pxMenuPage)
	{
		pxMenuPage->SetUnscaledLocalPos( xPos);

		bSuccess = true;
	}

	return bSuccess;
}

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

bool Asura_GUIMenu_System::ResizeMenuPage( Asura_Hash_ID uMenuPageID, float fNewWidth, float fNewHeight)
{
	bool bSuccess = false;

	Asura_GUIMenu_Menu_Page* pxMenuPage = GetMenuPageByID( uMenuPageID);
	if( pxMenuPage)
	{
		pxMenuPage->Resize( fNewWidth, fNewHeight);
		bSuccess = true;
	}
	
	return bSuccess;
}

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


// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------
// -- Available menu list ----------------------------------------------------------------

void Asura_GUIMenu_System::ClearLocalVariables( void)
{
	u_int u;
	
	for( u=0; u<ASURA_GUIMENU_MAX_MENU_PAGES; u++)
	{
		s_apxMenuPages[u] = NULL;
		s_aucMenuPageUsageFlags[u] = 0;
	}

#ifdef ASURA_TOOLS
	for( u=0; u<ASURA_GUIMENU_CONTROL_MAX; u++)
	{
		s_pcToolControlNames[u] = NULL;
	}
#endif

	s_uMenuPageCount	= 0;	
	s_iSelectedMenuIndex = -1;

	s_pfMessageCallback = NULL;

	s_bControlMapOnStack = false;

	s_xUniqueName.MakeBlank();
	s_uUniqueMenuNumber = 0;
	s_uUniqueWidgetNumber = 0;
	s_uUniqueElementNumber = 0;

	s_uButtonInput = 0;

	s_pxMenuControlMaps = NULL;
	s_uControlMapIndexInUse = 0;
	s_fLastHAxisValue = 0.0f;
	s_fLastVAxisValue = 0.0f;

#ifdef ASURA_GUIMENU_ENABLE_METRICS
	s_bUpdateMetrics = false;
	Asura_Mem::Set( &s_xMetrics, 0, sizeof( Asura_GUIMenu_Metrics));
#endif // ASURA_GUIMENU_ENABLE_METRICS
}

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

bool Asura_GUIMenu_System::AddToMenuList( Asura_GUIMenu_Menu_Page* pxMenu)
{
	bool bRet = false;

	Asura_Assert( pxMenu, "NULL pointer in Asura_GUIMenu_System::AddToMenuList");

	if( pxMenu)
	{
		Asura_Assert( s_uMenuPageCount < ASURA_GUIMENU_MAX_MENU_PAGES, "too many menus - need to increase ASURA_GUIMENU_MAX_MENU_PAGES. If in tools, some menus will not be saved so you should exit tools before saving anything." );
		if( s_uMenuPageCount < ASURA_GUIMENU_MAX_MENU_PAGES)
		{
			int iMenuIndex = FindExistingMenuPage( pxMenu->GetNameHash() );

			if( iMenuIndex == -1)
			{
				iMenuIndex = s_uMenuPageCount;
				s_apxMenuPages[s_uMenuPageCount++] = pxMenu;
				bRet = true;
			}
			else
			{
				delete pxMenu;
			}

	#ifndef ASURA_TOOLS
			Asura_Assert( s_apxMenuPages[iMenuIndex]->GetRefCount() == 0, "Asura_GUIMenu_System::AddToMenuList - This menu page has already been loaded.  Returning pointer to original data.  This menu instance has been ignored.");
	#endif
			s_apxMenuPages[iMenuIndex]->IncRefCount();

			if( s_apxMenuPages[iMenuIndex]->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY)
			{
				FlagMenuPageAsCodeDriven( iMenuIndex, true);
			}

		}
	}

	return bRet;
}

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

Asura_GUIMenu_Menu_Page* Asura_GUIMenu_System::GetMenuPageByIndex( u_int uIndex)
{
	Asura_Assert( uIndex < s_uMenuPageCount, "Asura_GUIMenu_System::GetContainerItem -  u_int uIndex >= Menu Page Entries");
	if( uIndex < s_uMenuPageCount)
	{
		return s_apxMenuPages[uIndex];
	}

	return NULL;
}

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

Asura_GUIMenu_Menu_Page* Asura_GUIMenu_System::GetMenuPageByID( Asura_Hash_ID uHashID)
{
	Asura_Assert( uHashID != ASURA_HASH_ID_UNSET, "Asura_GUIMenu_System::GetMenuPageByID -  requested hash == ASURA_HASH_ID_UNSET");

	for(u_int u = 0; u < s_uMenuPageCount; ++u)
	{
		Asura_Assert(s_apxMenuPages[u], "menu page pointer is NULL");
		if(s_apxMenuPages[u] && s_apxMenuPages[u]->GetID() == uHashID)
		{
			return s_apxMenuPages[u];
		}
	}

	return 0;
}

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

bool Asura_GUIMenu_System::RemoveFromMenuList( Asura_GUIMenu_Menu_Page* pxMenuPage)
{
	u_int u;
	bool bCopy = false;

	for( u=0; u<s_uMenuPageCount; u++)
	{
		// -- found a match
		if( s_apxMenuPages[u] == pxMenuPage)
		{
			s_apxMenuPages[u] = NULL;
//			s_aucMenuPageUsageFlags[u] = 0;	// this should probably be here
			bCopy = true;	
			continue;
		}

		if( bCopy == true)
		{
			s_apxMenuPages[u-1] = s_apxMenuPages[u];
			s_aucMenuPageUsageFlags[u-1] = s_aucMenuPageUsageFlags[u];
			s_apxMenuPages[u] = NULL;
			s_aucMenuPageUsageFlags[u] = 0;
		}
	}

	if( bCopy == true)
	{	s_uMenuPageCount--;	}

	return bCopy;
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::FindRootObjectByID( Asura_Hash_ID uHashID)
{
	u_int i;
	Asura_GUIMenu_Root* pxItem = NULL;
	Asura_GUIMenu_Menu_Page* pxMenuPage;

	Asura_Assert( uHashID != ASURA_HASH_ID_UNSET, "Asura_GUIMenu_System::FindRootObjectByID -  requested hash == ASURA_HASH_ID_UNSET");

	for( i=0; i<s_uMenuPageCount; i++)
	{
		if( s_apxMenuPages[i]->GetID() == uHashID)
		{
			pxItem = s_apxMenuPages[i];
			break;
		}

		pxMenuPage = static_cast<Asura_GUIMenu_Menu_Page*>(s_apxMenuPages[i]);

		pxItem = pxMenuPage->FindContainerItemByID( uHashID);
		if( pxItem != NULL)
		{
			break;	
		}
	}

	return pxItem;
}

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

Asura_GUIMenu_Widget_Base*	Asura_GUIMenu_System::FindWidgetObjectByID( Asura_Hash_ID uHashID)
{
	Asura_GUIMenu_Root* pxRootObject = FindRootObjectByID( uHashID );
	if (pxRootObject)
	{
		u_int uType = pxRootObject->GetType();
		if (uType < Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_WIDGET_BEGIN || 
			uType > Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_PROJECT_SPECIFIC_WIDGET_END)
		{
			// not a widget
			return NULL;
		}
	}
	return static_cast<Asura_GUIMenu_Widget_Base*>(pxRootObject);
}

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

Asura_GUIMenu_Root* Asura_GUIMenu_System::FindParentMenuOfObjectID( Asura_Hash_ID uHashID)
{
	Asura_GUIMenu_Root* pxObject = FindRootObjectByID( uHashID);
	Asura_GUIMenu_Root* pxFoundMenu = NULL;

	while( (pxFoundMenu == NULL) && (pxObject != NULL))
	{
		// It's done this way around because, the starting object could be a menu
		// so it would return itself and we don't want that.
		pxObject = pxObject->GetParentObject();

		if( pxObject != NULL)
		{
			if( pxObject->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_MENUPAGE)
			{
				pxFoundMenu = pxObject;
				break;
			}
		}
	}

	return pxFoundMenu;
}

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

int Asura_GUIMenu_System::FindExistingMenuPage( const Asura_Hash_ID uNameHash )
{
	int iRetVal = -1;

	const u_int uMenuCount = GetCurrentMenuListCount();
	for( u_int u=0; u<uMenuCount; u++)
	{
		if( s_apxMenuPages[u] && (s_apxMenuPages[u]->GetNameHash() == uNameHash) )
		{
			// -- found a match, return the menu page index --
			iRetVal = static_cast<int> (u);
		}
	}

	return iRetVal;
}

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

void Asura_GUIMenu_System::SetControlMapIndexToUse( u_int uControllerIndex)
{
#ifdef ASURA_USE_CONTROLMAP_MANAGER
	Asura_Assert( uControllerIndex < Platform_GetNumControlMaps(), "Asura_GUIMenu_System::SetControlMapIndexToUse - index passed isn't within the max controller range.");

	if( uControllerIndex < Platform_GetNumControlMaps())
	{
		if( s_bControlMapOnStack)
		{
			Asura_ControlManager::RemoveOverrideControls( &s_pxMenuControlMaps[s_uControlMapIndexInUse] );
		}

		s_uControlMapIndexInUse = uControllerIndex;

		if( s_bControlMapOnStack)
		{
			Asura_ControlManager::PushOverrideControls( &s_pxMenuControlMaps[s_uControlMapIndexInUse] );
		}
	}
#endif // ASURA_USE_CONTROLMAP_MANAGER
}

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

void Asura_GUIMenu_System::LoadMenuText(const char* szFilename, Asura_Hash_ID uTextPageHash, int iLang /* = -1 */, bool bReload /* = false */)
{
#ifndef ASURA_TOOLS
	Asura_Assert(!bReload, "Shouldn't be attempting to reload outside of tools");
#endif
	if(iLang <= 0)
	{
		iLang = Asura_LocalisedText::GetCurrentLanguage();
	}

	char szFullFilename[50];
	Asura_PrintfToBfr(szFullFilename, ASURA_GUIMENU_TEXT_DIRECTORY "\\%s_%s." ASURA_STANDARD_FILE_EXTENSION, sizeof(szFullFilename), true,
		szFilename, Asura_LocalisedText::GetTwoCharCodeForLang((Asura_LocalisedText_Language)iLang));

#ifdef ASURA_TOOLS
	if(bReload)
	{
		//clearout current text
		Asura_HashedLocalisedText::UnloadPage(uTextPageHash);
		if(Tools_FileSystem::FileExists_CheckNetwork(szFullFilename))
		{
			Asura_ChunkLoading_System::LoadAsuraFile( szFullFilename );
			// force regeneration of text selection overlay.
			Tools_Mode_GUIMenu::TextUpdated();
		}
		else
		{
			Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to find %s.",szFullFilename);
		}
	}
	else
#endif
	{
		if(!Asura_HashedLocalisedText::GetPage(uTextPageHash))
		{
			// Just load it.
			Asura_ChunkLoading_System::LoadAsuraFile( szFullFilename );
		}

#ifdef ASURA_TOOLS
		// And store the name in our list, alongside the text page hash
		Asura_GUIMenu_System::RegisterMenuTextPage( uTextPageHash, szFilename ); 
#endif
	}
	
//	#ifdef ASURA_TOOLS
	s_iLanguage = iLang;
//	#endif
}

#ifdef ASURA_TOOLS
void Asura_GUIMenu_System::RegisterMenuTextPage( Asura_Hash_ID uTextPageHash, const char* szFilename )
{
	// Store the name in our list, alongside the text page hash
	Asura_String* pxString = s_xMenuTextFilenames.AddNode(uTextPageHash);
	if( pxString )
	{
		*pxString = szFilename;
	}	
}

void Asura_GUIMenu_System::ReloadAllMenuText(int iLang /* = -1 */)
{
	const u_int uNumberOfFiles = s_xMenuTextFilenames.GetNumberOfNodes();
	for(u_int uFileIndex = 0; uFileIndex < uNumberOfFiles; ++uFileIndex)
	{
		const Asura_Hash_ID uTextPageHash = s_xMenuTextFilenames.GetHashByIndex(uFileIndex);
		const Asura_String* const pxFilename = s_xMenuTextFilenames.GetDataByHash(uTextPageHash);
		LoadMenuText(pxFilename->GetString(), uTextPageHash, iLang, true);
	}
}

const Asura_String* Asura_GUIMenu_System::GetMenuTextFilenameFromHash(Asura_Hash_ID uHash)
{
	Asura_Assert(uHash != ASURA_HASH_ID_UNSET, "Hash id is unset");
	const Asura_TemplateHashTree<Asura_String>& xFilenameTree = Asura_GUIMenu_System::GetMenuTextFilenameTree();
	return xFilenameTree.GetDataByHash(uHash);
}

#endif

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

void Asura_GUIMenu_System::StartTextInput(Asura_Hash_ID uID, 
										  Asura_UnicodeChar* wszBuffer, 
										  u_int uBufferMaxChars,
										  const Asura_UnicodeChar* wszMessage /* = NULL */ )
{
	Asura_Assert( !IsDoingTextInput(), "already doing text input");
	s_uTextInputID = uID;
	if (!wszMessage)
	{
		wszMessage = L"";
	}
	Platform_BeginTextInput( wszMessage, wszBuffer, uBufferMaxChars );
}

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

void Asura_GUIMenu_System::LoadGenericAudioData( void)
{
	char szFilename[256];
	Asura_PrintfToBfr(szFilename,"GUIMenu\\GUIAudio." ASURA_STANDARD_FILE_EXTENSION, sizeof(szFilename), true);
	Asura_ChunkLoading_System::LoadAsuraFile( szFilename );
}

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

Asura_GUIMenu_Menu_Widget_Match* Asura_GUIMenu_System::FastSearchForWidget( Asura_Hash_ID uWidgetHash)
{
	Asura_GUIMenu_Menu_Widget_Match* pxMatch = NULL;

	pxMatch = s_xFastWidgetLookUpTree.GetDataByHash( uWidgetHash);
	Asura_Assert(!pxMatch || pxMatch->pxWidgetBase->GetID() == uWidgetHash,"GUIMenu fast lookup tree contains invalid data - Possibly from editing/renaming in tools.");
	return pxMatch;
}

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

void Asura_GUIMenu_System::AddWidgetToSearchCache( Asura_GUIMenu_Widget_Base* pxWidgetBase, const Asura_GUIMenu_Menu_Page* pxMenuOwner)
{
	Asura_GUIMenu_Menu_Widget_Match xEntry;

	xEntry.pxMenuPage = pxMenuOwner;
	xEntry.pxWidgetBase = pxWidgetBase;

	s_xFastWidgetLookUpTree.AddNode( pxWidgetBase->GetID(), xEntry);
}

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

void Asura_GUIMenu_System::AddLoadingWidgetToSearchCache( Asura_GUIMenu_Widget_Base* pxWidgetBase)
{
	if (s_pxLoadingMenu == 0)
	{
		Asura_Assert(0, "No loading menu set, can't add widget to tree");
	}
	AddWidgetToSearchCache( pxWidgetBase, s_pxLoadingMenu);
}

// --------------------------------------------------------------------------------------- 
void Asura_GUIMenu_System::ResetFastWidgetLookUpTree()
{
	s_xFastWidgetLookUpTree.Reset();
}

// --------------------------------------------------------------------------------------- 
void Asura_GUIMenu_System::RemoveWidgetFromSearchCache( Asura_Hash_ID uWidgetHash)
{
	s_xFastWidgetLookUpTree.DeleteNodeByHash(uWidgetHash);
}

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

#ifdef ASURA_GUIMENU_ENABLE_METRICS
void Asura_GUIMenu_System::Metrics_Begin( void)
{
	s_bUpdateMetrics = true;

	// The message peaks are not cleared in the per frame update
	s_xMetrics.uGetConsoleVarCalls_Bool		=
	s_xMetrics.uGetConsoleVarCalls_Int		=
	s_xMetrics.uGetConsoleVarCalls_Float	=
	s_xMetrics.uGetConsoleVarCalls_String	=
	s_xMetrics.uUpdateCalls_MenuPages		= 0;
}

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

void Asura_GUIMenu_System::Metrics_End( void)
{
	s_bUpdateMetrics = false;
}

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

void Asura_GUIMenu_System::Metrics_Render( void)
{
	float fPosY = 100.0f;
	float fScale = 0.6f;
	float fFontHeight = Asura_Font_System::GetFontHeight() * fScale;

	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffff0000, 0, "GUIMenu Metrics");
	fPosY += fFontHeight;

	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "Message Queue Peak/Second: %d -- Max Peak: %d", s_xMetrics.uQueuePeakPerSecond_MessagePump, s_xMetrics.uQueuePeak_MessagePump);
	fPosY += fFontHeight;
	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "ConsoleVar Bool Calls : %d", s_xMetrics.uGetConsoleVarCalls_Bool);
	fPosY += fFontHeight;
	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "ConsoleVar Int Calls : %d", s_xMetrics.uGetConsoleVarCalls_Int);
	fPosY += fFontHeight;
	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "ConsoleVar Float Calls : %d", s_xMetrics.uGetConsoleVarCalls_Float);
	fPosY += fFontHeight;
	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "ConsoleVar String Calls : %d", s_xMetrics.uGetConsoleVarCalls_String);
	fPosY += fFontHeight;
	Asura_Font_System::Print( 10.0f, fPosY, fScale, 0xffffffff, ASURA_TEXTFORMAT_FORMATSTRING, "MenuPages Updating : %d", s_xMetrics.uUpdateCalls_MenuPages);
	fPosY += fFontHeight;
}

#endif

bool Asura_GUIMenu_System::ShouldPause()
{
	for( u_int u = 0; u < s_uMenuPageCount; ++u)
	{
		if( IsMenuPageActive(u) )
		{
			if(s_apxMenuPages[u]->ShouldPause())
			{
				return true;
			}
		}
	}
	return false;
}

// Play the named music track.
bool Asura_GUIMenu_System::ConsoleCmd_PlayMusicTrack(const char* szMusicName, bool bInterrogate, bool bHelp)
{
	if(bHelp || bInterrogate)
	{
		Asura_CommandConsole::Printf("Plays a music name with the specified name.");
	}
	else
	{
		//PlayTrack here
#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
		Asura_Dynamic_Music_System::PlayTrack(Asura_GetHashID(szMusicName),1.0f,1.0f);
#endif
	}
	return true;
}

// Stop all music from playing
bool Asura_GUIMenu_System::ConsoleCmd_StopMusic(bool bHelp)
{
	if(bHelp)
	{
		Asura_CommandConsole::Printf("Stops the current music from playing.");
	}
	else
	{
		//Stop music here
#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
		Asura_Dynamic_Music_System::Stop();
#endif
	}
	return true;
}


bool Asura_GUIMenu_System::ConsoleCmd_OpenMenuPage(const char* szMenuName, bool bInterrogate, bool bHelp)
{
	if(bHelp || bInterrogate)
	{
		Asura_CommandConsole::Printf("Opens a menu page with the given name. Never sets back link");
	}
	else
	{
		OpenMenuPage(Asura_GetHashID(szMenuName), true, false);
	}
	return true;
}

bool Asura_GUIMenu_System::ConsoleCmd_ChangeMenuPage(const char* szMenuName, bool bInterrogate, bool bHelp)
{
	if(bHelp || bInterrogate)
	{
		Asura_CommandConsole::Printf("Opens menu page with the given name and closes current one. Never sets back link");
	}
	else
	{
		CloseMenuPage(Asura_GUIMenu_System::GetFocusedMenuHashID());
		OpenMenuPage(Asura_GetHashID(szMenuName), true, false);
	}
	return true;
}

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

void Asura_GUIMenu_System::SetAutoMenuSizes( float fWidth, float fHeight)
{
	Asura_Assert( fWidth > 0.0f, "Specified width is invalid.");
	Asura_Assert( fHeight > 0.0f, "Specified height is invalid.");

	if( fWidth > 0.0f && fHeight > 0.0f)
	{
		s_bAutoMenuSizesSet = true;

		s_xAutoMenuSizeDims.x = fWidth;
		s_xAutoMenuSizeDims.y = fHeight;
		s_xVirtualScreenScale.Zero();// NY - 20 November 2008 - will need recalculating
	}
}

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

void Asura_GUIMenu_System::SetAutoMenuOffsets( float fXOffset, float fYOffset )
{
	// if the dimentions of the page have not been set then the offset can not be safely applied, just assert and return in else clause. 
	if( s_bAutoMenuSizesSet )
	{
		if( fXOffset < 0.0f )
		{	
			Asura_Assert( false, "An offset has been requested that will place a menu page ouside the viewport ON THE TOP, offset has not been applied" );
			return;
		}
		else if ( ( fXOffset + s_xAutoMenuSizeDims.x ) > static_cast<float>( Asura_Viewport::GetWidth() ) )
		{
			Asura_Assert( false, "An offset has been requested that will place a menu page ouside the viewport ON THE BOTTOM, offset has not been applied" );
			return;
		}
		else if ( fYOffset < 0.0f )
		{
			Asura_Assert( false, "An offset has been requested that will place a menu page ouside the viewport ON THE LEFT, offset has not been applied" );
			return;
		}
		else if ( ( fYOffset + s_xAutoMenuSizeDims.y ) > static_cast<float>( Asura_Viewport::GetHeight() ) )
		{
			Asura_Assert( false, "An offset has been requested that will place a menu page ouside the viewport ON THE BOTTOM, offset has not been applied" );
			return;
		}

		s_xAutoMenuOffsetDims.x = fXOffset;
		s_xAutoMenuOffsetDims.y = fYOffset;
	}
	else
	{
		Asura_Assert( false, "Menu Page offset has been requested when the page size has not been defined yet." );
	}
}

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

void Asura_GUIMenu_System::SetVirtualResolution( float fWidth, float fHeight)
{
	s_xVirtualResolution.x = fWidth;
	s_xVirtualResolution.y = fHeight;
	s_xVirtualScreenScale.Zero();// NY - 20 November 2008 - will need recalculating
}

bool Asura_GUIMenu_System::HasVirtualResolution()
{
#ifdef ASURA_TOOLS
	if (Tools_System::IsActive())
	{
		return Tools_Mode_GUIMenu::IsPreview();
	}
#endif // #ifdef ASURA_TOOLS
	return s_xVirtualResolution.x >= 1.0f
		&& s_xVirtualResolution.y >= 1.0f;
}

const Asura_Vector_2& Asura_GUIMenu_System::GetVirtualScreenScale()
{
#ifdef ASURA_TOOLS
	if (Tools_System::IsActive())
	{
		static Asura_Vector_2 xToolsScale(1.0f, 1.0f);
		if (Tools_Mode_GUIMenu::IsPreview()
			&& !Tools_GUIMenu_PreviewOverlay::s_bUseVirtualResolution)
		{
			xToolsScale.x = Tools_Mode_GUIMenu::GetScreenSize().x / Tools_Mode_GUIMenu::GetVirtualSize().x;
			xToolsScale.y = Tools_Mode_GUIMenu::GetScreenSize().y / Tools_Mode_GUIMenu::GetVirtualSize().y;
		}
		else
		{
			xToolsScale.x = 1.0f;
			xToolsScale.y = 1.0f;
		}
		return xToolsScale;
	}
#endif // #ifdef ASURA_TOOLS
	if (s_xVirtualScreenScale.x == 0.0f
		|| s_xVirtualScreenScale.y == 0.0f)
	{
		if (HasVirtualResolution())
		{
			s_xVirtualScreenScale.x = static_cast<float>(Asura_Viewport::GetWidth()) / s_xVirtualResolution.x;
			s_xVirtualScreenScale.y = static_cast<float>(Asura_Viewport::GetHeight()) / s_xVirtualResolution.y;
		}
		else
		{
			s_xVirtualScreenScale.x = 1.0f;
			s_xVirtualScreenScale.y = 1.0f;
		}
	}
	return s_xVirtualScreenScale;
}

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

void Asura_GUIMenu_System::NotifyVideoModeChange( void)
{
// -- Currently this only needs to re-apply the center menu on screen flags again.
	u_int u;
	SetAutoMenuSizes( static_cast<float>( Asura_Viewport::GetWidth() ), static_cast<float>( Asura_Viewport::GetHeight() ) );
	SetAutoMenuOffsets( 0.0f, 0.0f );

	for( u=0; u<s_uMenuPageCount; u++)
	{
		if( IsMenuPageActive( u) )
		{
			s_apxMenuPages[u]->AutoResize();
		}
	}
}

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

void Asura_GUIMenu_System::SetActiveWidgetConsoleVar(Asura_Hash_ID uHash) 
{
	if(uHash != (u_int)s_iConsoleVar_ActiveWidget)
	{ 
		s_iConsoleVar_LastActiveWidget = s_iConsoleVar_ActiveWidget; 
		s_iConsoleVar_ActiveWidget = uHash;
	}
}

#endif // ASURA_USE_GUI_MENU_SYSTEM
