///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_ControlManager.h
// Author : Steven Keen (Derby)
// Date   : 12-Jan-2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

#ifdef ASURA_USE_CONTROLMAP_MANAGER

// This file's header.
#include "Input/Asura_ControlManager.h"

// Engine independent.
#include "Core/Asura_HashTree.h"
#include "Core/Asura_List.h"
#include "Debugging/Asura_Assert.h"
#include "Input/Asura_ControlMap.h"
#if defined(ASURA_SUPPORT_COMMAND_CONSOLE)
#include "Interface/Asura_CommandConsole.h"
#endif	// defined(ASURA_SUPPORT_COMMAND_CONSOLE)

// G L O B A L S /////////////////////////////////////////////////////////////
Asura_Hash_ID	Asura_ControlManager::s_uDefaultControlsUniqueHash	= ASURA_HASH_ID_UNSET;

Asura_ControlManager::ControlMapStack	Asura_ControlManager::s_xOverrideControlMapStack;
Asura_ControlManager::StackTree			Asura_ControlManager::s_xDefaultStackTree;

Asura_ControlMap*	Asura_ControlManager::s_pxControlMapToFind	= NULL;
Asura_Hash_ID		Asura_ControlManager::s_uFoundStackHash		= ASURA_HASH_ID_UNSET;

// C L A S S   I M P L E M E N T A T I O N S /////////////////////////////////

void Asura_ControlManager::Initialise( void)
{
}


void Asura_ControlManager::Shutdown( void)
{
    Reset();

	// (MP - 07.03.2007) I think we should require the callers to deal with
    // cleaning up after themselves.
    Asura_Assert( (s_xDefaultStackTree.GetNumberOfNodes() == 0), "Failed to remove all default control-maps before shutdown." );
    Asura_Assert( (s_xOverrideControlMapStack.GetNumEntries() == 0), "Failed to remove all control-map overrides before shutdown." );
}


void Asura_ControlManager::Reset( void)
{
}


void Asura_ControlManager::Update( void)
{
	// Update the ALL of the control-maps...
	Update(s_xOverrideControlMapStack);
	s_xDefaultStackTree.Traverse(Traverse_Update);
}


void Asura_ControlManager::ResetAllControlMapValues( void )
{
	s_xDefaultStackTree.Traverse(Traverse_Reset);
	Reset(s_xOverrideControlMapStack);

    // (MP - 13.03.2007) Unpleasant hack to deal with debouncing. Really the
    // control map code ought to deal with this internally. Perhaps at least
    // this hack ought to move into there.
    Update();
    Update();
}


bool Asura_ControlManager::AddDefaultControls(const Asura_Hash_ID uDefaultControlMapHash,
											  Asura_ControlMap* pxGameControlMap)
{
	ControlMapStack*	pxFoundStack	= s_xDefaultStackTree.GetDataByHash(uDefaultControlMapHash);

	// Do we already have this stack?
	if(pxFoundStack == NULL)
	{
		ControlMapStack*	pxNewStack	= s_xDefaultStackTree.AddNode(uDefaultControlMapHash);

		if(pxNewStack == NULL)
		{
			Asura_Assert(false, "Failed to add a new default control-map stack to our tree.");
			return(false);
		}
		else
		{
			pxNewStack->AddToList(pxGameControlMap);
			pxGameControlMap->ResetValues();

			if(HasOverrideControls())
			{
				pxGameControlMap->Deactivate();
			}
			else
			{
				pxGameControlMap->Activate();
			}

			return(true);
		}
	}
	else
	{
		Asura_Assert(false, "Already have a default control-map stack with this hash.");
		return(false);
	}
}

bool Asura_ControlManager::RemoveDefaultControls(const Asura_Hash_ID uDefaultControlMapHash)
{
	if(s_xDefaultStackTree.DeleteNodeByHash(uDefaultControlMapHash))
	{
		return(true);
	}
	else
	{
		Asura_Assert(false, "Failed to find default control-map stack to delete.");
		return(true);
	}
}

void Asura_ControlManager::AddDefaultControls( Asura_ControlMap* pxGameControlMap )
{
	AddDefaultControls(++s_uDefaultControlsUniqueHash, pxGameControlMap);
}

void Asura_ControlManager::RemoveDefaultControls( Asura_ControlMap* pxGameControlMap )
{
	s_pxControlMapToFind	= pxGameControlMap;
	s_uFoundStackHash		= ASURA_HASH_ID_UNSET;

	s_xDefaultStackTree.Traverse(Traverse_FindControlMap);

	if(s_uFoundStackHash == ASURA_HASH_ID_UNSET)
	{
		Asura_Assert(false, "Couldn't find control-map to remove.");
	}
	else if(!s_xDefaultStackTree.DeleteNodeByHash(s_uFoundStackHash))
	{
		Asura_Assert(false, "Failed to delete default control-map stack specified.");
	}
}

Asura_ControlMap* Asura_ControlManager::PushDefaultControls(const Asura_Hash_ID uDefaultControlMapHash,
															Asura_ControlMap* pxControlMap)
{
	ControlMapStack*	pxStack	= s_xDefaultStackTree.GetDataByHash(uDefaultControlMapHash);

	if(pxStack == NULL)
	{
		Asura_Assert(false, "Cannot find default control-map stack to push the specified control-map to.");
		return(NULL);
	}
	else
	{
		Asura_ControlMap*	pxHeadControlMap	= pxStack->GetHeadObject();

		// Ensure that only the new control-map is active...
		if(pxHeadControlMap != NULL)
		{
			pxHeadControlMap->Deactivate();
		}
		
		pxControlMap->ResetValues();

		if(HasOverrideControls())
		{
			pxControlMap->Deactivate();
		}
		else
		{
			pxControlMap->Activate();
		}

		// Add the new control-map to the list...
		pxStack->AddToList(pxControlMap);
		return(pxControlMap);
	}
}

Asura_ControlMap* Asura_ControlManager::PopDefaultControls(const Asura_Hash_ID uDefaultControlMapHash)
{
	ControlMapStack*	pxStack	= s_xDefaultStackTree.GetDataByHash(uDefaultControlMapHash);

	if(pxStack == NULL)
	{
		Asura_Assert(false, "Cannot find default control-map stack to pop the specified control-map from.");
		return(NULL);
	}
	else
	{
		Asura_ControlMap*	pxPoppedControlMap	= pxStack->PopHeadObject();
		Asura_ControlMap*	pxHeadControlMap	= pxStack->GetHeadObject();

		// Ensure that only the head control-map is active...
		pxPoppedControlMap->Deactivate();
		if((pxHeadControlMap != NULL) && !HasOverrideControls())
		{
			pxHeadControlMap->Activate();
		}

		return(pxHeadControlMap);
	}
}


Asura_ControlMap* Asura_ControlManager::PushOverrideControls( Asura_ControlMap* pxControlMap )
{
	Asura_ControlMap*	pxHeadControlMap	= s_xOverrideControlMapStack.GetHeadObject();

	// Ensure that only the new control-map is active...
	if(pxHeadControlMap == NULL)
	{
		s_xDefaultStackTree.Traverse(Traverse_Deactivate);
	}
	else
	{
		pxHeadControlMap->Deactivate();
	}

	pxControlMap->ResetValues();
	pxControlMap->Activate();

	// Add the new control-map to the list...
    s_xOverrideControlMapStack.AddToList(pxControlMap);
	return(pxControlMap);
}

Asura_ControlMap* Asura_ControlManager::PopOverrideControls( Asura_ControlMap* pxControlMap )
{
	Asura_ControlMap*	pxPoppedControlMap	= s_xOverrideControlMapStack.PopHeadObject();
	Asura_ControlMap*	pxHeadControlMap	= s_xOverrideControlMapStack.GetHeadObject();

    Asura_Assert( pxPoppedControlMap == pxControlMap, "Pushed and popped temp controls must match - this is a stack!" );

	// Ensure that only the head control-map is active...
	Asura_Assert(pxPoppedControlMap, "Null control map pointer");
	if (pxPoppedControlMap)
	{
	    pxPoppedControlMap->Deactivate();
	}
	if(pxHeadControlMap == NULL)
	{
		s_xDefaultStackTree.Traverse(Traverse_Activate);
	}
	else
	{
		pxHeadControlMap->Activate();
	}

	return(pxHeadControlMap);
}

bool Asura_ControlManager::RemoveOverrideControls(Asura_ControlMap* pxControlMap)
{
	if(s_xOverrideControlMapStack.FindObject(pxControlMap))
	{
		Asura_ControlMap*	pxHeadControlMap	= s_xOverrideControlMapStack.GetHeadObject();

		s_xOverrideControlMapStack.RemoveFromList(pxControlMap);

		if(pxControlMap == pxHeadControlMap)
		{
			// We've removed the head control-map - time to re-active another one...
			pxHeadControlMap	= s_xOverrideControlMapStack.GetHeadObject();

			if(pxHeadControlMap == NULL)
			{
				s_xDefaultStackTree.Traverse(Traverse_Activate);
			}
			else
			{
				pxHeadControlMap->Activate();
			}
		}
		return(true);
	}
	else
	{
		Asura_Assert(false, "Cannot find control-map to remove from the override stack.");
		return(false);
	}
}

void Asura_ControlManager::Traverse_FindControlMap(Asura_Hash_ID uDefaultControlMapHash,
												   ControlMapStack* pxStack)
{
	if((pxStack != NULL) && (pxStack->FindObject(s_pxControlMapToFind) != NULL))
	{
		s_uFoundStackHash	= uDefaultControlMapHash;
	}
}

void Asura_ControlManager::Traverse_Reset(Asura_Hash_ID uDefaultControlMapHash,
										  ControlMapStack* pxStack)
{
	if(pxStack !=  NULL)
	{
		Reset(*pxStack);
	}
}

void Asura_ControlManager::Traverse_Activate(Asura_Hash_ID uDefaultControlMapHash,
											 ControlMapStack* pxStack)
{
	if(pxStack != NULL)
	{
		Activate(*pxStack);
	}
}

void Asura_ControlManager::Traverse_Update(Asura_Hash_ID uDefaultControlMapHash,
										   ControlMapStack* pxStack)
{
	if(pxStack !=  NULL)
	{
		Update(*pxStack);
	}
}

void Asura_ControlManager::Traverse_Deactivate(Asura_Hash_ID uDefaultControlMapHash,
											   ControlMapStack* pxStack)
{
	if(pxStack != NULL)
	{
		Deactivate(*pxStack);
	}
}

void Asura_ControlManager::Reset(ControlMapStack& xStack)
{
	// Reset all control-maps on this stack...
	for(Asura_List_It<Asura_ControlMap> xIt(&xStack); !xIt.Done(); xIt.Next())
	{
		Asura_ControlMap*	pxControlMap	= xIt.GetCurrent();

		if(pxControlMap != NULL)
		{
			pxControlMap->ResetValues();
		}
	}
}

void Asura_ControlManager::Activate(ControlMapStack& xStack)
{
	for(Asura_List_It<Asura_ControlMap> xIt(&xStack); !xIt.Done(); xIt.Next())
	{
		Asura_ControlMap*	pxControlMap	= xIt.GetCurrent();

		if(pxControlMap != NULL)
		{
			pxControlMap->Activate();
		}
	}
}

void Asura_ControlManager::Update(ControlMapStack& xStack)
{
	for(Asura_List_It<Asura_ControlMap> xIt(&xStack); !xIt.Done(); xIt.Next())
	{
		Asura_ControlMap*	pxControlMap	= xIt.GetCurrent();

		if(pxControlMap != NULL)
		{
			pxControlMap->Update();
		}
	}
}

void Asura_ControlManager::Deactivate(ControlMapStack& xStack)
{
	for(Asura_List_It<Asura_ControlMap> xIt(&xStack); !xIt.Done(); xIt.Next())
	{
		Asura_ControlMap*	pxControlMap	= xIt.GetCurrent();

		if(pxControlMap != NULL)
		{
			pxControlMap->Deactivate();
		}
	}
}

const Asura_ControlMap* Asura_ControlManager::GetCurrentControlMap(const Asura_Hash_ID uDefaultControlMapHash)
{
	if(s_xOverrideControlMapStack.GetNumEntries() == 0)
	{
		const ControlMapStack*	pxStack	= s_xDefaultStackTree.GetDataByHash(uDefaultControlMapHash);

		return((pxStack == NULL) ? NULL : pxStack->GetHeadObject());
	}
	else
	{
		return(s_xOverrideControlMapStack.GetHeadObject());
	}
}

const Asura_ControlMap* Asura_ControlManager::GetCurrentOverrideControlMap(void)
{
	if(s_xOverrideControlMapStack.GetNumEntries() == 0)
	{
		return(NULL);
	}
	else
	{
		return(s_xOverrideControlMapStack.GetHeadObject());
	}
}

#endif // #ifdef ASURA_USE_CONTROLMAP_MANAGER


// End of file. ///
