//--------------------------------------------------------------------------------------
//	File	:	AVP_ServerEntity_GamePlayVolume.h
//	Created	:	22 / 10 / 07
//	Author	:	Gaz Thomas
//	Copyright (C) 2006 Rebellion, All Rights Reserved.
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// BEGIN FILE WRAPPER
//--------------------------------------------------------------------------------------
#ifdef ASURA_USE_PRAGMA_ONCE 
#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE
#ifndef __AVP_SERVERENTITY_GAMEPLAYVOLUME_H__
#define __AVP_SERVERENTITY_GAMEPLAYVOLUME_H__ 1
//--------------------------------------------------------------------------------------
// END FILE WRAPPER
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
//	INCLUDES
//--------------------------------------------------------------------------------------

// asura
#include "Core/Asura_List.h"
#include "Core/Asura_OrientedVolume.h"
#include "Entity/Asura_Entity.h"
#include "Network/Asura_Guid.h"
#include "Volume/Asura_VolumeGroup.h"

// avp
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/Spawners/AVP_SpawnerInterface.h"

//--------------------------------------------------------------------------------------
// FORWARD DECLARATIONS
//--------------------------------------------------------------------------------------
class Asura_Volume;
class Asura_VolumeGroup;

//--------------------------------------------------------------------------------------
//	Class	:	AVP_ServerEntity_GamePlayVolume
//	Created	:	22 / 10 / 07
//	Author	:	Gareth Thomas
//--------------------------------------------------------------------------------------
class AVP_ServerEntity_GamePlayVolume : public Asura_Entity_Server, public AVP_SpawnerInterface
{
public:

	enum GamePlayAreaType
	{
		NONE_ASSIGNED = 0,
		TIGHT_CORRIDOR,
		LARGE_CORRIDOR,
		SMALL_ROOM,
		LARGE_ROOM,
		OPEN_SPACE,
		IGNORE_GPV,
		MAX_AREA_TYPES,
	};

	enum Flags
	{ 
		FLAG_ALL_LISTED_TYPES, 
		FLAG_TRIGGERS, 
		FLAG_LIGHTS, 
		FLAG_PHYSICSOBJECTS, 
		FLAG_PREDATORS, 
		FLAG_ALIENS, 
		FLAG_HUMANS, 
		FLAG_LIFTS,
		FLAGS_PFX,
		FLAG_SOUNDS,
		FLAG_FACEHUGGERS,
		FLAG_SENTRYGUNS,
		FLAG_ALLACTORS,
		FLAG_CIVILIANS,
		FLAG_ANDROIDS,
		FLAG_MARINES,
		FLAG_CONTAINERS,
		FLAG_END_ENUM 
	};

	// Public Volume Functions
	virtual bool	Contains				(const Asura_Vector_3& xPosition) const			{return m_pxVolumeGroup->Contains(xPosition);}
	u_int			GetNumberOfVolumes		(void) const									{return m_pxVolumeGroup->GetNumberOfVolumes();}
	Asura_Quat*		GetVolumeOrient			(u_int uIndex) const							{return m_pxVolumeGroup->GetVolumeOrient(uIndex);}
	Asura_Volume*	GetVolume				(u_int uIndex)									{return m_pxVolumeGroup->GetVolume(uIndex);}
	void			AddVolume				(Asura_Volume* pxVolume)						{m_pxVolumeGroup->AddVolume(pxVolume);}
	void			RemoveVolume			(Asura_Volume* pxVolume)						{m_pxVolumeGroup->RemoveAndDestroyVolume(pxVolume);}
	void			RemoveVolume			(u_int uIndex)									{m_pxVolumeGroup->RemoveAndDestroyVolume(uIndex);}
	void			DisplaceVolumes			(Asura_Vector_3& xOffset)						{m_pxVolumeGroup->DisplaceVolumes(xOffset);}

	//	Public Overridden functions
	virtual void						WriteToChunkStream			(Asura_Chunk_Stream& xStream) const;
	virtual void						ReadFromChunkStream			(Asura_Chunk_Stream& xStream);
	virtual bool 						CanBeSavedToChunk			(void) const							{return(true);}
	virtual bool						IsFilledFromChunkBuffer		(void) const							{return(false);}
	virtual void						PostLoadInitialise			(void);
	virtual bool						HasClientEntities			(void)	const							{ return false; }
	virtual bool						HandleMessage				(const Asura_Message* pxMessage);

	#ifdef ASURA_TOOLS
	virtual void						ApplyChangesForTemplateInstance(class Tools_EntityTemplateInstance* pxInstance);
	virtual bool CanBeIncludedInTemplate(void) const										{return (Classification == AVP_ENTITYCLASS_GAMEPLAYVOLUME);}
//	virtual void Tools_Reset();
	#endif

	//	Public Static Functions
	static AVP_ServerEntity_GamePlayVolume*	Create(const Asura_Guid uGuid);
	static AVP_ServerEntity_GamePlayVolume*	GetVolumeThatContainsPosition( const Asura_Vector_3& xPosition, const Asura_Guid uPreviousGPVGuid = ASURA_GUID_UNREGISTERED );

#ifdef ASURA_TOOLS
	void RenderForWaypointingMode( void );
	static AVP_ServerEntity_GamePlayVolume*	Tools_GetVolumeThatContainsPosition( const Asura_Vector_3& xPosition, const Asura_Guid uPreviousGPVGuid = ASURA_GUID_UNREGISTERED );
#endif

	static AVP_ServerEntity_GamePlayVolume*	FindEntity(Asura_Guid uGuid) {return s_xList.FindEntity(uGuid);}
	static const Asura_Hashed_List<AVP_ServerEntity_GamePlayVolume>* GetList(void)			{return &s_xList;}
	static const char**												 GetAreaTypeNames(void)	{return s_aszAreaTypeNames;}

	//	Public Functions
	void						SetPosition(const Asura_Vector_3& xPosition)								{m_xPosition = xPosition;}
	const Asura_Vector_3&		GetPosition(void) const														{return m_xPosition;}
	Asura_VolumeGroup*			GetVolumes(void) const														{return m_pxVolumeGroup;}
	int							GetNumVolumes(void) const													{return m_iNumVolumes;}
	u_int						GetNumAlienSpawnerGuids(void) const											{return m_uNumAlienSpawnerGuids;}
	u_int						GetNumHumanoidSpawnerGuids(void) const										{return m_uNumHumanoidSpawnerGuids;}
	u_int						GetNumSpawnPointGuids(void) const											{return m_uNumSpawnPointGuids;}
	u_int						GetNumCoverPointGuids(void) const											{return m_uNumCoverPointGuids;}
	u_int						GetNumGuardPointGuids(void) const											{return m_uNumGuardPointGuids;}
	u_int						GetNumFormationPointGuids(void) const										{return m_uNumFormationPointGuids;}
	u_int						GetNumLookAtPointGuids(void) const											{return m_uNumLookAtPointGuids;}
	u_int						GetNumFleePointGuids(void) const											{return m_uNumFleePointGuids;}
	u_int						GetNumGS2Guids(void) const													{return m_uNumGS2Guids;}
	Asura_Guid					GetAlienSpawnerGuid(u_int uIndex) const										{return m_pxAlienSpawnerGuids[uIndex];}
	Asura_Guid					GetHumanoidSpawnerGuid(u_int uIndex) const									{return m_pxHumanoidSpawnerGuids[uIndex];}
	Asura_Guid					GetSpawnPointGuid(u_int uIndex) const										{return m_pxSpawnPointGuids[uIndex];}
	Asura_Guid					GetCoverPointGuid(u_int uIndex) const										{return m_pxCoverPointGuids[uIndex];}
	Asura_Guid					GetGuardPointGuid(u_int uIndex) const										{return m_pxGuardPointGuids[uIndex];}
	Asura_Guid					GetFormationPointGuid(u_int uIndex) const									{return m_pxFormationPointGuids[uIndex];}
	Asura_Guid					GetLookAtPointGuid(u_int uIndex) const										{return m_pxLookAtPointGuids[uIndex];}
	Asura_Guid					GetFleePointGuid(u_int uIndex) const										{return m_pxFleePointGuids[uIndex];}
	u_int						GetGS2Guid(u_int uIndex) const												{return m_pxGS2Guids[uIndex];}

	Asura_Hash_ID				GetFlareBlueprint() const													{return m_uFlareBlueprintHash;}

	Asura_Guid					GetLinkedGamePlayVolumeGuid(int iIndex) const								{return m_puLinkedGamePlayVolumes[iIndex];}
	void						SetLinkedGamePlayVolumeGuid(int iIndex, Asura_Guid uGuid)					{m_puLinkedGamePlayVolumes[iIndex] = uGuid;}
	u_int						GetNumLinkedGamePlayVolumes(void) const										{return m_uNumLinkedGamePlayVolumes;}
	void						SetNumLinkedGamePlayVolumes(u_int uVal)										{m_uNumLinkedGamePlayVolumes = uVal;}

	u_int						GetGamePlayAreaType(void) const												{return m_eGamePlayAreaType;}
	void						SetGamePlayAreaType(u_int eType)											{m_eGamePlayAreaType = eType;}

	void						SetBitFlags(int iBitFlags)													{m_iBitFlags = iBitFlags;}
	int							GetBitFlags(void)															{return m_iBitFlags;}
	bool						IncludeAllTypes(void)														{return (m_iBitFlags & (1 << FLAG_ALL_LISTED_TYPES) ? true : false);}
	bool						IncludeTriggers(void)														{return (m_iBitFlags & (1 << FLAG_TRIGGERS) ? true : false);}
	bool						IncludeLights(void)															{return (m_iBitFlags & (1 << FLAG_LIGHTS) ? true : false);}
	bool						IncludePhysicsObjects(void)													{return (m_iBitFlags & (1 << FLAG_PHYSICSOBJECTS) ? true : false);}
	bool						IncludePredators(void)														{return (m_iBitFlags & (1 << FLAG_PREDATORS) ? true : false);}
	bool						IncludeAliens(void)															{return (m_iBitFlags & (1 << FLAG_ALIENS) ? true : false);}
	bool						IncludeHumans(void)															{return (m_iBitFlags & (1 << FLAG_HUMANS) ? true : false);}
	bool						IncludeLifts(void)															{return (m_iBitFlags & (1 << FLAG_LIFTS) ? true : false);}
	bool						IncludePFX(void)															{return (m_iBitFlags & (1 << FLAGS_PFX) ? true : false);}
	bool						IncludeSounds(void)															{return (m_iBitFlags & (1 << FLAG_SOUNDS) ? true : false);}
	bool						IncludeFaceHuggers(void)													{return (m_iBitFlags & (1 << FLAG_FACEHUGGERS) ? true : false);}
	bool						IncludeSentryguns(void)														{return (m_iBitFlags & (1 << FLAG_SENTRYGUNS) ? true : false);}
	bool						IncludeAllActors(void)														{return (m_iBitFlags & (1 << FLAG_ALLACTORS) ? true : false);}
	bool						IncludeCivilains(void)														{return (m_iBitFlags & (1 << FLAG_CIVILIANS) ? true : false);}
	bool						IncludeAndroids(void)														{return (m_iBitFlags & (1 << FLAG_ANDROIDS) ? true : false);}
	bool						IncludeMarines(void)														{return (m_iBitFlags & (1 << FLAG_MARINES) ? true : false);}
	bool						IncludeContainers(void)														{return (m_iBitFlags & (1 << FLAG_CONTAINERS) ? true : false);}


	void						SetIncludeAllTypes(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_ALL_LISTED_TYPES)) : (m_iBitFlags &= ~(1 << FLAG_ALL_LISTED_TYPES));}
	void						SetIncludeTriggers(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_TRIGGERS))  : (m_iBitFlags &= ~(1 << FLAG_TRIGGERS));}
	void						SetIncludeLights(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_LIGHTS))  : (m_iBitFlags &= ~(1 << FLAG_LIGHTS));}
	void						SetIncludePhysicsObjects(bool bVal)											{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_PHYSICSOBJECTS))  : (m_iBitFlags &= ~(1 << FLAG_PHYSICSOBJECTS));}
	void						SetIncludePredators(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_PREDATORS))  : (m_iBitFlags &= ~(1 << FLAG_PREDATORS));}
	void						SetIncludeAliens(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_ALIENS))  : (m_iBitFlags &= ~(1 << FLAG_ALIENS));}
	void						SetIncludeHumans(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_HUMANS))  : (m_iBitFlags &= ~(1 << FLAG_HUMANS));}
	void						SetIncludeLifts(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_LIFTS))  : (m_iBitFlags &= ~(1 << FLAG_LIFTS));}
	void						SetIncludePFX(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAGS_PFX))  : (m_iBitFlags &= ~(1 << FLAGS_PFX));}
	void						SetIncludeSounds(bool bVal)													{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_SOUNDS))  : (m_iBitFlags &= ~(1 << FLAG_SOUNDS));}
	void						SetIncludeFaceHuggers(bool bVal)											{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_FACEHUGGERS))  : (m_iBitFlags &= ~(1 << FLAG_FACEHUGGERS));}
	void						SetIncludeSentryguns(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_SENTRYGUNS))  : (m_iBitFlags &= ~(1 << FLAG_SENTRYGUNS));}
	void						SetIncludeAllActors(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_ALLACTORS))  : (m_iBitFlags &= ~(1 << FLAG_ALLACTORS));}
	void						SetIncludeCivilains(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_CIVILIANS))  : (m_iBitFlags &= ~(1 << FLAG_CIVILIANS));}
	void						SetIncludeAndroids(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_ANDROIDS))  : (m_iBitFlags &= ~(1 << FLAG_ANDROIDS));}
	void						SetIncludeMarines(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_MARINES))  : (m_iBitFlags &= ~(1 << FLAG_MARINES));}
	void						SetIncludeContainers(bool bVal)												{ (bVal == true) ? (m_iBitFlags |= (1 << FLAG_CONTAINERS))  : (m_iBitFlags &= ~(1 << FLAG_CONTAINERS));}
	void						SetFlareBPHashFromAreaType();

	// Spawner interface.
	virtual void 		ScoreSpawners( const Asura_ScoreParams* pxScoreParams, float& fHighestScore, Asura_Guid& uBestGuid ) const;
	virtual bool 		OwnsSpawnerGuid( const Asura_Guid uSpawnerGuid ) const;
	virtual Asura_Guid 	Spawn( const Asura_Guid uSpawnerGuid, const Asura_SpawnParams* pxSpawnParams );

    enum { MAX_LINKED_GAMEPLAYVOLUMES = 6 };

protected:	

	//	Construction / Destruction
	AVP_ServerEntity_GamePlayVolume(const Asura_Guid uGuid);
	virtual ~AVP_ServerEntity_GamePlayVolume(void);

	void BuildAlienSpawnGuidArray(void);
	void BuildHumanoidSpawnGuidArray(void);
	void BuildSpawnPointArray(void);
	void BuildCoverPointGuidArray(void);
	void BuildGuardPointGuidArray(void);
	void BuildFormationPointGuidArray(void);
	void BuildLookAtPointGuidArray(void);
	void BuildFleePointGuidArray(void);
	void BuildGS2GuidArray(void);

	void ActivateSelectedEntities(bool bActivate);

protected:
    // the volumes

	// NEW
	Asura_VolumeGroup*			m_pxVolumeGroup; // Container class for Asura_Volumes
	int							m_iNumVolumes;

	// Alien spawners in this game play volume
	Asura_Guid*					m_pxAlienSpawnerGuids;
	u_int						m_uNumAlienSpawnerGuids;

	// Humanoid spawners in this game play volume
	Asura_Guid*					m_pxHumanoidSpawnerGuids;
	u_int						m_uNumHumanoidSpawnerGuids;

	// Spawn points in this game play volume.
	Asura_Guid*					m_pxSpawnPointGuids;
	u_int						m_uNumSpawnPointGuids;

	// cover points in this game play volume
	Asura_Guid*					m_pxCoverPointGuids;
	u_int						m_uNumCoverPointGuids;

	// Guard points in this game play volume
	Asura_Guid*					m_pxGuardPointGuids;
	u_int						m_uNumGuardPointGuids;

	// Formation points in this game play volume
	Asura_Guid*					m_pxFormationPointGuids;
	u_int						m_uNumFormationPointGuids;

	// LookAt points in this game play volume
	Asura_Guid*					m_pxLookAtPointGuids;
	u_int						m_uNumLookAtPointGuids;

	// Flee points in this game play volume
	Asura_Guid*					m_pxFleePointGuids;
	u_int						m_uNumFleePointGuids;

	// GS2 Nodes in this game play volume
	Asura_Guid*					m_pxGS2Guids;
	u_int						m_uNumGS2Guids;

	//	Protected variables
	Asura_Vector_3			    m_xPosition;
	u_int						m_eGamePlayAreaType;

	// Protected Static Variables
	static const char*			s_aszAreaTypeNames[MAX_AREA_TYPES];

	// Bit flags for entity control
	int							m_iBitFlags;

	// linked gameplay volumes
	Asura_Guid					m_puLinkedGamePlayVolumes[MAX_LINKED_GAMEPLAYVOLUMES];
	u_int						m_uNumLinkedGamePlayVolumes;

	Asura_Hash_ID				m_uFlareBlueprintHash;

private:
#ifdef ASURA_TOOLS
	//	Friend classes
	friend class ToolsAVP_Entity_GamePlayVolume;
	friend class ToolsAVP_GamePlayVolume_VolumeEdit_Controller;
#endif


	//	Private typedefs
	typedef Asura_Entity_Server PARENT;

	// Chunk Version
	enum { CURRENT_CHUNK_VERSION = 4 };

	//	Private statics
	static Asura_Hashed_List<AVP_ServerEntity_GamePlayVolume> s_xList;
};
/// End of class 'AVP_ServerEntity_GamePlayVolume'. ///

#ifdef ASURA_TOOLS
// HashedListIterator
template <class T> class AVP_GPV_NoDestroy_Hashed_List_It
{
public :
	
	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: Constructor
	//----------------------------------------------------------------------
	AVP_GPV_NoDestroy_Hashed_List_It< T >( const Asura_Hashed_List<T>* pxList )
	{
		Asura_Assert( pxList, "AVP_GPV_NoDestroy_Hashed_List_It :: Constructor - List Not Valid" );
		m_pxList = pxList;
		Restart( );
	}

	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: Destructor
	//----------------------------------------------------------------------
	~AVP_GPV_NoDestroy_Hashed_List_It<T>()
	{
	}

	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: GetCurrent
	// Gets the current entity in the iteration
	//----------------------------------------------------------------------
	T* GetCurrent() const
	{
		Asura_Assert(m_pxCurrentNode,"");
		return m_pxCurrentNode->m_pxObject;
	}

	//----------------------------------------------------------------------
	//----------------------------------------------------------------------
	T* operator()( void ) const { return GetCurrent(); }

	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: Next
	// Advance to the next entity in the list
	//----------------------------------------------------------------------
	void Next()
	{
		// Return to our place in the loop , if this isn't the first time
		if ( m_pxCurrentNode ) 
		{
			goto ReEnterLoop;
		}
		
		for ( ; m_uHashIndex < m_pxList->GetHashSize(); m_uHashIndex++ )
		{
			m_pxCurrentNode = m_pxList->GetHeadOfList( m_uHashIndex );

			while ( m_pxCurrentNode )
			{
				if ( !m_pxCurrentNode->m_bDeleted && !m_pxCurrentNode->m_pxObject->IsDestroyed() )
				{
					return;
				}

				ReEnterLoop :

				m_pxCurrentNode = m_pxCurrentNode->m_pxNext;
			}
		}
	}

	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: Done
	// Indicates whether the iteration has finished
	//----------------------------------------------------------------------
	bool Done() const { return m_pxCurrentNode == 0; }

	//----------------------------------------------------------------------
	// AVP_GPV_NoDestroy_Hashed_List_It :: Restart
	// Restarts the iteration
	//----------------------------------------------------------------------
	void Restart( )
	{
		//reset values
		m_uHashIndex = 0;
		m_pxCurrentNode = 0;
		//and find the first entry
		Next( );
	}

private :

	const Asura_Hashed_List<T>*		m_pxList;
	unsigned int					m_uHashIndex;
	const Asura_Hashed_Node<T>*		m_pxCurrentNode;
};
#endif // ASURA_TOOLS

#endif	// ifndef __AVP_ServerEntity_GamePlayVolume_H__
