#ifndef _RUWORLD_BASE_H_
#define _RUWORLD_BASE_H_

#include "../../Scene/Base/RuEntityBase.h"
#include "../../Scene/Gizmo/RuGizmo_Plane.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

namespace RuWorld
{
	enum TriggerType
	{
		ruTRIGGERTYPE_ZONE					= 1,								//!< Zone trigger
		ruTRIGGERTYPE_SCRIPT				= 2,								//!< Script trigger

		ruTRIGGERTYPE_FORCE_DWORD			= 0x7FFFFFFF
	};
}

// ************************************************************************************************************************************************************

class CRuWorld_ChunkTree : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct ChunkDescriptor
	{
	public:
		INT32								m_x;
		INT32								m_z;
		CRuAABB								m_bounds;
	};

	struct ChunkTreeNode
	{
	public:
		CRuAABB								m_bounds;						// Bounds of the chunk tree node

		INT32								m_chunkArraySize;				// Maximum number of chunks allowed at this node
		INT32								m_numChunks;					// Number of chunks at this node
		ChunkDescriptor*					m_chunks;						// Array of ChunkDescriptors

		ChunkTreeNode*						m_children[4];					// Children of the chunk tree node

	public:
											ChunkTreeNode();
											~ChunkTreeNode();

		BOOL								IsLeaf();
	};

	ChunkTreeNode*							m_root;							//!< Root of the chunk tree
	INT32									m_chunksPerNode;				//!< Maximum number of chunks per node

public:
											CRuWorld_ChunkTree();
	virtual									~CRuWorld_ChunkTree();

	BOOL									Initialize(const CRuAABB &treeBounds, INT32 chunksPerNode);

	BOOL									InsertChunk(INT32 x, INT32 z, const CRuAABB &bounds);

	// Enumeration
	void									EnumerateChunks(const CRuPlane4 *frustumPlanes, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(const CRuAABB &box, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(const CRuSphere &sphere, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(const CRuRay3 &ray, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(const CRuSegment3 &segment, CRuArrayList<DWORD> &chunkKeyOut);

protected:
	BOOL									InsertChunk(ChunkTreeNode *node, INT32 x, INT32 z, const CRuAABB &bounds);
	BOOL									Subdivide(ChunkTreeNode *node);

	void									EnumerateChunks(ChunkTreeNode *node, const CRuPlane4 *frustumPlanes, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(ChunkTreeNode *node, const CRuAABB &box, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(ChunkTreeNode *node, const CRuSphere &sphere, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(ChunkTreeNode *node, const CRuRay3 &ray, CRuArrayList<DWORD> &chunkKeyOut);
	void									EnumerateChunks(ChunkTreeNode *node, const CRuSegment3 &segment, CRuArrayList<DWORD> &chunkKeyOut);
};

// ************************************************************************************************************************************************************

class CRuWorld_EntityDescriptor : public IRuObject
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	// Identifying data
	char*									m_resourceName;						//!< Resource name of the entity
	UINT32									m_zoneFlags;						//!< Zone flags -- see RuGaia_Base for details

	// Orientation
	CRuVector3								m_scale;							//!< Scale of the entity
	CRuQuaternion							m_rotation;							//!< Rotation of the entity
	CRuVector3								m_translation;						//!< Translation of the entity

	// Bounding information
	BOOL									m_worldBoundsDirty;					//!< Is world bounds dirty?
	CRuSphere								m_localBounds;						//!< Local bounds of the entity
	CRuSphere								m_worldBounds;						//!< Bounds of the entity

	// Chunk relation information
	CRuArrayList<INT32>						m_linkedChunks;						//!< ID of chunks that associate with this entity

public:
											CRuWorld_EntityDescriptor();
	virtual									~CRuWorld_EntityDescriptor();

	// Serialization interface
	RUAPI virtual BOOL						SerializeFrom(IRuStream *stream);
	RUAPI virtual BOOL						SerializeTo(IRuStream *stream);

	RUAPI const char*						GetResourceName() const;
	RUAPI void								SetResourceName(const char *resName);

	RUAPI UINT32							GetZoneFlags() const;
	RUAPI void								SetZoneFlags(UINT32 zoneFlags);

	RUAPI const CRuVector3&					GetScale() const;
	RUAPI void								SetScale(const CRuVector3 &scale);

	RUAPI const CRuQuaternion&				GetRotation() const;
	RUAPI void								SetRotation(const CRuQuaternion &rotation);

	RUAPI const CRuVector3&					GetTranslation() const;
	RUAPI void								SetTranslation(const CRuVector3 &translation);

	RUAPI const CRuSphere&					GetLocalBounds() const;
	RUAPI void								SetLocalBounds(const CRuSphere &bounds);

	RUAPI const CRuSphere&					GetWorldBounds();

	// Linked chunks
	RUAPI INT32								GetNumLinkedChunks() const;
	RUAPI INT32								GetLinkedChunk(INT32 index) const;
	RUAPI BOOL								InsertLinkedChunk(INT32 chunkID);
	RUAPI BOOL								DeleteLinkedChunk(INT32 chunkID);
	RUAPI void								ClearLinkedChunks();
};

// ************************************************************************************************************************************************************

class CRuWorld_Trigger : public CRuEntity
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	CRuGizmo_Plane*							m_planeGizmo;						//!< Plane gizmo that defines the area of the trigger
	RuWorld::TriggerType					m_triggerType;
	INT32									m_zoneID;							//!< Trigger zone ID

public:
											CRuWorld_Trigger();
	virtual									~CRuWorld_Trigger();

	// IRuObject interface
	virtual BOOL							SerializeFrom(IRuStream *stream);
	virtual BOOL							SerializeTo(IRuStream *stream);

	void									Initialize(const CRuVector3 &origin);

	CRuGizmo_Plane*							GetGizmo();

	RuWorld::TriggerType					GetTriggerType();
	void									SetTriggerType(RuWorld::TriggerType triggerType);

	INT32									GetZoneID();
	void									SetZoneID(INT32 zoneID);
};

// ************************************************************************************************************************************************************

ruOBJECTMODULE_DEFINE(CRuObjectModule_RuWorld_EntityDescriptor, CRuWorld_EntityDescriptor)
ruOBJECTMODULE_DEFINE(CRuObjectModule_RuWorld_Trigger, CRuWorld_Trigger)

// ************************************************************************************************************************************************************

#pragma managed

#endif
