//////////////////////////////////////////////////////////////////////////////
//
// AVP_Profile.cpp
//
// (AJK - 25.07.2008) Created
//
// Copyright (c) 2008 Rebellion. All rights reserved.
//
//////////////////////////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Core/Profile/AVP_Profile.h"

// Asura
#include "Core/Asura_HashedLocalisedText.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "FileAccess/Asura_FileAccess.h"
#include "GUIMenu/Asura_GUIMenu_Menu_Page.h"
#include "GUIMenu/Asura_GUIMenu_System.h"
#include "Interface/Asura_CommandConsole.h"
#include "LoadAndSave/Asura_LoadAndSave.h"

// AVP
#include "Core/AVP_Settings.h"
#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
#include "LoadAndSave/AVP_Profile_LoadAndSave.h"
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)


bool AVP_Profile::s_bConsoleCommandsValid	= false;
bool AVP_Profile::s_bConsoleVariablesValid	= false;


Asura_Hash_ID AVP_Profile::s_uaOptionScreenGuids[NUM_OPTION_SCREEN_GUIDS] =
{
	0xfd733e35,		//FRONTEND_CONTROL,		Asura_GetHashID( "Options_Control_FrontEnd"); 
	0x0f119d17,		//FRONTEND_GRAPHICS,	Asura_GetHashID( "Options_Video_FrontEnd");
	0x4038cf03,		//FRONTEND_SOUND,		Asura_GetHashID( "Options_Sound_FrontEnd");  

	0x74844493,		//MARINE_CONTROL,		Asura_GetHashID( "Marine_Controls"); 
	0x9c4fa868,		//MARINE_GRAPHICS,		Asura_GetHashID( "Marine_Graphics"); 
	0x154f2a61,		//MARINE_SOUND,			Asura_GetHashID( "Marine_Sounds"); 

	0xf590912e,		//ALIEN_CONTROL,		Asura_GetHashID( "Alien_Controls"); 
	0x1d5bf503,		//ALIEN_GRAPHICS,		Asura_GetHashID( "Alien_Graphics"); 
	0x7aabe1bc,		//ALIEN_SOUND,			Asura_GetHashID( "Alien_Sounds"); 

	0x83165afe,		//PREDATOR_CONTROL,		Asura_GetHashID( "Predator_Controls"); 
	0xaae1bed3,		//PREDATOR_GRAPHICS,	Asura_GetHashID( "Predator_Graphics"); 
	0x13b9df8c,		//PREDATOR_SOUND		Asura_GetHashID( "Predator_Sounds"); 
};

AVP_Profile::AVP_Profile()
{
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
	SetupConsoleCommands();
	SetupConsoleVariables();
#endif	//defined(ASURA_SUPPORT_COMMAND_CONSOLE)

	SetToDefaults();

#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	AVP_Profile_LoadAndSave::Initialise(this);
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
}

void AVP_Profile::Shutdown()
{
#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	AVP_Profile_LoadAndSave::Shutdown();
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
}

void AVP_Profile::SetToDefaults()
{
	m_bChanged = false;
	m_xName  = "Rookie";
	m_xControls.SetToDefaults();
	m_xSounds.SetToDefaults();
	m_xGraphics.Platform_SetToDefaults();

	// Finally, do any platform specific set-up...
	Platform_SetToDefaults();
}

// AVP PROFILE
void AVP_Profile::Save()
{
	// Fill backup values
	m_xBackupControls = m_xControls;
	m_xBackupGraphics = m_xGraphics;
	m_xBackupSounds   = m_xSounds; 
	
#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	//SAVE THE FILE
	AVP_Profile_LoadAndSave::SaveProfileData();
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	
}

// AVP PROFILE
void AVP_Profile::Restore()
{
	//Restore values from backup
	m_xControls = m_xBackupControls;
	m_xGraphics = m_xBackupGraphics;
	m_xSounds   = m_xBackupSounds; 
}

void AVP_Profile::WriteToChunkStream(Asura_Chunk_Stream& xStream)
{
	int iCurrentChunkVersion = CURRENT_CHUNK_VERSION;

	#ifdef ASURA_TOOLS
		xStream.SetSwapEndian(false);
	#endif

	xStream << iCurrentChunkVersion;
	xStream << m_xName;

	m_xControls.WriteToChunkStream(xStream);
	m_xGraphics.WriteToChunkStream(xStream);
	m_xSounds.WriteToChunkStream(xStream);
}

AVP_Profile::E_PROFILE_FILE_STATES AVP_Profile::Load()
{
#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	AVP_Profile::E_PROFILE_FILE_STATES iReturnState;

	iReturnState = AVP_Profile_LoadAndSave::LoadProfileData();
	
	if( iReturnState == PROFILE_FILE_OK )
	{
		// Fill backup values
		m_xBackupControls = m_xControls;
		m_xBackupGraphics = m_xGraphics;
		m_xBackupSounds   = m_xSounds; 
	}
	else if( iReturnState != PROFILE_FILE_NOT_FOUND )
	{
		// if the issue is anything other than the fact the file does not exist assert. 
		Asura_Assertf( false, ( "AVP_Profile::Load\n Profile file could not be loaded with error code %d\n refer to AVP_Profile::E_PROFILE_FILE_STATES for erros code meanings", iReturnState ) );
	}

	return iReturnState;
#else
	Asura_Assert(false, "Cannot load profile - loading/saving is not defined.");
	return(PROFILE_FILE_NOT_FOUND);
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
}

void AVP_Profile::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iCurrentChunkVersion;

	xStream >> iCurrentChunkVersion;

	switch ( iCurrentChunkVersion )
	{
		case 0 :
		{
			bool bTemp;
			xStream >> bTemp;
			xStream >> m_xName;
			m_xControls.ReadFromChunkStream(xStream);
			break;
		}
		case 1 :
		{
			xStream >> m_xName;
			m_xControls.ReadFromChunkStream(xStream);
			m_xGraphics.ReadFromChunkStream(xStream);
			m_xSounds.ReadFromChunkStream(xStream);
			break;
		}
		default :
		{
			Asura_Assertf(false, ("Unknown chunk version (%d) in AVP_Profile", iCurrentChunkVersion));
			break;
		}
	}
}

void AVP_Profile::ApplySettings()
{
	m_xControls.ApplySettings();
	m_xGraphics.ApplySettings();
	m_xSounds.ApplySettings();
}

bool AVP_Profile::ConsoleCmd_Save( bool bHelp )
{
	 AVP_Settings::GetCurrentProfile()->Save();
	 return true;
}

bool AVP_Profile::ConsoleCmd_Restore( bool bHelp )
{
	AVP_Settings::GetCurrentProfile()->Restore();
	AVP_Settings::GetCurrentProfile()->Save();
	return true;
}

#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)

void AVP_Profile::SetupConsoleCommands()
{
	if(!s_bConsoleCommandsValid)
	{
		// Add the necessary console commands...
		Asura_CommandConsole::AddCmd( L"Profile.CMD.Save"                    , AVP_Profile::ConsoleCmd_Save           , Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		Asura_CommandConsole::AddCmd( L"Profile.CMD.Restore"                 , AVP_Profile::ConsoleCmd_Restore        , Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		Asura_CommandConsole::AddCmd( L"Profile.CMD.OpenOptionsMenu"         , AVP_Profile::ConsoleCmd_OpenOptionsMenu  , Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		Asura_CommandConsole::AddCmd( L"Profile.CMD.OpenConfirmCancelMenu"   , AVP_Profile::ConsoleCmd_OpenConfirmCancelMenu  , Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
		Asura_CommandConsole::AddCmd( L"Profile.CMD.ResetDefaults"			 , AVP_Profile::ConsoleCmd_ResetDefaults, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

		m_xControls.SetupConsoleCommands();
		m_xGraphics.SetupConsoleCommands();
		m_xSounds.SetupConsoleCommands();

		s_bConsoleCommandsValid	= true;
	}
}

void AVP_Profile::SetupConsoleVariables()
{
	// Ensure that we're starting from a blank-slate...
	RemoveConsoleVariables();

	// Add the necessary console variables...
	Asura_CommandConsole::AddVar( L"Profile.VAR.Changed", &m_bChanged, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	m_xControls.SetupConsoleVariables();
	m_xGraphics.SetupConsoleVariables();
	m_xSounds.SetupConsoleVariables();

	s_bConsoleVariablesValid	= true;
}
void AVP_Profile::RemoveConsoleVariables()
{
	if(s_bConsoleVariablesValid)
	{
		// Add the necessary console variables...
		Asura_CommandConsole::RemoveVar( L"Profile.VAR.Changed" );

		m_xControls.RemoveConsoleVariables();
		m_xGraphics.RemoveConsoleVariables();
		m_xSounds.RemoveConsoleVariables();

		s_bConsoleVariablesValid	= false;
	}
}

#endif	//defined(ASURA_SUPPORT_COMMAND_CONSOLE)

void AVP_Profile::Update()
{
#if defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)
	AVP_Profile_LoadAndSave::Update();
#endif	//defined(AVP_SUPPORT_PROFILE_LOADANDSAVE)

	m_xControls.Update();
	m_xGraphics.Update();
	m_xSounds.Update();
	UpdateChange();
}


bool AVP_Profile::ConsoleCmd_OpenOptionsMenu( bool bHelp)
{
	if( bHelp)
	{
		Asura_CommandConsole::Printf("Opens the appropriate base options menu.");
		return true;
	}
	else
	{
		// Close all menus
		Asura_GUIMenu_System::CloseMenuPage( AVP_Settings::GetCurrentProfile()->GetControls().GetCurSpeciesControlsMenuHash());
		Asura_GUIMenu_System::CloseMenuPage( AVP_Settings::GetCurrentProfile()->GetGraphics().GetCurSpeciesGraphicsMenuHash());
		Asura_GUIMenu_System::CloseMenuPage( AVP_Settings::GetCurrentProfile()->GetSounds().GetCurSpeciesSoundsMenuHash());

		Asura_GUIMenu_System::OpenMenuPage( GetCurSpeciesOptionsMenuHash(), true, false);

		return false;
	}
}

////////////////////////////////////////////////////////////////////////////////
//  CLASS    :  AVP_Profile
//  NAME     :  ConsoleCmd_OpenOptionsMenu() - PUBLIC, STATIC
//  CREATED  :  CAH (17.8.2008)
//  DESC     :  Menu interface function, called when any of the Reset to default buttons are pressed. 
//				Simply calls the correct reset function in the sub sections of the profile options based on the int argument passed.
//				0 - Controls; 1 - Graphics; 2 - Sound
////////////////////////////////////////////////////////////////////////////////

bool AVP_Profile::ConsoleCmd_ResetDefaults( u_int uSubCatagoryIndex, bool bInterrogate, bool bHelp )
{
	if( bHelp || bInterrogate)
	{
		Asura_CommandConsole::Printf("Resets sub catagories of options to defults,\n Argument options:\nFrontEnd; 0 = Controls; 1 = Graphics; 2 = Sound\nMarineIngame; 3,4,5\nAlienIngame; 6,7,8\nPredIngame; 9,10,11");
		return true;
	}

	// no need to check for <0 as argument is unsigned int. 
	if( uSubCatagoryIndex >= NUM_OPTION_SCREEN_GUIDS ) 
	{
		Asura_Assert( 1, "Options Sub catagory is out of range, defaults cannot be safely reset so function is aborting" );
		return false;
	}

	u_int uMenuPageHashID = s_uaOptionScreenGuids[uSubCatagoryIndex];

	switch( uSubCatagoryIndex )
	{	
		case FRONTEND_CONTROL:
		case MARINE_CONTROL:
		case ALIEN_CONTROL:
		case PREDATOR_CONTROL:
		{
			AVP_Settings::GetCurrentProfile()->GetControls().SetToDefaults();
			break;
		}
		case FRONTEND_GRAPHICS:
		case MARINE_GRAPHICS:
		case ALIEN_GRAPHICS:
		case PREDATOR_GRAPHICS:
		{
			AVP_Settings::GetCurrentProfile()->GetGraphics().Platform_SetToDefaults();
			break;
		}
		case FRONTEND_SOUND:
		case MARINE_SOUND:
		case ALIEN_SOUND:
		case PREDATOR_SOUND:
		{
			AVP_Settings::GetCurrentProfile()->GetSounds().SetToDefaults();
			break;
		}
		default:
		{
			Asura_Assertf( 1, ( "Options Sub-Catagory is not valid, range must be from 0 - %d. No changes have been made. ", ( NUM_OPTION_SCREEN_GUIDS - 1 ) ) );
			return false;
		}
	}

	AVP_Settings::GetCurrentProfile()->Save();

	// get a pointer to the page so we can refresh it
	Asura_GUIMenu_Menu_Page* pxPagePointer =  Asura_GUIMenu_System::GetMenuPageByID( uMenuPageHashID );

	Asura_Assertf( pxPagePointer, ( "Menu page with hash ID 0x%08x not found!!", uMenuPageHashID ) );
	if ( pxPagePointer )
	{
		// we have to store the back hash id and clear it. Because opening a page with a back ID already set hits asserts.
		u_int uHashID = pxPagePointer->GetBackMenuHash();
		pxPagePointer->ClearBackMenuHash();

		// the only way to refresh every element on a page in one call is to close and open it. since it is done on a putton press, not per frame this is acceptable.  
		Asura_GUIMenu_System::CloseMenuPage( uMenuPageHashID );
		Asura_GUIMenu_System::OpenMenuPage( uMenuPageHashID );

		// now re-assign the back hash id so the front end flow does not break. 
		pxPagePointer->SetBackMenuHash( uHashID );
	}
	
	return false;
}

bool AVP_Profile::ConsoleCmd_OpenConfirmCancelMenu( bool bHelp)
{
	if( bHelp)
	{
		Asura_CommandConsole::Printf("Opens the appropriate base options menu.");
		return true;
	}
	else
	{
		Asura_GUIMenu_System::OpenMenuPage( GetCurSpeciesConfirmCancelMenuHash(), true, false);
		return false;
	}
}

u_int AVP_Profile::GetCurSpeciesOptionsMenuHash()
{
	switch(AVP_Settings::GetPlayerSpecies())
	{
		case AVP_Settings::AVP_SPECIES_HUMAN :
		{
			return s_uAVP_PROFILE_MARINE_OPTIONS_MENU;
		}
		case AVP_Settings::AVP_SPECIES_ALIEN :
		{
			return s_uAVP_PROFILE_ALIEN_OPTIONS_MENU;
		}
		case AVP_Settings::AVP_SPECIES_PREDATOR :
		{
			return s_uAVP_PROFILE_PREDATOR_OPTIONS_MENU;
		}
		case AVP_Settings::AVP_SPECIES_UNKNOWN:
		{
			// This is valid, we don't know what species we are yet
			return ASURA_HASH_ID_UNSET; 
		}
		default :
		{
			Asura_Assert(false,"Wrong species passed in AVP_Profile");
			return ASURA_HASH_ID_UNSET;
		}
	}
}

u_int AVP_Profile::GetCurSpeciesConfirmCancelMenuHash()
{
	switch(AVP_Settings::GetPlayerSpecies())
	{
		case AVP_Settings::AVP_SPECIES_HUMAN :
		{
			return s_uAVP_PROFILE_MARINE_CONFIRM_CANCEL_MENU;
		}
		case AVP_Settings::AVP_SPECIES_ALIEN :
		{
			return s_uAVP_PROFILE_ALIEN_CONFIRM_CANCEL_MENU;
		}
		case AVP_Settings::AVP_SPECIES_PREDATOR :
		{
			return s_uAVP_PROFILE_PREDATOR_CONFIRM_CANCEL_MENU;
		}
		case AVP_Settings::AVP_SPECIES_UNKNOWN:
		{
			// This is valid, we don't know what species we are yet
			return ASURA_HASH_ID_UNSET; 
		}
		default :
		{
			Asura_Assert(false,"Wrong species passed in AVP_Profile");
			return ASURA_HASH_ID_UNSET;
		}
	}
}

u_int AVP_Profile::GetCurSpeciesPauseMenuHash()
{
	switch(AVP_Settings::GetPlayerSpecies())
	{
		case AVP_Settings::AVP_SPECIES_HUMAN :
		{
			return s_uAVP_PROFILE_MARINE_PAUSE_MENU;
		}
		case AVP_Settings::AVP_SPECIES_ALIEN :
		{
			return s_uAVP_PROFILE_ALIEN_PAUSE_MENU;
		}
		case AVP_Settings::AVP_SPECIES_PREDATOR :
		{
			return s_uAVP_PROFILE_PREDATOR_PAUSE_MENU;
		}
		case AVP_Settings::AVP_SPECIES_UNKNOWN:
		{
			// This is valid, we don't know what species we are yet
			return ASURA_HASH_ID_UNSET; 
		}
	default :
		{
			Asura_Assert(false,"Wrong species passed in AVP_Profile");
			return ASURA_HASH_ID_UNSET;
		}
	}
}

void AVP_Profile::UpdateChange()
{
	m_bChanged = ( m_xControls != m_xBackupControls ) ||
		         ( m_xGraphics != m_xBackupGraphics ) ||
		         ( m_xSounds   != m_xBackupSounds );
}
