#ifndef _RUGAIA_SQL_H_
#define _RUGAIA_SQL_H_

// Base types
#include "../Gaia/RuGaia_Base.h"
#include "../SQL/RuSQL_Base.h"

#pragma unmanaged

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

/*!
	A streamed AABB tree. 
*/
class CRuGaia_SQL : public CRuGaia_Base
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	struct ZoneDescriptorInfo
	{
		CRuGaia_ZoneDescriptor*					m_zoneDescriptor;										//!< Zone descriptor
		BOOL									m_dirty;												//!< Is the zone descriptor dirty?
	};

	struct ColObjectDesc
	{
		BOOL									m_dirty;												//!< Is the collision object descriptor dirty?
		INT32									m_key;													//!< Collision object key
		INT32									m_iteration;											//!< TODO: Iteration number of the collision object
		CRuAABB									m_bounds;												//!< Collision object bounds
	};

	struct Node
	{
		CRuVector3								m_center;												//!< True center of the node
		CRuAABB									m_bounds;												//!< Bounding box of the node
		CRuArrayList<ColObjectDesc *>*			m_colObjects;											//!< List of collison object descriptors
		Node*									m_children[4];											//!< Pointers to children

												Node();
												Node(const CRuAABB &bounds, float maxExtents);
												~Node();
	
		BOOL									IsLeaf()
												{
													return m_children[0] == NULL;
												}

		BOOL									AddCollisionObject(IRuCollisionObject *colObject);
		BOOL									AddCollisionObject(ColObjectDesc *colObjectDesc);
		BOOL									RemoveCollisionObject(INT32 objKey);

		void									ResetDirty();
		void									Enumerate(CRuCollisionQuery *colQuery, CRuArrayList<ColObjectDesc *> &objListOut);
		void									EnumerateDirty(CRuArrayList<ColObjectDesc *> &objListOut);
	};

	// SQL session
	CRuSQLSession*								m_sqlSession;

	// House-keeping
	CRuAABB										m_bounds;												//!< Total bounding volume of the Gaia object
	REAL										m_maxExtents;											//!< Maximum extents per node
	REAL										m_gridSpacing;											//!< Collision grid spacing
	char*										m_collisionMapName;										//!< Collision map name
	char*										m_srcResourceName;										//!< Source map name

	// Collision objects
	CRuArrayList<INT32>							m_deletedCollisionObjectDescriptors;					//!< List of keys of deleted collision object descriptors
	CRuArrayList<IRuCollisionObject *>			m_uncommittedCollisionObjects;							//!< List of collision objects that must be committed to the database

	// Zone descriptor table
	CRuArrayList<ZoneDescriptorInfo>			m_deletedZoneDescriptors;								//!< Deleted zone descriptor array
	CRuArrayList<ZoneDescriptorInfo>			m_zoneDescriptors;										//!< Zone descriptor array

	// Runtime node tree
	Node*										m_root;													//!< Root node

	// Runtime collision object instancing data
	CRuLRUQueue<INT32, IRuCollisionObject *>*	m_colObjQueue;											//!< LRU queue of instanced collision objects

	// Workspace
	CRuArrayList<ColObjectDesc *>				m_objList;												//!< Scratch pad

public:
												CRuGaia_SQL();
	virtual										~CRuGaia_SQL();

	BOOL										Create(char *collisionMapName, char *srcResourceName, const CRuAABB &bounds, float maxExtents, float gridSpacing);
	BOOL										Open(char *collisionMapName);
	virtual BOOL								Save();

	virtual const CRuAABB&						GetBounds() const;
	virtual float								GetGridSpacing() const;
	virtual const char*							GetSourceResourceName() const;
	
	virtual INT32								GetNumZoneDescriptors() const;

	virtual const CRuGaia_ZoneDescriptor*		GetZoneDescriptor(INT32 id, INT32 timeGroup, INT32 weatherGroup) const;
	virtual const CRuGaia_ZoneDescriptor*		GetZoneDescriptorByIndex(INT32 index) const;

	virtual BOOL								SetZoneDescriptor(const CRuGaia_ZoneDescriptor *zoneDesc);
	virtual BOOL								RemoveZoneDescriptor(const CRuGaia_ZoneDescriptor *zoneDesc);
	virtual BOOL								RemoveZoneDescriptorAtIndex(INT32 index);

	virtual BOOL								SetZoneName(INT32 id, const char *zoneName);
	virtual BOOL								SetZoneID(INT32 oldID, INT32 newID);

	virtual IRuPathHierarchy_Base*				GetPathHierarchy() { return NULL; }

	// Hierarchy management
	virtual BOOL								AddCollisionObject(IRuCollisionObject *colObject);
	virtual BOOL								RemoveCollisionObject(INT32 objKey);

	// Collision query interface
	virtual BOOL								QueryCollision(CRuCollisionQuery *colQuery);

protected:
	void										ClearZoneDescriptors();
	void										ClearDeletedZoneDescriptors();

	void										SaveCollisionObjectDescriptors();
	void										LoadCollisionObjectDescriptors();
	void										SaveCollisionObjects();

	void										SaveTimeGroups();
	void										LoadTimeGroups();

	IRuCollisionObject*							InstanceCollisionObject(ColObjectDesc *objDesc);
	BOOL										FlushColObjQueue();
	static BOOL									FlushColObjQueueCallback(const void *key, const void *data, void *userData);
};

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

#pragma managed

#endif
