// ------------------------------------------------------------------------------------ //
//																						//
//	File: Asura_GUIMenu_Widget_Base.cpp													//
//																						//
//	Description: base class for all widgets												//
//																						//
//	Created: Steve Keen - 9/11/06														//
//																						//
//	Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.							//
// ------------------------------------------------------------------------------------ //

#include "Core/Asura.h"

// This file's header
#include "Asura_GUIMenu_Widget_Base.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM
// Asura
#include "Core/Asura_Hash.h"
#include "Core/Asura_String.h"

#include "GUIMenu/Asura_GUIMenu_Audio.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_Message.h"
#include "GUIMenu/Asura_GUIMenu_MessagePump.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "GUIMenu/Asura_Profiling_GUIMenu.h"

// Tools
#ifdef ASURA_TOOLS
#include "GUIMenu/Tools_GUIMenu_Root.h"
#include "GUIMenu/Tools_GUIMenu_XMLExporter.h"
#endif

#include "Rendering/Asura_Render.h"

// --------------------------------------------------------------------------------------- 
// -- Constants -------------------------------------------------------------------------- 
static const u_int uASURA_GUIMENU_MAX_WIDGET_NAVEXIT_RECURSION_LEVEL = 64;

// --------------------------------------------------------------------------------------- 
// -- Constructors -----------------------------------------------------------------------


Asura_GUIMenu_Widget_Base::Asura_GUIMenu_Widget_Base( void)
: m_bSelectable(true)
, m_bCanBeSelectable(true)
, m_bIsAlwaysSelectable(false)
, m_bIsFocusedObject(false)
, m_uCurrentState(ASURA_GUIMENU_WIDGET_STATE_DEFAULT)
{
	u_int u;

	for( u=0; u<ASURA_GUIMENU_UI_NAV_EXIT_MAX; u++)
	{
		m_auHashNavID[u] = ASURA_HASH_ID_UNSET;
	}

#ifdef ASURA_TOOLS
	m_uStyleChildEditableFlags = ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_UP |
								 ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_DOWN |
								 ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_LEFT |
								 ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_RIGHT;
#endif
}

// ---------------------------------------------------------------------------------------
// -- Destructor -------------------------------------------------------------------------

Asura_GUIMenu_Widget_Base::~Asura_GUIMenu_Widget_Base( void)
{
	Asura_GUIMenu_System::RemoveWidgetFromSearchCache(GetID());
}

// --------------------------------------------------------------------------------------- 
// -- Public Functions ------------------------------------------------------------------- 

void Asura_GUIMenu_Widget_Base::Update( float fElapsedTime)
{
	ASURA_GUIMENU_PROFILE_START_TASK(ASURA_GUIMENU_PROFILE__WIDGET_BASE);

	PARENT::Update( fElapsedTime);

	switch( m_uCurrentState)
	{
		case ASURA_GUIMENU_WIDGET_STATE_DEFAULT:
			break;

		case ASURA_GUIMENU_WIDGET_STATE_ROLL_ON:
			m_uCurrentState = ASURA_GUIMENU_WIDGET_STATE_HILIGHTED;
			break;

		case ASURA_GUIMENU_WIDGET_STATE_HILIGHTED:
			break;

		case ASURA_GUIMENU_WIDGET_STATE_CLICKED:
			break;

		case ASURA_GUIMENU_WIDGET_STATE_ROLL_OFF:
			m_uCurrentState = ASURA_GUIMENU_WIDGET_STATE_DEFAULT;
			break;

		case ASURA_GUIMENU_WIDGET_STATE_EDITING:
			break;

		case ASURA_GUIMENU_WIDGET_STATE_DISABLED:
		default:
			break;
	}

	ASURA_GUIMENU_PROFILE_END_TASK();
}

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

void Asura_GUIMenu_Widget_Base::Render( u_int uState)
{
	if (IsRenderingDisabled())
	{
		return;
	}

	const u_int uContainerCount = GetContainerCount();
	for( u_int u=0; u<uContainerCount; u++)
	{
		if( m_ppxContainerParts[u]->IsActionEnabled( m_uCurrentState))
		{
			// uState should contain menu state flags but no widget state flags
			Asura_Assert(!(uState & m_uCurrentState), "widget state overlaps with parent");

			m_ppxContainerParts[u]->Render( uState | m_uCurrentState);
			// (MH - 15.03.2007) attempt to fix ordering being broken sometimes.
			// could prove costly to render stuff without batching...
			Asura_Render::FlushDisplay();
		}
	}
}

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

void Asura_GUIMenu_Widget_Base::Copy( const Asura_GUIMenu_Root* pxSource )
{
	PARENT::Copy( pxSource );

	const Asura_GUIMenu_Widget_Base* pxSourceWidget = static_cast<const Asura_GUIMenu_Widget_Base*> (pxSource);
	
	#ifdef ASURA_TOOLS
	//Only want to copy the nav exits when copying an entire menu. RAR 17/08/2007
	if(Tools_Mode_GUIMenu::IsCopyingMenu())
	{
		SetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_LEFT, pxSourceWidget->GetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_LEFT));
		SetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_RIGHT, pxSourceWidget->GetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_RIGHT));
		SetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_UP, pxSourceWidget->GetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_UP));
		SetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_DOWN, pxSourceWidget->GetNavExitID(ASURA_GUIMENU_UI_NAV_EXIT_DOWN));
	}
	#endif

	m_xOnRollInCommand.Copy(&pxSourceWidget->m_xOnRollInCommand);
	m_xOnRollOutCommand.Copy(&pxSourceWidget->m_xOnRollOutCommand);

	m_bCanBeSelectable = pxSourceWidget->m_bCanBeSelectable;
	m_bIsAlwaysSelectable = pxSourceWidget->m_bIsAlwaysSelectable;
}


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

u_int Asura_GUIMenu_Widget_Base::ProcessNavigationInput( u_int uButtonPresses)
{
//	int iActionButtonIndex = -1;
	u_int uButtonsTrapped = 0;
	bool bNavigateChange = false;

	Asura_Hash_ID uHashExitID = ASURA_HASH_ID_UNSET;

	if( (uButtonPresses&ASURA_GUIMENU_ACTION_BUTTON_UP) != 0)
	{
		uHashExitID = GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_UP);

		if( uHashExitID != ASURA_HASH_ID_UNSET)
		{
			uButtonsTrapped |= ASURA_GUIMENU_ACTION_BUTTON_UP;
		}

		bNavigateChange = true;
	}
	else if( (uButtonPresses&ASURA_GUIMENU_ACTION_BUTTON_DOWN) != 0)
	{
		uHashExitID = GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_DOWN);		

		if( uHashExitID != ASURA_HASH_ID_UNSET)
		{
			uButtonsTrapped |= ASURA_GUIMENU_ACTION_BUTTON_DOWN;
		}

		bNavigateChange = true;
	}
	else if( (uButtonPresses&ASURA_GUIMENU_ACTION_BUTTON_LEFT) != 0)
	{
		uHashExitID = GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_LEFT);

		if( uHashExitID != ASURA_HASH_ID_UNSET)
		{
			uButtonsTrapped |= ASURA_GUIMENU_ACTION_BUTTON_LEFT;
		}

		bNavigateChange = true;
	}
	else if( (uButtonPresses&ASURA_GUIMENU_ACTION_BUTTON_RIGHT) != 0)
	{
		uHashExitID = GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_RIGHT);
		
		if( uHashExitID != ASURA_HASH_ID_UNSET)
		{
			uButtonsTrapped |= ASURA_GUIMENU_ACTION_BUTTON_RIGHT;
		}

		bNavigateChange = true;
	}

	// -- we have an exit hash
	if( uHashExitID != ASURA_HASH_ID_UNSET)
	{
		// -- notify the next item to be selected
		Asura_GUIMenu_MessagePump::PostMessage( uHashExitID, GetID(), ASURA_GUIMENU_UI_MSG_ON_ROLL_IN, 0);

		// -- notify the current item, to be deselected --
		Asura_GUIMenu_MessagePump::PostMessage( GetID(), GetID(), ASURA_GUIMENU_UI_MSG_ON_ROLL_OUT, 0);
	}

	if( bNavigateChange)
	{
		if( uHashExitID != ASURA_HASH_ID_UNSET)
		{
			// -- change to a different widget --
			Asura_GUIMenu_Audio::Play( ASURA_GUIMENU_AUDIO_TYPE_ON_NAVIGATE);
		}
		else
		{
			// -- notifies the player that they can't go in this direction.
			Asura_GUIMenu_Audio::Play( ASURA_GUIMENU_AUDIO_TYPE_FAILURE);
		}
	}

	return uButtonsTrapped;
}

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

u_int Asura_GUIMenu_Widget_Base::ProcessInputActivity( const Asura_GUIMenu_Input& xInput)
{
	int iActionButtonIndex = -1;
	u_int uButtonsTrapped = 0;
	const u_int uButtonPresses = xInput.m_uButtonPresses;

	uButtonsTrapped = ProcessNavigationInput( uButtonPresses);

	if( uButtonsTrapped == 0)
	{
		for (u_int u = ASURA_GUIMENU_ACTION_BITSHIFT_UP; u <= ASURA_GUIMENU_ACTION_BITSHIFT_ALT_ACCEPT9; ++u)
		{
			u_int uAcceptType = (1<<u);

			if( (uButtonPresses&uAcceptType) != 0)
			{
				iActionButtonIndex = uAcceptType;
				uButtonsTrapped |= uAcceptType;
			}
		}
	}

	//check for click if the cursor is within the widget
	//RAR 01/08/2007
	if(xInput.m_bUseCursor && ContainsPos(xInput.m_xCursorPos))
	{
		if(uButtonPresses & ASURA_GUIMENU_ACTION_BUTTON_CLICK)
		{
			iActionButtonIndex = ASURA_GUIMENU_ACTION_BUTTON_CLICK;
			uButtonsTrapped |= ASURA_GUIMENU_ACTION_BUTTON_CLICK;
		}
	}

	if( iActionButtonIndex != -1)
	{
		// Pass on all buttons intercepted.
		Asura_GUIMenu_MessagePump::PostMessage( GetID(), GetID(), ASURA_GUIMENU_UI_MSG_ON_CLICKED, GetType(), uButtonsTrapped);
	}

	return uButtonsTrapped;
}


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

void Asura_GUIMenu_Widget_Base::SetHiddenByConditionVar( bool bTF )
{ 
	PARENT::SetHiddenByConditionVar( bTF );
	SetSelectable( !bTF );
}

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

bool Asura_GUIMenu_Widget_Base::HandleMessage( const Asura_Message_GUIMenu_Notify* pxMessage)
{
	bool bRet = false;
	Asura_GUIMenu_Widget_State eCurrentState = GetCurrentState();
	u_int uMessageType = ASURA_GUIMENU_GET_MAIN_MESSAGE( pxMessage->uActionType);

	switch( uMessageType)
	{
		case ASURA_GUIMENU_UI_MSG_ON_INIT:
			bRet = OnInit( pxMessage);
			break;
								   
		case ASURA_GUIMENU_UI_MSG_ON_DEINIT:
			bRet = OnDeInit( pxMessage);
			break;

		case ASURA_GUIMENU_UI_MSG_ON_DATA_CHANGE:
			bRet = OnDataChange( pxMessage);
			break;

		case ASURA_GUIMENU_UI_MSG_ON_DATA_REQUEST:
			bRet = OnDataRequest( pxMessage);
			break;

		case ASURA_GUIMENU_UI_MSG_ON_CLICKED:
			if( eCurrentState != ASURA_GUIMENU_WIDGET_STATE_DISABLED)
			{
				bRet = OnClicked( pxMessage);
			}
			break;

		case ASURA_GUIMENU_UI_MSG_ON_ROLL_IN:
			SetAsFocusedObject( true);

			if( eCurrentState != ASURA_GUIMENU_WIDGET_STATE_DISABLED)
			{
				bRet = OnRollIn( pxMessage); 
			}
			break;

		case ASURA_GUIMENU_UI_MSG_ON_ROLL_OUT:
			SetAsFocusedObject( false);

			if( eCurrentState != ASURA_GUIMENU_WIDGET_STATE_DISABLED)
			{
				bRet = OnRollOut( pxMessage);
			}
			break;

		case ASURA_GUIMENU_UI_MSG_ENABLE_DISABLE:
			bRet = OnEnable( pxMessage);
			break;

		default:
			break;
	}

	return bRet;
}

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

u_int Asura_GUIMenu_Widget_Base::GetNavExitID( Asura_GUIMenu_Navigation_Exit uExit) const
{
	// array to store the hashIDs of the widgets we've recursed through so the recursion
	// can exit if we end up looping round.
	Asura_Hash_ID auHashIDs[uASURA_GUIMENU_MAX_WIDGET_NAVEXIT_RECURSION_LEVEL];
	return GetNavExitID_Internal( uExit, auHashIDs, 0 );
}


u_int Asura_GUIMenu_Widget_Base::GetNavExitID_Internal( Asura_GUIMenu_Navigation_Exit uExit, Asura_Hash_ID* puHashIds, u_int uCount)  const
{
	Asura_Hash_ID uHashExitID = ASURA_HASH_ID_UNSET;

	Asura_Assert( uExit < ASURA_GUIMENU_UI_NAV_EXIT_MAX, "Asura_GUIMenu_Widget_Base::GetNavExitID - uExit >= ASURA_GUIMENU_UI_NAV_EXIT_MAX");

	uHashExitID = m_auHashNavID[uExit];

	if (uHashExitID != ASURA_HASH_ID_UNSET)
	{
		for (u_int u = 0; u < uCount; ++u)
		{
			if (uHashExitID == puHashIds[u])
			{
				// already visited this widget, so end the recursion
				return ASURA_HASH_ID_UNSET;
			}
		}

		// check if its selectable - if not, recurse into the widgets linked from there
		const Asura_GUIMenu_Widget_Base* pxWidgetBase = Asura_GUIMenu_System::FindWidgetObjectByID(uHashExitID);
#ifdef ASURA_TOOLS
		if (!Tools_GUIMenu_Root::IsRenaming())
#endif
		{
			Asura_Assertf( pxWidgetBase, ("broken navigation link in widget %s on menu page %s", GetNameAsChar(), 
				FindOwnerMenu() ? FindOwnerMenu()->GetNameAsChar() : "unknown" ));
		}

		
		if (pxWidgetBase)
		{
			bool bSkipPastWidget = !pxWidgetBase->IsSelectable();
			#ifdef ASURA_TOOLS
			if(Tools_Level_Export::IsExport())
			{
				//For exports , skip past any widgets that won't appear in the export.
				//Ignoring selectability in this case , since it might change while in game.
				bSkipPastWidget = !pxWidgetBase->AreThisAndParentsFlaggedForPlatform(Tools_Level_Export::s_eExportType);
			}
			else
			{
				//Skip past widgets that aren't part of the platform being previewed
				bSkipPastWidget |= !pxWidgetBase->AreThisAndParentsFlaggedForPlatform(Tools_Mode_GUIMenu::GetPreviewPlatform());
			}
			#endif

			if(bSkipPastWidget)
			{
				if (uCount < uASURA_GUIMENU_MAX_WIDGET_NAVEXIT_RECURSION_LEVEL)
				{
					puHashIds[uCount++] = uHashExitID;
					return pxWidgetBase->GetNavExitID_Internal(uExit, puHashIds, uCount);
				}
			}
		}
	}
	return uHashExitID;
}

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

void Asura_GUIMenu_Widget_Base::SetNavExitID( Asura_GUIMenu_Navigation_Exit uExit, u_int hashExitID)
{
	Asura_Assert( uExit < ASURA_GUIMENU_UI_NAV_EXIT_MAX, "Asura_GUIMenu_Widget_Base::GetNavExitID - uExit >= ASURA_GUIMENU_UI_NAV_EXIT_MAX");
	m_auHashNavID[uExit] = hashExitID;
}

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

void Asura_GUIMenu_Widget_Base::SetNavExitIDs( Asura_Hash_ID uHashUp, Asura_Hash_ID uHashDown, Asura_Hash_ID uHashLeft, Asura_Hash_ID uHashRight)
{
	SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_LEFT, uHashLeft);
	SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_RIGHT, uHashRight);
	SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_UP, uHashUp);
	SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_DOWN, uHashDown);
}


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

Asura_GUIMenu_Widget_Base* Asura_GUIMenu_Widget_Base::FindSelectableWidgetAtPos(const Asura_Vector_2& xPos)
{
	if(IsSelectable())
	{
		if(ContainsPos(xPos))
		{
			for(u_int u = 0; u < GetContainerCount(); ++u)
			{
				if (m_ppxContainerParts[u]->ContainsPos(xPos))
				{
					return this;
				}
			}
		}
	}
	return PARENT::FindSelectableWidgetAtPos(xPos);
}


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

bool Asura_GUIMenu_Widget_Base::Whisper( const Asura_Message_GUIMenu_Notify* pxNotify)
{
	bool bMessageHandled = false;

	Asura_Assert( pxNotify != NULL, "Asura_GUIMenu_Widget_Base::Whisper - Asura_Message_GUIMenu_Notify* pxNotify == NULL");

	// -- Is message meant for this widget? 
	// -- GUIMENU_ID_ALL signified that the message is meant for everything --
	if( (pxNotify->uToID == GetID()) || (pxNotify->uToID == ASURA_GUIMENU_ID_ALL))
	{
		bMessageHandled = HandleMessage( pxNotify);
	}

	if( (bMessageHandled == false) || (pxNotify->uToID == ASURA_GUIMENU_ID_ALL))
	{
		const u_int uContainerCount = GetContainerCount();
		for( u_int u=0; u<uContainerCount; u++)
		{
			bMessageHandled = m_ppxContainerParts[u]->Whisper( pxNotify);

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

	return bMessageHandled;
}

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

bool Asura_GUIMenu_Widget_Base::OnInit( const Asura_Message_GUIMenu_Notify* pxMessage)
{
	const u_int uContainerCount = GetContainerCount();
	for( u_int u=0; u<uContainerCount; u++)
	{
		if( m_ppxContainerParts[u] && m_ppxContainerParts[u]->IsWidget() )
		{
			const Asura_Message_GUIMenu_Notify &xMsg = Asura_GUIMenu_MessagePump::CreateMessage( m_ppxContainerParts[u]->GetID(), GetID(), ASURA_GUIMENU_UI_MSG_ON_INIT, 0);
			m_ppxContainerParts[u]->Whisper(&xMsg);
		}
	}

	// -- Need to make sure the state is reset to default
	m_uCurrentState = ASURA_GUIMENU_WIDGET_STATE_DEFAULT;

	return false;
}

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

#ifdef ASURA_TOOLS
void Asura_GUIMenu_Widget_Base::UpdateLocalDataFromStyle( void)
{
	Asura_GUIMenu_Widget_Base* pxStyleBase;

	PARENT::UpdateLocalDataFromStyle();

	if( m_pxStyleObject != NULL)
	{
		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_UP) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			// -- this isn't correct.  It will need remapping to the freshly created widgets --
			SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_UP, pxStyleBase->GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_UP));
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_DOWN) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			// -- this isn't correct.  It will need remapping to the freshly created widgets --
			SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_DOWN, pxStyleBase->GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_DOWN));
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_LEFT) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			// -- this isn't correct.  It will need remapping to the freshly created widgets --
			SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_LEFT, pxStyleBase->GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_LEFT));
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_NAVID_RIGHT) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			// -- this isn't correct.  It will need remapping to the freshly created widgets --
			SetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_RIGHT, pxStyleBase->GetNavExitID( ASURA_GUIMENU_UI_NAV_EXIT_RIGHT));
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_SELECTABLE) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			m_bCanBeSelectable = pxStyleBase->m_bCanBeSelectable;
			if (!m_bCanBeSelectable)
			{
				// remove all links from this widget
				for( u_int u = 0; u < ASURA_GUIMENU_UI_NAV_EXIT_MAX; ++u)
				{
					m_auHashNavID[u] = ASURA_HASH_ID_UNSET;
				}
			}
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ISALWAYSSELECTABLE) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			m_bIsAlwaysSelectable = pxStyleBase->m_bIsAlwaysSelectable;
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ONROLLIN_COMMAND) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			m_xOnRollInCommand = pxStyleBase->m_xOnRollInCommand;
		}

		if( (m_uStyleUseLocalDataFlags&ASURA_GUIMENU_WIDGET_BASE_LOCAL_FLAG_ONROLLOUT_COMMAND) == 0)
		{
			pxStyleBase = static_cast<Asura_GUIMenu_Widget_Base*>(m_pxStyleObject);

			m_xOnRollOutCommand = pxStyleBase->m_xOnRollOutCommand;
		}
	}
}
#endif
// --------------------------------------------------------------------------------------- 

void Asura_GUIMenu_Widget_Base::ReadFromChunkStream( Asura_Chunk_Stream& xStream, Asura_GUIMenu_Root* pxParentObject, u_int uChunkVersion)
{
	u_int uLocalChunkVersion;

	PARENT::ReadFromChunkStream( xStream, pxParentObject, 0xffffffff);

	uLocalChunkVersion = ReadVersionNumber(xStream);

	if( CheckVersionNumber( uLocalChunkVersion,ASURA_GUIMENU_CHUNK_TYPE_WIDGET_BASE,xStream.GetFileHandle() ) == true)
	{
		for(u_int u = 0; u < ASURA_GUIMENU_UI_NAV_EXIT_MAX; ++u)
		{
			xStream >> m_auHashNavID[u];
		}

		if( uLocalChunkVersion >= 2)
		{
			m_xOnRollInCommand.ReadFromChunkStream( xStream);
			m_xOnRollOutCommand.ReadFromChunkStream( xStream);
		}

		if ( uLocalChunkVersion >= 1 )
		{
			xStream >> m_bCanBeSelectable;
		}

		if ( uLocalChunkVersion >= 3 )
		{
			xStream >> m_bIsAlwaysSelectable;
		}
	}
	Asura_GUIMenu_System::AddLoadingWidgetToSearchCache(this);
}
// --------------------------------------------------------------------------------------- 

#ifdef ASURA_TOOLS
void Asura_GUIMenu_Widget_Base::WriteToChunkStream( Asura_Chunk_Stream& xStream) const
{
	u_int u;

	PARENT::WriteToChunkStream( xStream);

	WriteVersionNumber( ASURA_CHUNK_WIDGET_BASE_VERSION, xStream);

	// -- Fill in the navigation exit information --
	for( u=0; u<ASURA_GUIMENU_UI_NAV_EXIT_MAX; u++)
	{
		if(Tools_Level_Export::IsExport())
		{
			//During exports , write out using GetNavExitID() so that it can skip past any widgets
			//that won't appear in the export.
			xStream << GetNavExitID((Asura_GUIMenu_Navigation_Exit)u);
		}
		else
		{
			xStream << m_auHashNavID[u];
		}
	}

	m_xOnRollInCommand.WriteToChunkStream( xStream);
	m_xOnRollOutCommand.WriteToChunkStream( xStream);

	xStream << m_bCanBeSelectable;
	xStream << m_bIsAlwaysSelectable;
}

void Asura_GUIMenu_Widget_Base::ExportToXML( Tools_GUIMenu_XMLExporter* pxExporter ) const
{
	PARENT::ExportToXML( pxExporter );
	pxExporter->AddToBuffer( pxExporter->GetTabs() );
	pxExporter->AddToBuffer( "<WidgetBase_data>\n" );
	pxExporter->IncTabs();

	// -- Fill in the navigation exit information --
	for( u_int u=0; u<ASURA_GUIMENU_UI_NAV_EXIT_MAX; u++)
	{
		pxExporter->AddToBuffer( pxExporter->GetTabs() );
		pxExporter->AddToBuffer( "<hash_nav_id num='" ); pxExporter->AddToBuffer( u ); pxExporter->AddToBuffer( "' id='" );
		pxExporter->AddToBufferHex( m_auHashNavID[u] );
		pxExporter->AddToBuffer( "' />\n" );
	}

	if(!m_xOnRollInCommand.IsBlank())
	{
		pxExporter->AddToBuffer( pxExporter->GetTabs() );
		pxExporter->AddToBuffer( "<on_update>\n" );
		pxExporter->IncTabs();
		m_xOnRollInCommand.ExportToXML( pxExporter );
		pxExporter->DecTabs();
		pxExporter->AddToBuffer( pxExporter->GetTabs() );
		pxExporter->AddToBuffer( "</on_update>\n" );
	}
	if(!m_xOnRollOutCommand.IsBlank())
	{
		pxExporter->AddToBuffer( pxExporter->GetTabs() );
		pxExporter->AddToBuffer( "<on_update>\n" );
		pxExporter->IncTabs();
		m_xOnRollOutCommand.ExportToXML( pxExporter );
		pxExporter->DecTabs();
		pxExporter->AddToBuffer( pxExporter->GetTabs() );
		pxExporter->AddToBuffer( "</on_update>\n" );
	}
	
	pxExporter->AddToBuffer( pxExporter->GetTabs() );
	pxExporter->AddToBuffer( "<can_be_selectable>" );
	pxExporter->AddToBuffer( m_bCanBeSelectable );
	pxExporter->AddToBuffer( "</can_be_selectable>\n" );

	pxExporter->AddToBuffer( pxExporter->GetTabs() );
	pxExporter->AddToBuffer( "<is_always_selectable>" );
	pxExporter->AddToBuffer( m_bIsAlwaysSelectable );
	pxExporter->AddToBuffer( "</is_always_selectable>\n" );

	pxExporter->DecTabs();
	pxExporter->AddToBuffer( pxExporter->GetTabs() );
	pxExporter->AddToBuffer( "</WidgetBase_data>\n" );
}


#endif // ASURA_TOOLS

// --------------------------------------------------------------------------------------- 
// --------------------------------------------------------------------------------------- 
// -- Protected Functions ------------------------------------------------------------------

// --------------------------------------------------------------------------------------- 
// --------------------------------------------------------------------------------------- 
// -- Private Functions ------------------------------------------------------------------ 


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

#endif // ASURA_USE_GUI_MENU_SYSTEM
