#ifndef _RUGAIA_STREAM_H_
#define _RUGAIA_STREAM_H_

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

#pragma unmanaged

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

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

protected:
	struct ZoneDescriptorInfo
	{
		INT32									m_timeGroup;											//!< Time group
		INT32									m_weatherGroup;											//!< Weather group
		CRuGaia_ZoneDescriptor*					m_zoneDescriptor;										//!< Zone descriptor
	};

	struct ColObjectDesc
	{
		INT32									m_key;													//!< Collision object key
		INT32									m_iteration;											//!< TODO: Iteration number of the collision object
		INT32									m_offset;												//!< Collision object offset
		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, INT32 objOffset);
		BOOL									RemoveCollisionObject(INT32 objKey);

		BOOL									SerializeFrom(IRuStream *stream);
		BOOL									SerializeTo(IRuStream *stream);

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

	// Source stream
	IRuStream*									m_stream;												//!< Data stream

	// Header stuff
	INT32										m_tableAddressOffset;									//!< Offset, from beginning of data stream, to the 32-bit quantity that stores the collision tree table offset in the stream
	INT32										m_zoneTableAddressOffset;								//!< Offset, from beginning of data stream, to the 32-bit quantity that stores the zone table offset in the stream

	// House-keeping
	CRuAABB										m_bounds;
	float										m_gridSpacing;
	char*										m_srcResourceName;

	// Tree
	Node*										m_root;													//!< Root node

	// Zone descriptor table
	CRuArrayList<CRuGaia_ZoneDescriptor *>		m_zoneDescriptors;										//!< Zone descriptor array

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

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

public:
												CRuGaia_Stream();
	virtual										~CRuGaia_Stream();

	BOOL										Create(IRuStream *stream, const CRuAABB &bounds, float maxExtents, float gridSpacing, const char *srcResourceName);
	BOOL										Open(IRuStream *stream);
	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								MarkZoneDescriptorAsDirty(const CRuGaia_ZoneDescriptor *zoneDesc) { return TRUE; }

	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										SaveTimeGroups(IRuStream *stream);
	void										LoadTimeGroups(IRuStream *stream);
	IRuCollisionObject*							InstanceCollisionObject(ColObjectDesc *objDesc);
	BOOL										FlushColObjQueue();
	static BOOL									FlushColObjQueueCallback(const void *key, const void *data, void *userData);
};

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

#pragma managed

#endif
