// ------------------------------------------------------------------------
/*
	\author: Jaap Suter

	Copyright (C) Electronic Arts Canada Inc. 2002.  All rights reserved.	
*/
// ------------------------------------------------------------------------

/*! \file */

#include "reveal/impl/menu.h"
#include "reveal/impl/util.h"
#include "reveal/impl/tree.h"

#include "reveal/input_state.h"
#include "reveal/renderer.h"

#include "reveal/smart_ptr/scoped_array.h"

#include <assert.h>
#include <string.h>

namespace Reveal {
	namespace Impl {

// -------------------------------------------------------------------------------
Menu::Menu( const char* name, Tree& tree, Menu* parent )
  :
Widget( name, tree, parent ),
mControls(),
mChildMenus(),
mNumChildMenus( 0 ),
mNumControls( 0 ),
mOpenedChild( 0 )
{}

// ------------------------------------------------------------------------------
Menu::~Menu()
{
	GetTree().RemoveFromMrus( *this );
	if ( (GetTree().GetWidgetWithFocus() == this) || IsChildOf( GetTree().GetWidgetWithFocus() ) )
	{
		GetTree().SetWidgetWithFocus( Parent() );
	}
}

// -------------------------------------------------------------------------------
void Menu::AddControl( const char* path, Widget* control )
{
	// Local function definition;
	struct StringInsensitiveEquals
	{
		bool operator () ( const char* a, const char* b )
		{
			while ( tolower( static_cast< unsigned char >( *a++ ) ) == tolower( static_cast< unsigned char >( *b++ ) ) )
				if ( (*a == 0) || (*b == 0) )
					if ( (*a == 0) && (*b == 0) ) return true;
					else return false;
			return false;
		}
	} StrICmp;


    assert( path != 0 );
	assert( control != 0 );

    const char *seperators = "/\\";

    // Skip possible starting slashes;
    while ( (*path != '\0') && (strchr( seperators, *path ) != 0) ) ++path;

    // If nothing is left in the string, then this is the
    // menu we add the control to;
    if ( *path == '\0' )
    {
		// Maybe there already exists a control with this name;
		size_t i = 0; for ( ; i < mNumControls; ++i ) if ( StrICmp( mControls[ i ]->Name(), control->Name() ) ) break;

		if ( i != mNumControls )
		{
			// There is already one, so we replace it with this new one;
            mControls[ mNumControls ].Reset( control );
			mControls[ mNumControls ]->SetParent( this );
		}
		else
		if ( mNumControls < MAX_NUM_CONTROLS )
        {
			mControls[ mNumControls ].Reset( control );
			mControls[ mNumControls ]->SetParent( this );
            ++mNumControls;
			if ( !Parent() || Parent()->mOpenedChild == this ) Open();
        }
	}
    else // We add a child menu;
    {
      // Get the next seperator;
      const char* iter = path + strcspn( path, seperators );

      // Create the next submenu;
      //if ( mNumChildMenus < MAX_NUM_CHILD_MENUS )
      {
				char childMenuName[ Widget::MAX_NAME_STRING_LENGTH ];
				size_t nameLength = static_cast< size_t >( iter - path );
				if ( nameLength > (Widget::MAX_NAME_STRING_LENGTH - 1) ) nameLength = (Widget::MAX_NAME_STRING_LENGTH - 1);
				strncpy( childMenuName, path, nameLength );
				childMenuName[ nameLength ] = '\0';

				// Maybe there already exists a child menu with this name;
        size_t i = 0; for ( ; i < mNumChildMenus; ++i ) if ( StrICmp( mChildMenus[ i ]->Name(), childMenuName ) ) break;

        // If not found, add a new child menu;
        if ( i == mNumChildMenus && i < MAX_NUM_CHILD_MENUS)
        {
          mChildMenus[ i ].Reset( new Menu( childMenuName, GetTree(), this ) );
          ++mNumChildMenus;
          if ( !Parent() || Parent()->mOpenedChild == this ) Open();
        }

        if (i < MAX_NUM_CHILD_MENUS)
				{
					mChildMenus[ i ]->AddControl( iter, control );
				}
      }
    }
}

// -------------------------------------------------------------------------------
Widget* Menu::DoHandle( const InputState& inputState )
{
	Widget* widgetThatHandledTheInput = NULL;

	if ( IsVisible() )
	{	
		// Give the opened child a chance to handle the input first, because maybe it (or one of
		// its childs) handles the input;
		if ( mOpenedChild )
		{
			widgetThatHandledTheInput = mOpenedChild->Handle( inputState );
		}
		
		// If it's not handled, give all other menu's a chance to deal with it;
		if ( ! widgetThatHandledTheInput )
		{
			for ( size_t i = 0; i < mNumChildMenus; ++i )
			{
				if ( mChildMenus[ i ].Get() != mOpenedChild )
				{
					widgetThatHandledTheInput = mChildMenus[ i ]->Handle( inputState );					
					if ( widgetThatHandledTheInput ) break;
				}
			}
		}

		// If it's still not handled, give controls a chance to handle it;
		if ( ! widgetThatHandledTheInput )
		{
			for ( size_t i = 0; i < mNumControls; ++i )
			{
				widgetThatHandledTheInput = mControls[ i ]->Handle( inputState );
				if ( widgetThatHandledTheInput ) break;
			}
		}
	
		// If it's still not handled, we'll try it ourselves;
		if ( ! widgetThatHandledTheInput )
		{
			if ( HasFocus() )
			{
				widgetThatHandledTheInput = this;

				if ( IsInMru() )
				{
					if ( inputState.Released( InputState::CONFIRM | InputState::DOWN ) )
					{
						widgetThatHandledTheInput = GiveFocusToFirstChildWidget();
					}
					else
					if ( inputState.Released( InputState::UP ) )
					{
						widgetThatHandledTheInput = GiveFocusToFirstChildWidget();
						if ( widgetThatHandledTheInput ) widgetThatHandledTheInput = GiveFocusToPrevWidget( widgetThatHandledTheInput );
					}
					else
					if ( inputState.Released( InputState::LEFT ) )
					{					
						GetTree().PrevMruMenu();
					}
					else
					if ( inputState.Released( InputState::RIGHT ) )
					{				
						GetTree().NextMruMenu();
					}
				}
				else
				{	
					if ( inputState.Released( InputState::LEFT_MOUSE | InputState::CONFIRM) )
					{
						MakeMostRecentlyUsed();
					}
					if ( inputState.Released( InputState::CONFIRM | InputState::RIGHT ) )
					{
						widgetThatHandledTheInput = GiveFocusToFirstChildWidget();
					}
					if ( inputState.Released( InputState::BACK | InputState::LEFT ) )
					{					
						widgetThatHandledTheInput = GiveFocusToParent();
					}
					if ( inputState.Released( InputState::DOWN ) )
					{
						if ( Parent() ) widgetThatHandledTheInput = Parent()->GiveFocusToNextWidget( this );
					}
					else
					if ( inputState.Released( InputState::UP ) )
					{					
						if ( Parent() ) widgetThatHandledTheInput = Parent()->GiveFocusToPrevWidget( this );
					}
				}
			}
		}
	}

	return widgetThatHandledTheInput;
}

// -------------------------------------------------------------------------------
void Menu::Open()
{
	int y = Y();
	int x = X();

	// Are the children to the left;
	if ( ChildrenToLeft() )
	{
		if ( IsInMru() )
		{
			x -= GuiMetrics::MENU_INDENT;
			y += Height();				
		}
		else
		{
			x -= Width() - 2 * GuiMetrics::MENU_INDENT; // If we go to the left, we indent horizontally twice instead of once, to avoid a perfect aligment with a menu
			y += GuiMetrics::MENU_INDENT;
		}
	}		
	else
	{
		if ( IsInMru() )
		{	
			x += GuiMetrics::MENU_INDENT;
			y += Height();
		}
		else
		{
			x += Width() - GuiMetrics::MENU_INDENT;
			y += GuiMetrics::MENU_INDENT;
		}
	}
	
	// Does it fit on the screen;
	int totalOpenedHeight = TotalOpenedHeight();
	if ( (y + totalOpenedHeight) > (GuiMetrics::SCREEN_HEIGHT - GuiMetrics::BAR_HEIGHT/2) )
	{
		// No, so move it up;
		y -= (y + totalOpenedHeight) - (GuiMetrics::SCREEN_HEIGHT - GuiMetrics::BAR_HEIGHT/2);
	}

	// Are we too high, underneath the MRU menus, then move it down, and don't care about what drops
	// off the screen anymore;
	if ( y < GuiMetrics::BAR_HEIGHT ) y = GuiMetrics::BAR_HEIGHT;

	// Open all children and controls, starting from the calculating y and x;
	{
		size_t i;
		for ( i = 0; i < mNumChildMenus; ++i )
		{
			if ( mChildMenus[ i ].Get() )
			{
				mChildMenus[ i ]->Show( x, y );
				mChildMenus[ i ]->Close();
				y += mChildMenus[ i ]->Height();
			}
		}		

		for ( i = 0; i < mNumControls; ++i )
		{
			if ( mControls[ i ].Get() )
			{
				mControls[ i ]->Show( x, y );
				y += mControls[ i ]->Height();
			}
		}
	}
	
	if ( Parent() ) Parent()->SetOpenedChild( this );
}

// -------------------------------------------------------------------------------
void Menu::Close()
{	
	size_t i;
	for ( i = 0; i < mNumControls; ++i )
	{
		assert( mControls[ i ].Get() );
		mControls[ i ]->Hide();
	}
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		assert( mChildMenus[ i ].Get() );
		mChildMenus[ i ]->Hide();
	}
}

// -------------------------------------------------------------------------------
void Menu::SetOpenedChild( Menu* child )
{
	// Make sure the given child is actually a child of us;
	if ( child != NULL )
	{
		size_t i = 0; for ( ; i < mNumChildMenus; ++i ) if ( child == mChildMenus[ i ].Get() ) break;
		assert( i != mNumChildMenus );
	}

    if ( mOpenedChild && (mOpenedChild != child) ) mOpenedChild->Close();
	mOpenedChild = child;
}

// -------------------------------------------------------------------------------
void Menu::Update()
{
	for (size_t i = 0; i < mNumChildMenus; ++i ) mChildMenus[ i ].Get()->Update();
	for (size_t i = 0 ; i < mNumControls; ++i ) mControls[ i ].Get()->Update();
}

// -------------------------------------------------------------------------------
void Menu::DoRender( const Renderer& renderer, const GuiColors& guiColors ) const
{
	Reveal::uint32_t bgColor= GetTree().GetGuiColors().mWidgetBackgroundColor;
	if ( GetTree().GetWidgetWithFocus() && GetTree().GetWidgetWithFocus()->Parent() == Parent() ) bgColor= GetTree().GetGuiColors().mWidgetSameLevelBackgroundColor;
	if ( HasFocus() ) bgColor= GetTree().GetGuiColors().mWidgetHighlightedBackgroundColor;
	
	if ( Y() < GuiMetrics::BAR_HEIGHT )
	{
		bgColor= HasFocus() ? GetTree().GetGuiColors().mWidgetBackgroundColor : GetTree().GetGuiColors().mWidgetHighlightedBackgroundColor;
	}

	renderer.Bar(	 X(), Y(), Width(), Height(), bgColor);
	renderer.String( X() + GuiMetrics::TEXT_BORDER_WIDTH, Y() + GuiMetrics::TEXT_BORDER_HEIGHT, Name(), GetTree().GetGuiColors().mTextColor );
	DrawBorder( renderer, guiColors );

	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		if ( mChildMenus[ i ].Get() != mOpenedChild ) mChildMenus[ i ]->Render( renderer, guiColors );
	}
	for ( i = 0; i < mNumControls;	++i ) { mControls[   i ]->Render( renderer, guiColors ); }
	if ( mOpenedChild ) mOpenedChild->Render( renderer, guiColors );
}

// -------------------------------------------------------------------------------
int Menu::TotalOpenedHeight()
{
	int r = 0;
	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i ) r += mChildMenus[ i ]->Height();
	for ( i = 0; i < mNumControls;	++i ) r += mControls[   i ]->Height();
	return r;
}

// -------------------------------------------------------------------------------
void Menu::MakeMostRecentlyUsed()
{
	GetTree().SetMruMenu( *this );
}

// -------------------------------------------------------------------------------
Widget* Menu::GiveFocusToNextWidget( Widget* currentWidgetWithFocus )
{
	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		if ( mChildMenus[ i ].Get() == currentWidgetWithFocus )
		{
			if ( ++i == mNumChildMenus )
			{
				if ( mNumControls != 0 )
				{
                    GetTree().SetWidgetWithFocus( mControls[ 0 ].Get() );
					return mControls[ 0 ].Get();
				}					
				else i = 0;
			}
			
			GetTree().SetWidgetWithFocus( mChildMenus[ i ].Get() );
			return mChildMenus[ i ].Get();
		}
	}

	for ( i = 0; i < mNumControls; ++i )
	{
		if ( mControls[ i ].Get() == currentWidgetWithFocus )
		{
			if ( ++i == mNumControls )
			{
				if ( mNumChildMenus != 0 )
				{
					GetTree().SetWidgetWithFocus( mChildMenus[ 0 ].Get() );
					return mChildMenus[ 0 ].Get();
				}
				else
				{
					i = 0;
				}
			}

			GetTree().SetWidgetWithFocus( mControls[ i ].Get() );
			return mControls[ i ].Get();
		}
	}

	assert( false ); // Should be unreachable;
	return NULL;	 // For release we return NULL;
}

// -------------------------------------------------------------------------------
Widget* Menu::GiveFocusToPrevWidget( Widget* currentWidgetWithFocus )
{
	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		if ( mChildMenus[ i ].Get() == currentWidgetWithFocus )
		{
			if ( i == 0 )
			{
				if ( mNumControls != 0 )
				{
                    GetTree().SetWidgetWithFocus( mControls[ mNumControls - 1 ].Get() );
					return mControls[ mNumControls - 1 ].Get();
				}					
				else i = mNumChildMenus - 1;
			}
			else --i;
			
			GetTree().SetWidgetWithFocus( mChildMenus[ i ].Get() );
			return mChildMenus[ i ].Get();
		}
	}

	for ( i = 0; i < mNumControls; ++i )
	{
		if ( mControls[ i ].Get() == currentWidgetWithFocus )
		{
			if ( i == 0 )
			{
				if ( mNumChildMenus != 0 )
				{
					GetTree().SetWidgetWithFocus( mChildMenus[ mNumChildMenus - 1 ].Get() );
					return mChildMenus[ mNumChildMenus - 1 ].Get();
				}
				else
				{
					i = mNumControls - 1;
				}
			}
			else --i;

			GetTree().SetWidgetWithFocus( mControls[ i ].Get() );
			return mControls[ i ].Get();
		}
	}

	assert( false ); // Should be unreachable;
	return NULL;	 // For release we return NULL;
}

// -------------------------------------------------------------------------------
Widget* Menu::GiveFocusToFirstChildWidget()
{
	if ( mChildMenus[ 0 ].Get() )
	{
		GetTree().SetWidgetWithFocus( mChildMenus[ 0 ].Get() );	
		return mChildMenus[ 0 ].Get();
	}
	else
	if ( mControls[ 0 ].Get() )
	{
		GetTree().SetWidgetWithFocus( mControls[ 0 ].Get() );	
		return mControls[ 0 ].Get();
	}
	else return this;
}

// -------------------------------------------------------------------------------
size_t Menu::DoToString( const char* path, char* buffer, size_t size ) const
{
	// Copy the given path in a local buffer;
	char* s = buffer;
	char p[ MAX_PATH_STRING_LENGTH ];
	strncpy( p, path, MAX_PATH_STRING_LENGTH );
    p[ MAX_PATH_STRING_LENGTH - 1 ] = '\0';
	
	// Append the name of this menu;
	{
		char* q = p + strlen( p );
		*q++ = '/';
		strncpy( q, Name(), MAX_PATH_STRING_LENGTH - (q-p) );
	}

	// Output all children;
	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		const size_t childMenuLength = mChildMenus[ i ]->ToString( p, s, size );
		assert( childMenuLength <= size );
		s += childMenuLength;
		size -= childMenuLength;
	}

	// Output all controls;
	for ( i = 0; i < mNumControls; ++i )
	{
		const size_t controlLength = mControls[ i ]->ToString( p, s, size );
		assert( controlLength <= size );
		s += controlLength;
		size -= controlLength;
	}

	return static_cast< size_t >( s - buffer );
}

// -------------------------------------------------------------------------------
void Menu::DoFromString( const char* data )
{
	// Perhaps the data is ill-formed right away, hence we ignore it;
	if ( *data != '\"' ) return;

	// If the second character is a quote as well;
	if ( data[ 1 ] == '\"' )
	{
		// This is a control-name-value pair;
		data += 3;
		if ( *data++ == '\"' )
		{			
			SmartPtr::ScopedArray< char > nameOfControlArray( new char[ strlen( data ) + 1 ] );
			char* nameOfControl = nameOfControlArray.Get();
			while ( (*data != '\"') && (*data != '\0') )
			{
				*nameOfControl++ = *data++;
			}
			*nameOfControl = '\0';

			data += 2;
			if ( *data == '\"' )
			{
                // Find the control with that name;
				for ( size_t i = 0; i < mNumControls; ++i )
				{
					if ( 0 == strcmp( nameOfControlArray.Get(), mControls[ i ]->Name() ) )
					{
						// Let it deal with the rest;
						mControls[ i ]->FromString( data );
						return;
					}
				}
			}
		}
	}
	else
	{	
		// This needs to be dispatched to a child menu;

		SmartPtr::ScopedArray< char > nameOfChildMenuArray( new char[ strlen( data ) + 1 ] );
		char* nameOfChildMenu = nameOfChildMenuArray.Get();
		SmartPtr::ScopedArray< char > restArray( new char[ strlen( data ) + 1 ] );
		char* rest = restArray.Get();
		
		++data;
		while ( (*data != '\\') && (*data != '/') && (*data != '\"') )
		{
			*nameOfChildMenu++ = *data++;
		}
		*nameOfChildMenu = '\0';
		
		*rest++ = '\"';
		if ( *data++ == '\"' ) *rest++ = '\"';
		
		while ( (*data != '\n') && (*data != '\0') )
		{
			*rest++ = *data++;
		}
		*rest = '\0';

		// Find the child menu with that name;
		for ( size_t i = 0; i < mNumChildMenus; ++i )
		{
			if ( 0 == strcmp( nameOfChildMenuArray.Get(), mChildMenus[ i ]->Name() ) )
			{
				// Let it deal with the rest;
				mChildMenus[ i ]->FromString( restArray.Get() );
				return;
			}
		}
	}
}

// -------------------------------------------------------------------------------
void Menu::Remove( const char* path, const char* name )
{
	// Skip some slashes and backslashes;
	while ( (*path == '\\') || (*path == '/') ) ++path;

	// If we still have something left;
	if ( *path == '\0' )
	{
		// Cut off excess characters;
		char controlName[ Widget::MAX_NAME_STRING_LENGTH ];
		strncpy( controlName, name, Widget::MAX_NAME_STRING_LENGTH );
		controlName[ Widget::MAX_NAME_STRING_LENGTH - 1 ] = '\0';

		// Look for the control
		for ( size_t i = 0; i < mNumControls; ++i )
		{
			if ( 0 == strcmp( controlName, mControls[ i ]->Name() ) )
			{
				while ( i < (mNumControls - 1) )
				{
					mControls[ i ].Swap( mControls[ i + 1 ] );
					++i;
				}
				mControls[ mNumControls - 1 ].Reset();
				--mNumControls;
				Open();	// Re-open, so we fill in a possible gap;
				return;
			}
		}
	}
	else
	{
		// Get the first menu-name in the path;
		char  menuNameArray[ Widget::MAX_NAME_STRING_LENGTH ];
		char* menuName = menuNameArray;
		while ( (*path != '\\') && (*path != '/') && (*path != '\0') )
		{
			*menuName++ = *path++;
			if ( (menuName  - menuNameArray) >= (MAX_NAME_STRING_LENGTH - 1) )
			{
				while ( (*path != '\\') && (*path != '/') && (*path != '\0') ) ++path;
				break;
			}
        }
		*menuName = '\0';

		// Skip some more slashes and backslashes;
		while ( (*path == '\\') || (*path == '/') ) ++path;

		// Look for the child menu;
		for ( size_t i = 0; i < mNumChildMenus; ++i )
		{
			if ( 0 == strcmp( menuNameArray, mChildMenus[ i ]->Name() ) )
			{
				// If we have a name, continue removing it;
				if ( name  )
				{
					mChildMenus[ i ]->Remove( path, name );
				}
				else
				{
					// Was this the last menu name in the path;
					if ( *path == '\0' )
					{
						// Perhaps its in an MRU, so remove it there;
						GetTree().RemoveFromMrus( *mChildMenus[ i ] );

						// Remove it from this (its parent);
						mOpenedChild = NULL;
						while ( i < (mNumChildMenus - 1) )
						{
							mChildMenus[ i ].Swap( mChildMenus[ i + 1 ] );
							++i;
						}
						mChildMenus[ mNumChildMenus - 1 ].Reset();
						--mNumChildMenus;
						if ( Parent() ) Parent()->Open();	// Re-open the parent, so we fill in a possible gap;
					}
					else
					{
						mChildMenus[ i ]->Remove( path, name );
					}					
				}

				return;
			}
		}
	}
}

// -------------------------------------------------------------------------------
bool Menu::ChildrenToLeft() const
{	
	bool tryToGoLeft = false;

	// If we have no parent,
	if ( Parent() == 0 )
	{
		// If we are an MRU, we try to go towards the center of the screen;
		if ( IsInMru() )
		{
			if ( X() < (GuiMetrics::SCREEN_WIDTH/2) )
				tryToGoLeft = false;
			else
				tryToGoLeft = true;

		}
		else // We try to get away from the center of the screen;
		{
			if ( X() < (GuiMetrics::SCREEN_WIDTH/2) )
				tryToGoLeft = true;
			else
				tryToGoLeft = false;
		}
	}
	else
	if ( Parent()->X() < X() )
	{
		tryToGoLeft = false;
	}
	else
	{
		tryToGoLeft = true;
	}

	if ( !tryToGoLeft )
	{
		// We try to go to the right;
		if ( X() > (GuiMetrics::SCREEN_WIDTH - 2 * GuiMetrics::GetWidgetWidth()) )
		{
			// There is no more room on the right, so go back to the left;
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		// We try to go to the left;
		if ( X() < GuiMetrics::GetWidgetWidth() )
		{
			// There is no more room on the left, so go back to the right;
			return false;
		}
		else
		{
			return true;
		}
	}
}

// -------------------------------------------------------------------------------
bool Menu::IsChildOf( const Widget* w ) const
{
	size_t i;
	for ( i = 0; i < mNumChildMenus; ++i )
	{
		if ( w == mChildMenus[ i ].Get() ) return true;
		if ( mChildMenus[ i ]->IsChildOf( w ) ) return true;
	}

	for ( i = 0; i < mNumControls; ++i )
	{
		if ( w == mControls[ i ].Get() ) return true;
	}

	return false;
}

// -------------------------------------------------------------------------------
Widget* Menu::GetWidget ( const char* path )
{
	// Local function definition;
	struct StringInsensitiveEquals
	{
		bool operator () ( const char* a, const char* b )
		{
			while ( tolower( static_cast< unsigned char >( *a++ ) ) == tolower( static_cast< unsigned char >( *b++ ) ) )
				if ( (*a == 0) || (*b == 0) )
					if ( (*a == 0) && (*b == 0) ) return true;
					else return false;
			return false;
		}
	} StrICmp;

	// Skip some slashes and backslashes;
	while ( (*path == '\\') || (*path == '/') ) ++path;

	// Get the first menu-name in the path;
	char  menuNameArray[ Widget::MAX_NAME_STRING_LENGTH ];
	char* menuName = menuNameArray;
	while ( (*path != '\\') && (*path != '/') && (*path != '\0') )
	{
		*menuName++ = *path++;
		if ( (menuName  - menuNameArray) >= (MAX_NAME_STRING_LENGTH - 1) )
		{
			while ( (*path != '\\') && (*path != '/') && (*path != '\0') ) ++path;
			break;
		}
    }
	*menuName = '\0';

	// Skip some more slashes and backslashes;
	while ( (*path == '\\') || (*path == '/') ) ++path;

	//Check to see if the path points to a control
	for ( size_t i = 0; i < mNumControls; i++)
	{
		if ( StrICmp( menuNameArray, mControls[ i ]->Name() ) )
			return mControls[ i ].Get();
	}

	// Look for the child menu;
	for ( size_t i = 0; i < mNumChildMenus; ++i )
	{
		if ( StrICmp( menuNameArray, mChildMenus[ i ]->Name() ) )
		{
			// Was this the last menu name in the path;
			if ( *path == '\0' )
			{
				return mChildMenus[ i ].Get();
			}
			else
			{
				return mChildMenus[ i ]->GetWidget( path );
			}
		}
	}

	return NULL;
}

	} // Namespace Impl;
} // Namespace Reveal;
