//////////////////////////////////////////////////////////////////////////////
//
// Tools_GUIMenu_System.cpp
//
// Copyright (c) 2006 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

#include "Core/Asura.h"

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "Tools_GUIMenu_System.h"


// Asura includes
#include "ChunkSystem/Asura_Chunk_GUIMenu.h"
#include "ChunkSystem/Asura_Chunk_Texture.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Asura_TextureManagement.h"
#include "Debugging/Asura_Logfile.h"
#include "Debugging/Asura_Debug_Timers.h"
#include "Entity/Asura_StaticMessage_System.h"
#include "Entity/Asura_StaticMessageBlock.h"
#include "FileAccess/Asura_FileAccess.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"

//Tools
#include "Tools_Overlays.h"

#include "GUIMenu/Tools_GUIMenu_XMLExporter.h"

#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Dialog.h"

#include "Load&Save/Tools_SaveAsura.h"
#include "Load&Save/LevelExport/Tools_Level_Export.h"
#include "Load&Save/Tools_LoadedFileList.h"
#include "Misc/Tools_MessageLog.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Misc/Tools_Timed_Messages.h"
#include "PC/FileSystem/Tools_FileSystem.h"

/////////////////////////////////////////////////////////////////////////////////////////

bool Tools_GUIMenu_System::s_bGlobalSettingsChanged = false;

Asura_Vector_2 Tools_GUIMenu_System::s_xOverlayPosition(25.0f,2.0f);

const char* Tools_GUIMenu_System::s_apszAvailableMenuNames[ASURA_GUIMENU_MAX_MENU_PAGES+1];

const Asura_Char** Tools_GUIMenu_System::s_ppcMenuWidgetNames;
const Asura_Char** Tools_GUIMenu_System::s_ppcWidgetElementNames;
Asura_Hash_ID* Tools_GUIMenu_System::s_puMenuWidgetHashes;

u_int Tools_GUIMenu_System::s_uWidgetCount = 0;

int Tools_GUIMenu_System::s_iSelectedMenuIndex;
Asura_Message_GUIMenu_Activate* Tools_GUIMenu_System::s_pxSelectedMenuMsgData;

List<Asura_String> Tools_GUIMenu_System::s_xModifiedFiles;
List<Tools_GUIMenu_FileData*> Tools_GUIMenu_System::s_xFileDataList;
bool Tools_GUIMenu_System::s_bAnimatorsModified = false;
bool Tools_GUIMenu_System::s_bTextureFlagsModified = false;

bool Tools_GUIMenu_System::s_bAudioDataChanged;

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

	DestroyStaticCollections();

	for( int i(0); i<ASURA_GUIMENU_MAX_MENU_PAGES+1; ++i )
	{	
		s_apszAvailableMenuNames[i] = NULL;	
	}

	s_ppcMenuWidgetNames = NULL;
	s_puMenuWidgetHashes = NULL;
	
	s_ppcWidgetElementNames = NULL;

	s_uWidgetCount = 0;

	s_iSelectedMenuIndex = 0;
	s_pxSelectedMenuMsgData = NULL;

	//load global menu files
	Tools_FileSystem::LoadAsuraFiles(szTOOLS_GUIMENU_SEQUENCES_FILE);
	Tools_FileSystem::LoadAsuraFiles(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
	Tools_FileSystem::LoadAsuraFiles("GUIMenu\\*.gui", (TOOLS_FILEFIND_RECURSIVE | TOOLS_FILEFIND_IGNOREBACKUPDIR) );

	s_bAudioDataChanged = false;
}

void Tools_GUIMenu_System::Shutdown()
{
	DestroyStaticCollections();

	while(s_xFileDataList.size())
	{  
		delete s_xFileDataList.first_entry();
		s_xFileDataList.delete_first_entry();
	}
}

void Tools_GUIMenu_System::DestroyStaticCollections()
{
	if( s_ppcMenuWidgetNames != NULL)
	{
		delete []s_ppcMenuWidgetNames;
		s_ppcMenuWidgetNames = NULL;
	}

	if( s_puMenuWidgetHashes != NULL)
	{
		delete []s_puMenuWidgetHashes;
		s_puMenuWidgetHashes = NULL;
	}

	if( s_ppcWidgetElementNames != NULL)
	{
		delete []s_ppcWidgetElementNames;
		s_ppcWidgetElementNames = NULL;
	}

	s_uWidgetCount = 0;
}


void Tools_GUIMenu_System::Update()
{
}


bool Tools_GUIMenu_System::IsModified()
{
	return (s_xModifiedFiles.size() > 0) || s_bAnimatorsModified || s_bTextureFlagsModified;
}


void Tools_GUIMenu_System::SetModified(class Asura_GUIMenu_Menu_Page* pxMenu)
{

	Asura_Assert(pxMenu,"");
	SetModified(pxMenu->GetFilename());

}


void Tools_GUIMenu_System::SetModified(const char* szFilename)
{

	Asura_Assert(szFilename && *szFilename,"Invalid filename");

	//file already in list?
	for(LIF<Asura_String> xModifiedLIF(&s_xModifiedFiles);!xModifiedLIF.done();xModifiedLIF.next())
	{
		if(!xModifiedLIF().Compare(szFilename)) return;
	}

	//File wasn't already flagged as modified ,so check whether its going to be okay to write to it
	Asura_String xFullFilename;
	GetFullFilename(szFilename,xFullFilename);

	Tools_SaveAsura::WarnIfReadOnly(xFullFilename.GetString());	

	s_xModifiedFiles.add_entry(szFilename);
}


void Tools_GUIMenu_System::SetAnimatorsModified()
{
	if(s_bAnimatorsModified) return;

	Tools_SaveAsura::WarnIfReadOnly(szTOOLS_GUIMENU_SEQUENCES_FILE);
	s_bAnimatorsModified = true;
}

void Tools_GUIMenu_System::SetTextureFlagsModified()
{
	if(s_bTextureFlagsModified) return;

	Tools_SaveAsura::WarnIfReadOnly(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
	s_bTextureFlagsModified = true;
}


bool Tools_GUIMenu_System::CanSaveFile(const char* szFilename)
{
	Asura_Assert(szFilename && *szFilename,"Invalid filename");

	Asura_String xFullFilename;
	GetFullFilename(szFilename,xFullFilename);

	return Tools_SaveAsura::CanSaveFile(xFullFilename.GetString(),false);	
}


bool Tools_GUIMenu_System::IsAudioModified( void)
{
	return s_bAudioDataChanged;
}

void Tools_GUIMenu_System::SetAudioModified( void)
{
	//File wasn't already flagged as modified ,so check whether its going to be okay to write to it
	Asura_String xFullFilename;
	GetFullAudioFilename( szTOOLS_GUIMENU_AUDIO, xFullFilename);

	Tools_SaveAsura::WarnIfReadOnly(xFullFilename.GetString());	

	s_bAudioDataChanged = true;
}

void Tools_GUIMenu_System::GetFullAudioFilename(const char* szFilename,Asura_String& xFullFilename)
{
	char szTemp[MAX_PATH];

	Asura_PrintfToBfr(szTemp, "GUIMenu\\%s.asr", sizeof(szTemp), true, szFilename);
	xFullFilename = szTemp;
}

void Tools_GUIMenu_System::GetFullFilename(const char* szFilename,Asura_String& xFullFilename)
{
	char szTemp[MAX_PATH];
	
	if(!stricmp(szFilename,"Level"))
	{
		Asura_PrintfToBfr(szTemp,"%s.gui%s",sizeof(szTemp),true,Tools_SaveAsura::GetNameWithoutExtension(),Tools_Level_Export::ShouldExportBigEndian() ? ASURA_STANDARD_FILE_EXTENSION_BE_SUFFIX : "");
		xFullFilename = szTemp;
	}
	else
	{
		Asura_PrintfToBfr(szTemp,"GUIMenu\\%s.gui",sizeof(szTemp),true,szFilename);
		xFullFilename = szTemp;
	}
}

void Tools_GUIMenu_System::GetIDListFilename(const char* szFilename,Asura_String& xFullFilename)
{
	char szTemp[MAX_PATH];

	if(!stricmp(szFilename,"Level"))
	{
		Asura_PrintfToBfr(szTemp,"%s_GUIMenu_ID_List.txt",sizeof(szTemp),true,Tools_SaveAsura::GetNameWithoutExtension());
		xFullFilename = szTemp;
	}
	else
	{
		Asura_PrintfToBfr(szTemp,"GUIMenu\\%s_GUIMenu_ID_List.txt",sizeof(szTemp),true,szFilename);
		xFullFilename = szTemp;
	}
}



void Tools_GUIMenu_System::SaveAll()
{

	if(Tools_Level_Export::IsExport())
	{
		//Only save the level specific file during exports at the moment ,since
		//that will gain a filename in LevelExportTemp. RAR 07/02/2007
		SaveMenuPageAndContents("Level");
	}
	else
	{
		int iJunkIndex;
		Asura_NameTree xFileTree;

		SaveAnimators();

		//attempt to save all the modified files
		//(this ensures that any files that have lost all their events will get saved)
		for(LIF<Asura_String> xModifiedLIF(&s_xModifiedFiles);!xModifiedLIF.done();)
		{
			//keep track of the files done
			xFileTree.FindNodeIndexByName(xModifiedLIF().GetString(),true,iJunkIndex);

			if(SaveMenuPageAndContents(xModifiedLIF().GetString()))
			{
				xModifiedLIF.delete_current();
			}
			else
			{
				xModifiedLIF.next();
			}
		}

		//scan through all menus for other files to save
		for(u_int u(0);u<Asura_GUIMenu_System::GetCurrentMenuListCount();++u )
		{
			Asura_GUIMenu_Menu_Page* pxMenuPage(Asura_GUIMenu_System::GetMenuPageByIndex( u ));
			const char* szFilename = pxMenuPage->GetFilename();

			if(!szFilename || !*szFilename) continue;

			if(!xFileTree.FindNodeIndexByName(szFilename,true,iJunkIndex))
			{
				SaveMenuPageAndContents(szFilename);
			}
		}

		// -- Save the audio data
		SaveAudioData();
		s_bAudioDataChanged = false;
	}
}

void Tools_GUIMenu_System::SaveModified()
{

	//Don't save menu files in this way for the moment during exports. RAR 07/02/2007
	if(Tools_Level_Export::IsExport()) return;

	if(s_bAnimatorsModified)
	{
		SaveAnimators();
	}
	
	if(s_bTextureFlagsModified)
	{
		SaveTextureFlags();
	}

	for(LIF<Asura_String> xModifiedLIF(&s_xModifiedFiles);!xModifiedLIF.done();)
	{
		if(SaveMenuPageAndContents(xModifiedLIF().GetString()))
		{
			xModifiedLIF.delete_current();
		}
		else
		{
			xModifiedLIF.next();
		}
	}

	if( s_bAudioDataChanged)
	{
		SaveAudioData();
		s_bAudioDataChanged = false;
	}
}


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

bool Tools_GUIMenu_System::SaveAudioData()
{
	if(Tools_Level_Export::IsExport())
	{
		//Saving of menus for export is now dealt with by functions in Tools_GUIMenu_Export.cpp
		//RAR 02/03/2007
		return false;
	}

	Asura_SaveBlock xSaveBlock;
	Asura_Chunk_GUIMenu_Audio::Create(&xSaveBlock);

	xSaveBlock.AddAsuraTerminator();

	Asura_String xFullFileName;
	GetFullAudioFilename( szTOOLS_GUIMENU_AUDIO, xFullFileName);
	Tools_FileSystem::EnsureDirectoryExists( xFullFileName.GetString());
	bool bSuccess = xSaveBlock.SaveFile( xFullFileName.GetString(), true);
	if(bSuccess)
	{
		Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s.",szTOOLS_GUIMENU_AUDIO);
		Tools_LoadedFileList::UpdateModifiedTime(szTOOLS_GUIMENU_AUDIO);
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to save %s",szTOOLS_GUIMENU_AUDIO);
	}

	return bSuccess;	

}

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


void Tools_GUIMenu_System::SaveAnimators()
{

	Asura_SaveBlock xSaveBlock;
	Asura_Chunk_GUIMenu_AnimatorSequences::Create(&xSaveBlock);

	xSaveBlock.AddAsuraTerminator();
	Tools_FileSystem::EnsureDirectoryExists(szTOOLS_GUIMENU_SEQUENCES_FILE);
	bool bSuccess = xSaveBlock.SaveFile(szTOOLS_GUIMENU_SEQUENCES_FILE,true);
	if(bSuccess)
	{
		Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s.",szTOOLS_GUIMENU_SEQUENCES_FILE);
		Tools_LoadedFileList::UpdateModifiedTime(szTOOLS_GUIMENU_SEQUENCES_FILE);
		s_bAnimatorsModified = false;
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to save %s",szTOOLS_GUIMENU_SEQUENCES_FILE);
	}
}

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


void Tools_GUIMenu_System::AddTextureToNameTree(int iTextureID, void* pTree)
{
	if(iTextureID == ASURA_TEXTURE_NONE) return;
	Asura_NameTree* pxNameTree = (Asura_NameTree*) pTree;

	const Asura_String* pxName = Asura_Texture_Management::GetTextureName(iTextureID);
	if(pxName)
	{
		int iJunkIndex;
		pxNameTree->FindNodeIndexByName( pxName->GetString(), true, iJunkIndex);
	}
}

void Tools_GUIMenu_System::SaveTextureFlags()
{
	Asura_SaveBlock xSaveBlock;

	//determine the textures used by the menus
	Asura_NameTree xTextureNameTree;
	for( u_int i=0; i<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++i )
	{
		Asura_GUIMenu_Menu_Page* pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( i);

		pxMenuPage->TraverseUsedTextures(AddTextureToNameTree, &xTextureNameTree);
	}
	
	
	int iNumTextures = xTextureNameTree.GetNumberOfNodes();
	if(iNumTextures)
	{
		//get the flags used by those textures
		int* piTextureFlags = new int[iNumTextures];
		for(int i=0; i<iNumTextures; i++)
		{
			const Asura_String* pxName = xTextureNameTree.FindNodeNameByIndex(i);
			int iTextureID = Asura_Texture_Management::GetTextureIndex(pxName->GetString());

			piTextureFlags[i] = (iTextureID == ASURA_TEXTURE_NONE) ? 0 : Asura_Texture_Management::GetTextureFlags(iTextureID);
		}

		//write out the texture names and flags chunks
		Asura_Chunk_TextureNames::Create(&xTextureNameTree, &xSaveBlock);
		Asura_Chunk_TextureFlags::Create(iNumTextures, piTextureFlags, &xSaveBlock);

		delete [] piTextureFlags;

	}	


	xSaveBlock.AddAsuraTerminator();
	Tools_FileSystem::EnsureDirectoryExists(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
	bool bSuccess = xSaveBlock.SaveFile(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE,true);
	if(bSuccess)
	{
		Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s.",szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
		Tools_LoadedFileList::UpdateModifiedTime(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
		s_bAnimatorsModified = false;
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to save %s",szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
	}
}


bool Tools_GUIMenu_System::SaveMenuPageAndContents(const char* szFileName)
{
	u_int i;//, j;

	if(Tools_Level_Export::IsExport())
	{
		//Saving of menus for export is now dealt with by functions in Tools_GUIMenu_Export.cpp
		//RAR 02/03/2007
		return false;
	}

	Asura_String xFullFilename;
	GetFullFilename( szFileName, xFullFilename);

	if(!Tools_SaveAsura::CanSaveFile( xFullFilename.GetString(),true))
	{
		return false;
	}


	Asura_SaveBlock xSaveBlock;

#ifdef TOOLS_EXPORT_MENUS_XML
	Tools_GUIMenu_XMLExporter xGUIMenuExporter("GUIMenu");
#endif //TOOLS_EXPORT_MENUS_XML

	if(!Tools_Level_Export::IsExport())
	{
		Asura_Chunk_GUIMenu_File::Create(szFileName, &xSaveBlock);
	}

	Asura_HashTree xTextPageTree;
	List<Asura_GUIMenu_Menu_Page*> xMenuList;
	
	//list the menus being saved , and the text pages used by them
	for( i=0; i<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++i )
	{
		Asura_GUIMenu_Menu_Page* pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex(i);

		//Only create chunks for menus that belong to the current file RAR 07/02/2007
		const char* szMenuFileName = pxMenuPage->GetFilename();
		if(!szMenuFileName) continue;
		if(strcmp(szMenuFileName,szFileName)) continue;

		xMenuList.add_entry(pxMenuPage);
		pxMenuPage->ListUsedTextPages(xTextPageTree);
	}

	if(xTextPageTree.GetNumberOfNodes())
	{
		//make a chunk for each text page used
		Asura_Hash_ID* puTextPage = new Asura_Hash_ID[xTextPageTree.GetNumberOfNodes()];
		xTextPageTree.MakeHashList(puTextPage);
		
		for(int i=0; i<xTextPageTree.GetNumberOfNodes(); i++)
		{			
			Asura_Chunk_GUIMenu_TextPage::Create(puTextPage[i], &xSaveBlock);
		}

		delete [] puTextPage;
	}
	
	
	for( LIF<Asura_GUIMenu_Menu_Page*> xMenuLIF(&xMenuList); !xMenuLIF.done(); xMenuLIF.next())
	{
		Asura_GUIMenu_Menu_Page* pxMenuPage = xMenuLIF();

		Asura_Chunk_GUIMenu::Create( pxMenuPage, &xSaveBlock);
#ifdef TOOLS_EXPORT_MENUS_XML
		//finally, export them
		xGUIMenuExporter.StartXMLExport( pxMenuPage );
#endif //TOOLS_EXPORT_MENUS_XML
	}

	xSaveBlock.AddAsuraTerminator();
	Tools_FileSystem::EnsureDirectoryExists(xFullFilename.GetString());
	bool bSuccess = xSaveBlock.SaveFile(xFullFilename.GetString(),false);
	if(bSuccess)
	{
		Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s.",xFullFilename.GetString());
		Tools_LoadedFileList::UpdateModifiedTime(xFullFilename.GetString());
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Failed to save %s",xFullFilename.GetString());
	}

#ifdef TOOLS_EXPORT_MENUS_XML
	//write XML out
	xGUIMenuExporter.WriteXMLToFile( szFileName );
#else
	// (MH - 31.05.2007) superceded by XML output
	OutputGUIMenuIDInfo( szFileName);
#endif // TOOLS_EXPORT_MENUS_XML

	return bSuccess;	
}

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

bool Tools_GUIMenu_System::OutputGUIMenuIDInfo( const char* szFileName)
{
	u_int i;
	Asura_String xFullFilename;
	Asura_GUIMenu_Menu_Page* pxMenuPage;

	GetIDListFilename( szFileName, xFullFilename);

	if(!Tools_SaveAsura::CanSaveFile( xFullFilename.GetString(),true))
	{
		return false;
	}

	Asura_SimpleLogfileClear(( xFullFilename.GetString()));

	for( i=0; i<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++i )
	{
		pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( i);

		//Ignore menus that don't belong to the current file RAR 07/02/2007
		const char* szMenuFileName = pxMenuPage->GetFilename();
		if(!szMenuFileName) continue;
		if(strcmp(szMenuFileName,szFileName)) continue;

		pxMenuPage->OutputGUIMenuIDInfo( xFullFilename);
		Asura_SimpleLogfileOutput(( xFullFilename.GetString(), "\n---------------------------------------------------------------------------\n"));
	}

	Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s.",xFullFilename.GetString());
	Tools_LoadedFileList::UpdateModifiedTime(xFullFilename.GetString());

	return true;	
}

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

char** Tools_GUIMenu_System::GetAvailableMenuPageNames( int* piMenuPageCount)
{
	u_int u, uOffset;
	Asura_GUIMenu_Menu_Page* pxMenuPage;

	s_apszAvailableMenuNames[0] = "None";

	uOffset = 1;

	for( u=0; u<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++u )
	{
		pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( u);

		// -- only add the menu if it's not part of the alternate menu page list --
		//Disabled filtering out of menus in this way as a quick fix , since the code that actually
		//wants to use this doesn't cope with the indeces in the list not matching the indeces in the menu system.
		//RAR 02/07/2007
		//if( (pxMenuPage->GetMenuPageFlags()&ASURA_GUIMENU_MENUPAGE_FLAG_CODE_UPDATE_AND_RENDER_ONLY) == 0)
		{
			s_apszAvailableMenuNames[uOffset++] = pxMenuPage->GetNameAsChar();
		}
	}

	if( piMenuPageCount != NULL)	*piMenuPageCount = uOffset;

	return (char**)&s_apszAvailableMenuNames[0];
}

// Recurse all the descendants of pxWidgetRoot and count them.
u_int Tools_GUIMenu_System::CountAllWidgetsRecursive( Asura_GUIMenu_Root* pxWidgetRoot)
{
	u_int uCount = pxWidgetRoot->GetContainerCount();
	if( pxWidgetRoot != NULL)
	{
		for( u_int u = 0; u<pxWidgetRoot->GetContainerCount(); ++u)
		{
			uCount += CountAllWidgetsRecursive( pxWidgetRoot->GetContainerItem( u) );
		}
	}

	return uCount;
}

// Recurse all the descendants of pxWidgetRoot and store their names in s_ppcMenuWidgetNames array and
// hash ids in s_puMenuWidgetHashes array.
u_int Tools_GUIMenu_System::GetAllWidgetNamesRecursive( Asura_GUIMenu_Root* pxWidgetRoot, u_int uCurrentCount)
{
	Asura_GUIMenu_Root* pxChild;

	if( pxWidgetRoot != NULL)
	{
		for( u_int u = 0; u<pxWidgetRoot->GetContainerCount(); ++u)
		{
			Asura_Assert((uCurrentCount+1) < (s_uWidgetCount+1),"Array bounds error in GetAllWidgetNamesRecursive" );
			if ((uCurrentCount+1) < (s_uWidgetCount+1))
			{
				pxChild = pxWidgetRoot->GetContainerItem( u);
				s_ppcMenuWidgetNames[uCurrentCount+1] = pxChild->GetNameAsChar();
				s_puMenuWidgetHashes[uCurrentCount+1] = pxChild->GetID();

				uCurrentCount++;
				uCurrentCount = GetAllWidgetNamesRecursive( pxChild, uCurrentCount);
			}
		}
	}

	return uCurrentCount;
}

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

// Recurse all the descendants of the menu and return their names.
// If pHashIDs is not NULL then return a list of hash IDs as well, in the same order are the strings.
const Asura_Char** Tools_GUIMenu_System::GetAllMenuWidgetNames( Asura_Hash_ID uHashMenu, int* piItemCount, const Asura_Hash_ID** puHashIDs)
{
	Asura_GUIMenu_Root* pxMenuRoot;
	Asura_GUIMenu_Menu_Page* pxMenuPage;
	bool bSet = false;

	// Free static pointers.
	if( s_ppcMenuWidgetNames != NULL)
	{
		delete []s_ppcMenuWidgetNames;
		s_ppcMenuWidgetNames = NULL;
	}

	if( s_puMenuWidgetHashes != NULL)
	{
		delete []s_puMenuWidgetHashes;
		s_puMenuWidgetHashes = NULL;
	}

	if( s_ppcMenuWidgetNames == NULL)
	{
		if( uHashMenu != ASURA_HASH_ID_UNSET)
		{
			pxMenuRoot = Asura_GUIMenu_System::GetMenuPageByID( uHashMenu);
			if( pxMenuRoot != NULL)
			{
				pxMenuPage = static_cast<Asura_GUIMenu_Menu_Page*>(pxMenuRoot);

				// Get the total count of widgets.
				s_uWidgetCount = CountAllWidgetsRecursive( pxMenuPage);

				// Allocate space in static pointers
				s_puMenuWidgetHashes = new Asura_Hash_ID[s_uWidgetCount+1];

				s_ppcMenuWidgetNames = new const Asura_Char*[s_uWidgetCount+1];
				s_ppcMenuWidgetNames[0] = "None";
				s_puMenuWidgetHashes[0] = 0;

				GetAllWidgetNamesRecursive( pxMenuPage, 0);

				if( piItemCount != NULL)
				{
					*piItemCount = s_uWidgetCount+1;
				}

				bSet = true;
			}
		}
	}

	if ( puHashIDs != NULL )
	{
		(*puHashIDs) = s_puMenuWidgetHashes;
	}

	if( bSet == false)
	{
		s_ppcMenuWidgetNames = new const Asura_Char*[1];
		s_ppcMenuWidgetNames[0] = "None";		

		if( piItemCount != NULL)
		{
			*piItemCount = 1;	
		}
	}

	return s_ppcMenuWidgetNames;
}

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

const Asura_Hash_ID* Tools_GUIMenu_System::GetCurrentHashIds()
{
	return s_puMenuWidgetHashes;
}

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

const Asura_Char** Tools_GUIMenu_System::GetAllWidgetElementNames( Asura_Hash_ID uHashWidget, int* piItemCount, Element_Filter eFilterType)
{
	u_int u, v, w;
	Asura_GUIMenu_Root* pxMenuRoot;
	Asura_GUIMenu_Menu_Page* pxMenuPage;
	Asura_GUIMenu_Root* pxWidgetRoot;
	Asura_GUIMenu_Root* pxElementRoot;
	u_int uListOffset;
	bool bSet = false;

	if( s_ppcWidgetElementNames != NULL)
	{
		delete []s_ppcWidgetElementNames;
		s_ppcWidgetElementNames = NULL;
	}

	if( uHashWidget != ASURA_HASH_ID_UNSET)
	{
		for( u=0; u<Asura_GUIMenu_System::GetCurrentMenuListCount(); u++)
		{
			pxMenuRoot = Asura_GUIMenu_System::GetMenuPageByIndex( u);
			if( pxMenuRoot)
			{
				pxMenuPage = static_cast<Asura_GUIMenu_Menu_Page*>(pxMenuRoot);

				for( v=0; v<pxMenuPage->GetContainerCount(); v++)
				{
					pxWidgetRoot = pxMenuPage->GetContainerItem( v);
					if( pxWidgetRoot)
					{
						if( pxWidgetRoot->GetID() == uHashWidget)
						{
							s_ppcWidgetElementNames = new const Asura_Char*[pxWidgetRoot->GetContainerCount()+1];
							s_ppcWidgetElementNames[0] = "None";
							uListOffset = 1;
							bSet = true;

							for( w=0; w<pxWidgetRoot->GetContainerCount(); w++)
							{
								pxElementRoot = pxWidgetRoot->GetContainerItem( w);
								if( pxElementRoot)
								{
									bool bAllow = false;

									if( eFilterType == ELEMENT_FILTER_ALLOW_ALL)
									{
										bAllow = true;
									}
									else if( eFilterType == ELEMENT_FILTER_ALLOW_IMAGES)
									{
										if( pxElementRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_IMAGE)
										{
											bAllow = true;
										}
									}
									else if( eFilterType == ELEMENT_FILTER_ALLOW_PATH)
									{
										if( pxElementRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_PATH)
										{
											bAllow = true;
										}
									}
									else if( eFilterType == ELEMENT_FILTER_ALLOW_TEXT)
									{
										if( pxElementRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_TEXT)
										{
											bAllow = true;
										}
									}
									else if( eFilterType == ELEMENT_FILTER_ALLOW_STATUSTEXT)
									{
										if( pxElementRoot->GetType() == Asura_GUIMenu_Root::ASURA_GUIMENU_TYPEID_ELEMENT_STATUSTEXT)
										{
											bAllow = true;
										}
									}

									if( bAllow == true)
									{
										s_ppcWidgetElementNames[uListOffset++] = pxElementRoot->GetNameAsChar();
									}
								}
							}
						}
					}
				}
			}
		}

	}

	if( bSet == false)
	{
		s_ppcWidgetElementNames = new const Asura_Char*[1];
		s_ppcWidgetElementNames[0] = "None";
		uListOffset = 1;
	}

	if( piItemCount != NULL)
	{
		*piItemCount = uListOffset;
	}

	return s_ppcWidgetElementNames;
}

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

void Tools_GUIMenu_System::AddOverlayControls_ActivateGUIMenuPage(struct Asura_StaticMessage* pxMessage,class Asura_Overlay* pxOverlay,class Asura_Vector_2& xOffset)
{
	Asura_Message_GUIMenu_Activate* pxData = NULL;
	Asura_Dialog	*pxNewDialogue;
	char** ppszMenuPageNames;
	int iMenuPageCount;
	u_int i;
	Asura_GUIMenu_Root* pxMenuPage;

	pxData = static_cast< Asura_Message_GUIMenu_Activate* >( pxMessage->m_pData );

	ppszMenuPageNames = GetAvailableMenuPageNames( &iMenuPageCount);

	s_iSelectedMenuIndex = 0;

	if( pxData->uHashMenuPageID != ASURA_HASH_ID_UNSET)	// this data has an id set, so use it
	{
		for( i=0; i<Asura_GUIMenu_System::GetCurrentMenuListCount(); i++)
		{
			pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( i);

			if( pxMenuPage->GetID() == pxData->uHashMenuPageID)
			{
				// found a match, so set the starting index in the dropdown list to this one.
				s_iSelectedMenuIndex = i+1;
			}
		}
	}

	pxNewDialogue = new Asura_DropDown_List_Dialog( xOffset,
													ppszMenuPageNames,
													&s_iSelectedMenuIndex,
													Asura_Maths::Min( 8,iMenuPageCount),  // determines the number of lines displayed
													iMenuPageCount,
													_MenuNameListBoxCallBack);
	pxOverlay->AddDialog(pxNewDialogue);
	xOffset.y += Asura_Dialog::LargeSpacing();

	s_pxSelectedMenuMsgData = pxData;
}

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

void Tools_GUIMenu_System::_MenuNameListBoxCallBack( void)
{
	Asura_GUIMenu_Root* pxMenuPage;

	if( (s_pxSelectedMenuMsgData != NULL) && ( s_iSelectedMenuIndex != 0))
	{
		pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( s_iSelectedMenuIndex - 1);

		s_pxSelectedMenuMsgData->uHashMenuPageID = pxMenuPage->GetID();
	}
	else
	{
		s_pxSelectedMenuMsgData->uHashMenuPageID = ASURA_HASH_ID_UNSET;
	}
}

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



void Tools_GUIMenu_System::SetFilesToCheckForExternalModification()
{
	int iJunkIndex;
	Asura_NameTree xFileTree;

	//scan through all events for files being used
	for( u_int u(0); u<Asura_GUIMenu_System::GetCurrentMenuListCount(); ++u )
	{
		const Asura_GUIMenu_Menu_Page* pxMenuPage = Asura_GUIMenu_System::GetMenuPageByIndex( u );

		const char* szFilename = pxMenuPage->GetFilename();
		if(!szFilename || !*szFilename) continue;

		if(!xFileTree.FindNodeIndexByName(szFilename,true,iJunkIndex))
		{
			Asura_String xFullFilename;
			GetFullFilename(szFilename,xFullFilename);

			Tools_LoadedFileList::TrackExternalModification(xFullFilename.GetString());
		}
	}
	Tools_LoadedFileList::TrackExternalModification(szTOOLS_GUIMENU_SEQUENCES_FILE);
	Tools_LoadedFileList::TrackExternalModification(szTOOLS_GUIMENU_TEXTUREFLAGS_FILE);
	Tools_LoadedFileList::TrackExternalModification(szTOOLS_GUIMENU_AUDIO);
}

void Tools_GUIMenu_System::LoadLevelSpecificFile()
{

	if(Tools_SaveAsura::GetFileType() != AsuraFile_Environment) return;

	Asura_String xFullFilename;
	GetFullFilename(GetLevelSpecificFile(),xFullFilename);

	LoadAsuraFile(xFullFilename.GetString());
}



const char* Tools_GUIMenu_System::GetLevelSpecificFilename()
{
	static Asura_String s_xFilename;
	GetFullFilename(GetLevelSpecificFile(),s_xFilename);

	return s_xFilename.GetString();
}

void Tools_GUIMenu_System::ListMenuFiles(List<Asura_String>& xOutputList)
{
	Asura_NameTree xFileTree;
	//scan through all menus for the filenames in use
	for(u_int u(0);u<Asura_GUIMenu_System::GetCurrentMenuListCount();++u )
	{
		Asura_GUIMenu_Menu_Page* pxMenuPage( Asura_GUIMenu_System::GetMenuPageByIndex( u ) );
		const char* szFilename = pxMenuPage->GetFilename();

		if(!szFilename || !*szFilename) continue;

		int iJunkIndex;
		if(!xFileTree.FindNodeIndexByName(szFilename,true,iJunkIndex))
		{
			//found a new one
			xOutputList.add_entry(szFilename);
		}
	}
	
}

int Tools_GUIMenu_System::GetFileSortKey(const char* szFile)
{
	Asura_Assert(szFile,"");

	return GetFileData(szFile)->m_iSortKey;
}

void Tools_GUIMenu_System::SetFileSortKey(const char* szFile, int iSortKey)
{
	GetFileData(szFile)->m_iSortKey = iSortKey;
}

Tools_GUIMenu_FileData* Tools_GUIMenu_System::GetFileData(const char* szFile)
{
	//see if there is an existing entry
	for(LIF<Tools_GUIMenu_FileData*> xFileLIF(&s_xFileDataList);!xFileLIF.done();xFileLIF.next())
	{
		if(!xFileLIF()->m_xFilename.Compare(szFile))
		{
			return xFileLIF();
		}
	}
	//create a new entry for the file
	Tools_GUIMenu_FileData* pxFileData = new Tools_GUIMenu_FileData(szFile);
	s_xFileDataList.add_entry(pxFileData);
	return pxFileData;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////

Tools_GUIMenu_FileData::Tools_GUIMenu_FileData(const char* szFile)
{
	m_xFilename = szFile;
	m_iSortKey = 0;
}


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


#endif // #ifdef ASURA_USE_GUI_MENU_SYSTEM
