/**
*
* \file Asura_Entity_Spawner.h
*
* Created by DWE - 27/01/2003 10:57:36
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
* \brief
*
**/
#ifndef __ASURA_ENTITY_SPAWNER_H__
#define __ASURA_ENTITY_SPAWNER_H__

#include "Core/Asura_HashedList.h"
#include "Entity/Asura_Entity.h"

/// DWE - 27/01/2003 14:32:51 - The minimum distance within within a (player) entity we can spawn.
#define ASURA_MINIMUM_SPAWNING_RANGE 30.0f

class Asura_Entity_Spawner : public Asura_Entity_Server
{	
public:
	Asura_Entity_Spawner(Asura_Guid uGuid);
	virtual ~Asura_Entity_Spawner();

	// override of HasClientEntities() - we don't have any.
	virtual bool HasClientEntities() const { return false; }

	virtual void Update(void) = 0;
	virtual bool HandleMessage(const Asura_Message* pxMessage);

	void InitialiseFromChunkBuffer(const char*& pcChunkBuffer);
	void FillInChunkBuffer(char*& pcChunkBuffer);
	int GetChunkBufferSize();
	virtual bool CanBeSavedToChunk() const {return true;}

	// Setup functions
	void Initialise();
	
	void SetActive(const bool bValue) {m_bActive = bValue;}
	virtual void SetMinimumAmount(const int iValue) {m_iMinimumAmount = iValue;}
	void SetDelayBetweenSpawning(const float fValue) {m_fDelayBetweenSpawns = fValue;}
	void SetPosition(const Asura_Vector_3& xPosition) {m_xPosition = xPosition;}

	bool IsActive() {return m_bActive;}

	int* GetMinAmountPtr() {return &m_iMinimumAmount;}
	int* GetTotalToSpawnPtr() {return &m_iTotalToSpawn;}
	float* GetSpawnDelayPtr() {return &m_fDelayBetweenSpawns;}

	virtual void SetupStorage(const int iTotalToSpawn) = 0;

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

	/// DWE - 14/02/2003 15:39:28 - ChunkData is private so it doesn't get inherited.
private:
	struct ChunkData
	{
		enum {CURRENT_VERSION = 2};
		union
		{
			unsigned char m_ucFlags;
			struct
			{
				unsigned char m_bActive : 1,
							  Unused : 7;
			};
		};

		int m_iCurrentAmount;	// Number of entities currently active
		int m_iMinimumAmount;	// Number of entities that should be active

		int m_iTotalToSpawn;	// Maximum number of entities that will be respawned.
		int m_iTotalSpawned;	// Total that we have spawned so far.
		
		int m_iSizeOfEntityStorage; // Number of entities created.

		float m_fDelayBetweenSpawns;
		float m_fTimer;

		Asura_Vector_3 m_xPosition;
	};
	struct ChunkData_V0
	{
		unsigned char m_bActive : 1;

		int m_iCurrentAmount;
		int m_iMinimumAmount;

		float m_fDelayBetweenSpawns;
		float m_fTimer;

		Asura_Vector_3 m_xPosition;
	};

protected:

	// DWE - we may need Create functions with different params, such as orientation.
	virtual const Asura_Vector_3* GetSpawnPosition(); // DWE - override this function to get the position to create entity.
	virtual void Spawn(const Asura_Vector_3& xPosition) = 0; // DWE - Spawns entity.
	virtual void Spawn(const Asura_Vector_3& xPosition, const Asura_Euler_3& xOrientation) = 0; // DWE - Spawns entity with orientation

	unsigned char m_bActive : 1;
//	unsigned char m_bInitiallyActive : 1;

	int m_iCurrentAmount;
	int m_iMinimumAmount;
	int m_iTotalToSpawn;	// Maximum number of entities that will be respawned.
	int m_iTotalSpawned;	

//	Asura_Guid* m_puGuidList; // List of Guids to Entities I've spawned, so I can check if they're dead and spawn new ones.

	float m_fDelayBetweenSpawns;
	float m_fTimer;

	Asura_Vector_3 m_xPosition;	// DWE - though technically we don't need a position, it helps to know where the spawn point is to edit it.
	
/**** Static Members ****/
public:
	
	static Asura_Entity_Spawner* FindEntity(Asura_Guid uGuid)
	{
		return s_xList.FindEntity(uGuid);
	}
	static const Asura_Hashed_List<Asura_Entity_Spawner>* GetList()
	{
		return &s_xList;
	}

private:
	// List of all spawners in the game
	static Asura_Hashed_List<Asura_Entity_Spawner> s_xList;	
};

class Asura_Entity_BoundingBox_Spawner : public Asura_Entity_Spawner
{
public:
	Asura_Entity_BoundingBox_Spawner(Asura_Guid uGuid);
	virtual ~Asura_Entity_BoundingBox_Spawner();

	void InitialiseFromChunkBuffer(const char*& pcChunkBuffer);
	void FillInChunkBuffer(char*& pcChunkBuffer);
	int GetChunkBufferSize();
	
	void SetGuidToCentreOn(Asura_Guid uGuid) {m_uGuidToCentreOn = uGuid;}
	Asura_Guid GetGuidToCentreOn() {return m_uGuidToCentreOn;}
	
	float* GetRange() {return &m_fRange;}
	float* GetMinimumRange() {return &m_fMinRange;}

	static bool FindWaypointOutOfSightCallback(u_short uWaypointIndex);
	virtual void SetupStorage(const int iTotalToSpawn) = 0;

/// DWE - 14/02/2003 15:39:11 - ChunkData is private so it doesn't get inherited.
private:
	struct ChunkData
	{
		enum {CURRENT_VERSION = 1};
		//Asura_Bounding_Box m_xBoundingBox;
		Asura_Guid m_uGuidToCentreOn;
		float m_fRange;
		float m_fMinRange;
	};

	struct ChunkData_V0
	{
		Asura_Guid m_uGuidToCentreOn;
		float m_fRange;
	};

	
protected:

	// DWE - we may need Spawn functions with different params, such as orientation.
	virtual void Spawn(const Asura_Vector_3& xPosition) = 0; // DWE - Spawns entity.
	virtual void Spawn(const Asura_Vector_3& xPosition, const Asura_Euler_3& xOrientation) = 0;
	virtual const Asura_Vector_3* GetSpawnPosition(); // DWE - Gets a position in the BB that is out of sight of Guid
//	Asura_Bounding_Box m_xBoundingBox;
	/// DWE - 27/01/2003 11:15:35 - The BB is created around a specific entity
	/// So we can pick a position, out of sight of the entity but near by.
	Asura_Guid m_uGuidToCentreOn;

	// DWE - The size of the size of the Boudning box that is created arounf the entity.
	float m_fRange;
	/// DWE - 24/07/2003 12:04:57 - The minimum range of spawning
	float m_fMinRange;
};


/// DWE - 21/02/2003 11:05:04 - A quantum spawner will spawn at random at one of several positions.
class Asura_Entity_Quantum_Spawner : public Asura_Entity_Spawner
{
public:
	Asura_Entity_Quantum_Spawner(Asura_Guid uGuid);
	~Asura_Entity_Quantum_Spawner();

	void InitialiseFromChunkBuffer(const char*& pcChunkBuffer);
	void FillInChunkBuffer(char*& pcChunkBuffer);
	int GetChunkBufferSize();

	virtual void SetNumberOfSpawnPoints(unsigned int uValue);
	int  GetNumberOfSpawnPoints() {return m_uNumberOfSpawnPoints;}
	Asura_Vector_3* m_pxPositionList;
	virtual void SetupStorage(const int iTotalToSpawn) = 0;

	//public for tools access.
	bool m_bUseModuleLinking;		// Only spawn when out of visibility?

protected:
	unsigned int m_uNumberOfSpawnPoints;
	int* m_piLastKnownModuleList;	// list of the spawn points modules to speed up vis searches

	virtual void Spawn(const Asura_Vector_3& xPosition) = 0;
	virtual void Spawn(const Asura_Vector_3& xPosition,const Asura_Euler_3& xOrientation) = 0;
	virtual const Asura_Vector_3* GetSpawnPosition(); 

private:

	struct ChunkData
	{
		enum {CURRENT_VERSION = 1};
		unsigned int m_uNumberOfSpawnPoints;
		union
		{
			unsigned int m_uFlags;
			struct
			{
				unsigned int m_bUseModuleLinking : 1,
							 Unused : 31;
			};
		};
	};
	struct ChunkData_V0
	{
		unsigned int m_uNumberOfSpawnPoints;
	};
};


#endif//__ASURA_ENTITY_SPAWNER_H__
