#ifndef _RURESOURCEMANAGERD3D_H_
#define _RURESOURCEMANAGERD3D_H_

#include "../../Engine/Base/RuEngineBase.h"
#include "../../Engine/Base/RuResourceManagerBase.h"

#include "../../Engine/Texture/RuTextureAtlas_Aggregate.h"
#include "../../Engine/Texture/RuTextureAtlas_Paged.h"

#pragma unmanaged

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

class cFilePackage;

class CRuResourceManagerD3D : public IRuResourceManager
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

protected:
	class CRuRenderTargetPool
	{
	protected:
		INT32								m_poolSize;							//!< Size of the pool (number of render targets)
		INT32								m_rtSize;							//!< Render target size
		RuSurfaceFormat						m_rtFormat;							//!< Render target surface format

		CRuStack<IRuTexture *>				m_freeRenderTargets;				//!< Stack of free render targets
		CRuArrayList<IRuTexture *>			m_usedRenderTargets;				//!< List of used render targets

	public:
											CRuRenderTargetPool(IRuEngine *engine, INT32 poolSize, INT32 rtSize, RuSurfaceFormat rtFormat);
											~CRuRenderTargetPool();

		BOOL								IsIdenticalPoolType(INT32 rtSize, RuSurfaceFormat rtFormat);
		INT32								GetMatchScore(INT32 rtSize, RuSurfaceFormat rtFormat);

		IRuTexture*							GetRenderTarget();
		BOOL								FreeRenderTarget(IRuTexture *renderTarget);
		BOOL								ResetRenderTargetPool();
	};

	struct TextureDesc
	{
		DWORD								m_gcAge;							//!< Garbage collection age marker
		BOOL								m_disableGC;						//!< Disable GC on this texture?
		BOOL								m_pinned;							//!< Is texture pinned? (When pinned, the texture is never cleared from the cache)
		IRuBaseTexture*						m_texture;							//!< Texture

		TextureDesc()
		{
			m_gcAge = 0;
			m_disableGC = FALSE;
			m_pinned = FALSE;
			m_texture = NULL;
		}
	};

	struct ObjectDesc
	{
		INT32								m_cloneCount;
		DWORD								m_gcAge;
		IRuObject*							m_object;

		ObjectDesc()
		{
			m_cloneCount = -1;
			m_gcAge = 0;
			m_object = NULL;
		}
	};

	CRuGUID									m_guid_ProcessWorkQueues;			//!< GUID used for registering work queue processing function
	CRuGUID									m_guid_GarbageCollect;				//!< GUID used for registering garbage collection function

	IRuEngine*							m_engine;							// Engine core

	cFilePackage*							m_filePackage;						// File packager Entity

	CRuTernaryStringTree<IRuStream *>*		m_streamTree;

	CRuTernaryStringTree<TextureDesc>*		m_textureHash;

	CRuStringHash<CRuAnimation *>*			m_animationHash;					// Animation hash
	CRuStringHash<CRuAnimation_GR2 *>*		m_animationHash_GR2;				// Animation hash

	CRuTernaryStringTree<ObjectDesc>*		m_entityHash;

	CRuTernaryStringTree<IRuObject *>*		m_genericObjectTree;				//!< Generic object tree

	CRuArrayList<CRuRenderTargetPool *>		m_renderTargetPools;				//!< List of render target pools

	CRuTextureAtlas_Aggregate*				m_rtAtlas;							//!< Render target atlas

	DWORD									m_lastGCTime;
	DWORD									m_timeSinceLastGC;
	CRuArrayList<IRuBaseTexture *>			m_gc_Texture;
	CRuArrayList<IRuObject *>				m_gc_Object;

	// Critical sections
	CRuThread_CriticalSection*				m_filePackage_CS;

	// Probes
	INT32									m_probe_TextureLoads;
	INT32									m_probe_TextureLoadFails;
	INT32									m_probe_TextureLoadTransientFails;
	INT32									m_probe_EntityLoads;
	INT32									m_probe_EntityLoadFails;
	INT32									m_probe_EntityLoadTransientFails;

	// Work queues
	CRuThread_WorkQueue<char *, IRuStream *>*		m_streamWorkQueue;
	CRuThread_WorkQueue<char *, IRuObject *>*		m_objectWorkQueue;
	CRuThread_WorkQueue<char *, IRuBaseTexture *>*	m_textureWorkQueue;

	struct TextureWorkEntry
	{
		CRuTexture_Proxy*					m_stubTexture;
		RuSurfaceFormat						m_surfaceFormat;
		INT32								m_maxMipLevel;
	};

	CRuTernaryStringTree<TextureWorkEntry>			m_streamingTextures;
	CRuThread_CriticalSection						m_cs_StreamingTextures;



	// Worker thread
	CRuGUID									m_workerFunctionGUID;

	// Temp
	INT32									m_temp_Footprint;
	INT32									m_temp_Footprint2;
	CRuKeyHash<PTRVALUE>*					m_temp_EnumHash;

	CRuArrayList<TextureDesc>				m_temp_TextureDescList;

public:
											CRuResourceManagerD3D();
	virtual									~CRuResourceManagerD3D();

	// Memory reporting
	virtual INT32							GetMemoryFootprint(CRuKeyHash<PTRVALUE> *enumHash = NULL);

	// Engine association
	BOOL									SetEngine(IRuEngine *engine);
	virtual IRuEngine*						GetEngine();

	// Manager setup
	virtual const char*						GetRootDirectory();
	virtual void							SetRootDirectory(const char *rootDirectory);
	virtual	void							LoadPackageFile(const char *filename);
	virtual BOOL							FileExists(const char* filename);
	virtual BOOL							SetObjectDequeueRate(REAL dequeueRate);
	virtual BOOL							SetTextureDequeueRate(REAL dequeueRate);

	// Generic stream loading
	virtual IRuStream*						LoadStream(const char *resourceName);
	virtual BOOL							LoadStream(const char *resourceName, IRuStream **streamOut);

	// Texture management
	virtual BOOL							AddTexture(IRuBaseTexture *texture);
	virtual BOOL							RemoveTexture(IRuBaseTexture *texture);
	virtual BOOL							RemoveTexture(const char *textureName);
	virtual BOOL							TextureExistsInCache(const char *textureName);
	virtual BOOL							EnableTextureGarbageCollection(IRuBaseTexture *texture, BOOL enableGC);
	virtual BOOL							PinTexture(IRuBaseTexture *texture, BOOL pinTexture);

	virtual	IRuTexture*						LoadTexture(const char *textureName, RuSurfaceFormat surfaceFormat = ruSURFACEFMT_DEFAULT, UINT32 maxMipLevel = 0, BOOL async = FALSE);

	virtual BOOL							CreateRenderTargetPool(INT32 poolSize, INT32 rtSize, RuSurfaceFormat rtFormat);
	virtual BOOL							ResetRenderTargetPools();
	virtual IRuTexture*						GetPooledRenderTarget(INT32 rtSize, RuSurfaceFormat rtFormat);
	virtual BOOL							FreePooledRenderTarget(IRuTexture *renderTarget);

	virtual BOOL							CreateRenderTargetSubAtlas(INT32 subAtlasSize, INT32 pageSize, RuSurfaceFormat rtFormat);
	virtual BOOL							RestoreRenderTargetView(IRuTextureView *textureView);
	virtual BOOL							ResetRenderTargetViews();

	// Animation management
	virtual CRuAnimation*					LoadAnimation(const char *animationName);
	virtual CRuAnimation_GR2*				LoadAnimation_GR2(const char *animationName);

	// Entity management
	// TODO: Pre-load function, garbage collection of stale entities(clone count = 1), etc
	virtual BOOL							AddEntity(const char *entityName, CRuEntity *entity);

	virtual CRuEntity*						LoadEntity(const char *entityName);
	virtual BOOL							LoadEntity(const char *entityName, CRuEntity **entityOut);

	// Generic object dictionary
	virtual BOOL							AddGenericObject(const char *objectName, IRuObject *obj);
	virtual IRuObject*						GetGenericObject(const char *objectName);

	// Dictionary management
	virtual BOOL							ClearTextureDictionary();
	virtual BOOL							ClearAnimationDictionary();
	virtual BOOL							ClearAnimationDictionary_GR2();
	virtual BOOL							ClearEntityDictionary();
	virtual BOOL							ClearGenericObjectDictionary();

	// Status report
	virtual BOOL							IsObjectWorkQueueEmpty();
	virtual BOOL							IsTextureWorkQueueEmpty();

	// Debugging
	virtual BOOL							OutputResourceManifest();

protected:
	BOOL									HandleEvent_ObjectCloned(RuEventArgs *eventArgs);
	BOOL									HandleEvent_ObjectDisposed(RuEventArgs *eventArgs);

	// Garbage collection and other queue processing
	BOOL									ProcessWorkQueues(PTRVALUE userData);
	BOOL									GarbageCollect(PTRVALUE userData);

	BOOL									TextureDictionaryMemoryFootprintCallback(const void *key, void *data);
	BOOL									EntityDictionaryMemoryFootprintCallback(const void *key, void *data);

	void									UnpinAllTextures();
	BOOL									UnpinAllTexturesCallback(const void *key, void *data);

	BOOL									ClearTextureDictionaryCallback(const void *key, void *data);
	static BOOL								ClearAnimationDictionaryCallback(const void *key, const void *data, void *userData);
	static BOOL								ClearAnimationDictionaryCallback_GR2(const void *key, const void *data, void *userData);
	BOOL									ClearEntityDictionaryCallback(const void *key, void *data);
	BOOL									ClearGenericObjectDictionaryCallback(const void *key, void *data);

	BOOL									GCTextureDictionaryCallback(const void *key, void *data);
	BOOL									GCEntityDictionaryCallback(const void *key, void *data);

	BOOL									TextureManifestCallback(const void *key, void *data);
	BOOL									EntityManifestCallback(const void *key, void *data);

	// Common access to the file manager
	IRuStream*								LoadStream_Internal(const char *streamName);
	BOOL									DestroyStream_Internal(IRuStream *stream);

	// Other helpers
	RuSurfaceFormat							GetImageSurfaceFormat(IRuStream *imgStream);
	INT32									GetImageMipLevels(IRuStream *imgStream);
	IRuTexture*								CreateTextureToImageSpec(IRuStream *imgStream);
	BOOL									CopyImageToTexture(IRuStream *imgStream, IRuTexture *texture);

	IRuTexture*								LoadTexture_Internal(const char *textureName);
	BOOL									ConvertTexture_Internal(IRuTexture *srcTexture, CRuTexture_Proxy *dstTexture, RuSurfaceFormat surfaceFormat, INT32 maxMipLevel);

	BOOL									WorkerFunction();
};

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

#pragma managed

#endif
