//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//

#ifndef AI_NAMESPACES_H
#define AI_NAMESPACES_H

class CStringRegistry;

#if defined( _WIN32 )
#pragma once
#endif

#define MAX_STRING_INDEX 9999
const int GLOBAL_IDS_BASE = 1000000000; // decimal for debugging readability

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

inline bool AI_IdIsGlobal( int id )			{ return ( id >= GLOBAL_IDS_BASE || id == -1 ); }
inline bool AI_IdIsLocal( int id )			{ return ( id < GLOBAL_IDS_BASE || id == -1 );  }
inline int  AI_RemapToGlobal( int id )		{ return ( id != -1 ) ? id + GLOBAL_IDS_BASE : -1; }
inline int  AI_RemapFromGlobal( int id )	{ return ( id != -1 ) ? id - GLOBAL_IDS_BASE : -1; }

inline int	AI_MakeGlobal( int id )			{ return AI_IdIsLocal( id ) ? AI_RemapToGlobal( id ) : id; }

//-----------------------------------------------------------------------------
// CAI_GlobalNamespace
//
// Purpose: Symbol table for all symbols across a given namespace, a
//			bi-directional mapping of "text" to global ID
//

class CAI_GlobalNamespace
{
public:
	CAI_GlobalNamespace();
	~CAI_GlobalNamespace();

	void Clear();

	void AddSymbol( const char *pszSymbol, int symbolID );
	int NextGlobalBase() const;

	const char *IdToSymbol( int symbolID ) const;
	int SymbolToId( const char *pszSymbol ) const;

private:
	CStringRegistry * 	m_pSymbols;
	int					m_NextGlobalBase;
};

//-----------------------------------------------------------------------------
// CAI_LocalIdSpace
//
// Purpose: Maps per class IDs to global IDs, so that various classes can use
//			the same integer in local space to represent different globally
//			unique integers. Used for schedules, tasks, conditions and squads
//

class CAI_LocalIdSpace
{
public:
	CAI_LocalIdSpace( bool fIsRoot = false );

	bool Init( CAI_GlobalNamespace *pGlobalNamespace, CAI_LocalIdSpace *pParentIDSpace = NULL );
	bool IsGlobalBaseSet() const { return ( m_globalBase != -1 ); }

	bool AddSymbol( const char *pszSymbol, int localId, const char *pszDebugSymbolType = "", const char *pszDebugOwner = "" );

	int GlobalToLocal( int globalID ) const;
	int LocalToGlobal( int localID ) const;

	CAI_GlobalNamespace *GetGlobalNamespace() { return m_pGlobalNamespace; }
	const CAI_GlobalNamespace *GetGlobalNamespace() const { return m_pGlobalNamespace; }

private:
	bool IsLocalBaseSet() const	{ return ( m_localBase != MAX_STRING_INDEX );	}
	int GetLocalBase() const	{ return m_localBase;  }
	int GetGlobalBase() const	{ return m_globalBase; }
	int GetLocalTop() const		{ return m_localTop;  }
	int GetGlobalTop() const	{ return m_globalTop; }

	bool SetLocalBase( int newBase );

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

	int 					m_globalBase;
	int 					m_localBase;
	int 					m_localTop;
	int 					m_globalTop;

	CAI_LocalIdSpace *		m_pParentIDSpace;
	CAI_GlobalNamespace *	m_pGlobalNamespace;
};

//-----------------------------------------------------------------------------
//
// Namespaces used by CAI_BaseNPC
//
//-----------------------------------------------------------------------------

class CAI_GlobalScheduleNamespace
{
public:
	void Clear()
	{
		m_ScheduleNamespace.Clear();
		m_TaskNamespace.Clear();
		m_ConditionNamespace.Clear();
	}

	void 		AddSchedule( const char *pszSchedule, int scheduleID );
	const char *ScheduleIdToSymbol( int scheduleID ) const;
	int 		ScheduleSymbolToId( const char *pszSchedule ) const;

	void 		AddTask( const char *pszTask, int taskID );
	const char *TaskIdToSymbol( int taskID ) const;
	int 		TaskSymbolToId( const char *pszTask ) const;

	void 		AddCondition( const char *pszCondition, int conditionID );
	const char *ConditionIdToSymbol( int conditionID ) const;
	int 		ConditionSymbolToId( const char *pszCondition ) const;
	int			NumConditions() const;

private:
	friend class CAI_ClassScheduleIdSpace;

	CAI_GlobalNamespace m_ScheduleNamespace;
	CAI_GlobalNamespace m_TaskNamespace;
	CAI_GlobalNamespace m_ConditionNamespace;
};

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

class CAI_ClassScheduleIdSpace
{
public:
	CAI_ClassScheduleIdSpace( bool fIsRoot = false )
	 :	m_ScheduleIds( fIsRoot ),
	 	m_TaskIds( fIsRoot ),
	 	m_ConditionIds( fIsRoot )
	{
	}

	bool Init( const char *pszClassName, CAI_GlobalScheduleNamespace *pGlobalNamespace, CAI_ClassScheduleIdSpace *pParentIDSpace = NULL );

	const char *GetClassName() const { return m_pszClassName; }

	bool IsGlobalBaseSet() const;

	bool AddSchedule( const char *pszSymbol, int localId, const char *pszDebugOwner = "" );
	int ScheduleGlobalToLocal( int globalID ) const;
	int ScheduleLocalToGlobal( int localID ) const;

	bool AddTask( const char *pszSymbol, int localId, const char *pszDebugOwner = "" );
	int TaskGlobalToLocal( int globalID ) const;
	int TaskLocalToGlobal( int localID ) const;

	bool AddCondition( const char *pszSymbol, int localId, const char *pszDebugOwner = "" );
	int ConditionGlobalToLocal( int globalID ) const;
	int ConditionLocalToGlobal( int localID ) const;

private:
	const char *	 m_pszClassName;
	CAI_LocalIdSpace m_ScheduleIds;
	CAI_LocalIdSpace m_TaskIds;
	CAI_LocalIdSpace m_ConditionIds;
};

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

inline void CAI_GlobalScheduleNamespace::AddSchedule( const char *pszSchedule, int scheduleID )
{
	m_ScheduleNamespace.AddSymbol( pszSchedule, scheduleID);
}

inline const char *CAI_GlobalScheduleNamespace::ScheduleIdToSymbol( int scheduleID ) const
{
	return m_ScheduleNamespace.IdToSymbol( scheduleID );
}

inline int CAI_GlobalScheduleNamespace::ScheduleSymbolToId( const char *pszSchedule ) const
{
	return m_ScheduleNamespace.SymbolToId( pszSchedule );
}

inline void CAI_GlobalScheduleNamespace::AddTask( const char *pszTask, int taskID )
{
	m_TaskNamespace.AddSymbol( pszTask, taskID);
}

inline const char *CAI_GlobalScheduleNamespace::TaskIdToSymbol( int taskID ) const
{
	return m_TaskNamespace.IdToSymbol( taskID );
}

inline int CAI_GlobalScheduleNamespace::TaskSymbolToId( const char *pszTask ) const
{
	return m_TaskNamespace.SymbolToId( pszTask );
}

inline void CAI_GlobalScheduleNamespace::AddCondition( const char *pszCondition, int conditionID )
{
	m_ConditionNamespace.AddSymbol( pszCondition, conditionID);
}

inline const char *CAI_GlobalScheduleNamespace::ConditionIdToSymbol( int conditionID ) const
{
	return m_ConditionNamespace.IdToSymbol( conditionID );
}

inline int CAI_GlobalScheduleNamespace::ConditionSymbolToId( const char *pszCondition ) const
{
	return m_ConditionNamespace.SymbolToId( pszCondition );
}

inline int CAI_GlobalScheduleNamespace::NumConditions() const
{ 
	return m_ConditionNamespace.NextGlobalBase() - GLOBAL_IDS_BASE; 
}

inline bool CAI_ClassScheduleIdSpace::Init( const char *pszClassName, CAI_GlobalScheduleNamespace *pGlobalNamespace, CAI_ClassScheduleIdSpace *pParentIDSpace )
{
	m_pszClassName = pszClassName;
	return ( m_ScheduleIds.Init( &pGlobalNamespace->m_ScheduleNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_ScheduleIds : NULL ) &&
			 m_TaskIds.Init( &pGlobalNamespace->m_TaskNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_TaskIds : NULL ) &&
			 m_ConditionIds.Init( &pGlobalNamespace->m_ConditionNamespace, ( pParentIDSpace ) ? &pParentIDSpace->m_ConditionIds : NULL ) );
}

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

inline bool CAI_ClassScheduleIdSpace::IsGlobalBaseSet() const
{
	return m_ScheduleIds.IsGlobalBaseSet();
}

inline bool CAI_ClassScheduleIdSpace::AddSchedule( const char *pszSymbol, int localId, const char *pszDebugOwner )
{
	return m_ScheduleIds.AddSymbol( pszSymbol, localId, "schedule", pszDebugOwner );
}

inline int CAI_ClassScheduleIdSpace::ScheduleGlobalToLocal( int globalID ) const
{
	return m_ScheduleIds.GlobalToLocal( globalID );
}

inline int CAI_ClassScheduleIdSpace::ScheduleLocalToGlobal( int localID ) const
{
	return m_ScheduleIds.LocalToGlobal( localID );
}

inline bool CAI_ClassScheduleIdSpace::AddTask( const char *pszSymbol, int localId, const char *pszDebugOwner )
{
	return m_TaskIds.AddSymbol( pszSymbol, localId, "task", pszDebugOwner );
}

inline int CAI_ClassScheduleIdSpace::TaskGlobalToLocal( int globalID ) const
{
	return m_TaskIds.GlobalToLocal( globalID );
}

inline int CAI_ClassScheduleIdSpace::TaskLocalToGlobal( int localID ) const
{
	return m_TaskIds.LocalToGlobal( localID );
}

inline bool CAI_ClassScheduleIdSpace::AddCondition( const char *pszSymbol, int localId, const char *pszDebugOwner )
{
	return m_ConditionIds.AddSymbol( pszSymbol, localId, "condition", pszDebugOwner );
}

inline int CAI_ClassScheduleIdSpace::ConditionGlobalToLocal( int globalID ) const
{
	return m_ConditionIds.GlobalToLocal( globalID );
}

inline int CAI_ClassScheduleIdSpace::ConditionLocalToGlobal( int localID ) const
{
	return m_ConditionIds.LocalToGlobal( localID );
}

//=============================================================================

#endif // AI_NAMESPACES_H