#pragma once

#include "../../Engine/Animation/RuAnimBase.h"

#include "../../Engine/Base/RuCore.h"

#include "../../Engine/Base/RuEngineBase.h"
#include "../../Engine/Base/RuShaderBase.h"
#include "../../Engine/Base/RuMaterialBase.h"
#include "../../Engine/Base/RuInstanceManagerBase.h"

#include "../../Engine/Geometry/RuMeshBase.h"

#pragma managed(push, off)

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

class CRuInstanceManagerD3D : public IRuInstanceManager
{
	ruRTTI_DECLARE
	ruHEAP_DECLARE
	ruCLASSGUID_DECLARE

private:
	struct VBDesc
	{
		INT32											m_instanceIteration;
		INT32											m_usageCycle;
		IRuVertexBuffer*								m_vertexBuffer;
	};

	struct IBDesc
	{
		INT32											m_instanceIteration;
		INT32											m_usageCycle;
		IRuIndexBuffer*									m_indexBuffer;
	};

	struct BufferGCTuple
	{
		PTRVALUE										m_poolKey;
		CRuGUID											m_bufferKey;
	};

	struct TexDesc
	{
		PTRVALUE										m_texturePool;
		INT32											m_usageCycle;
		IRuBaseTexture*									m_sourceTexture;
		IRuBaseTexture*									m_instancedTexture;
	};

	struct TextureGCTuple
	{
		IRuBaseTexture*									m_texture;
		INT32											m_gcAge;
	};

	struct TexPoolDesc
	{
		CRuArrayList<IRuBaseTexture *>*					m_usedTextures;
		CRuQueue<TextureGCTuple>*						m_unusedTextures;
	};

	// Convenience typedefs
	typedef CRuHashMap<CRuGUID, VBDesc>					VertexBufferPool;

	// Cycle counter
	INT32												m_currentCycle;

	// Mesh instantiators
	CRuHashMap<PTRVALUE, IRuMeshInstantiator *>*		m_meshInstantiatorHash;

	IRuEngine*										m_engine;							//!< Engine core

	// Device buffer manager states
	CRuHashMap<PTRVALUE, VertexBufferPool *>*			m_vbPoolHash;
	CRuHashMap<CRuGUID, IBDesc>*						m_ibHash;

	PTRVALUE											m_gc_CurPoolKey;
	CRuQueue<BufferGCTuple>								m_gc_Buffers;

	// Texture instantiation pools
	CRuHashMap<CRuGUID, TexDesc *>*						m_instancedTextures;				//!< Hash of instanced textures
	CRuHashMap<CRuGUID, TexPoolDesc *>*					m_texturePools;						//!< Pools of unused textures

	CRuArrayList<CRuGUID>								m_gcInstancedTextures;

	PTRVALUE											m_purgeableTexturePool;
	INT32												m_purgeableTextureCycleDiff;
	CRuGUID												m_purgeableTextureKey;

	// Metrics
	char												m_metric_String[1024];
	INT32												m_metric_NumIBAllocations;
	INT32												m_metric_NumVBAllocations;
	INT32												m_metric_NumIBInstanceOps;
	INT32												m_metric_NumVBInstanceOps;

public:
														CRuInstanceManagerD3D();
	virtual												~CRuInstanceManagerD3D();

	// Settings
	virtual UINT32										GetCacheSize();

	BOOL												SetEngine(IRuEngine *engine);
	virtual IRuEngine*									GetEngine();

	// Mesh instantiator registration
	virtual BOOL										RegisterMeshInstantiator(IRuMeshInstantiator *meshInstantiator);
	IRuMeshInstantiator*								GetMeshInstantiator(const IRuVertexDeclaration *vertexDeclaration);

	// Instance retrieval
	virtual IRuVertexBuffer*							GetInstancedVertexBuffer(IRuMesh *mesh, IRuShader *shader);
	virtual IRuIndexBuffer*								GetInstancedIndexBuffer(IRuMesh *mesh);

	// Instance retrieval for textures
	BOOL												TestTextureCompatibility(IRuBaseTexture *texture0, IRuBaseTexture *texture1);
	virtual IRuBaseTexture*								GetInstance(IRuBaseTexture *texture);

	// Data invalidation
	virtual BOOL										ClearCache();

	// Metrics
	virtual INT32										GetNumMetricStrings();
	virtual const char*									GetMetricString(INT32 stringIndex);

	// Debugging
	virtual BOOL										OutputInstantiationManifest();

private:
	// Event handlers
	BOOL												HandleEvent_BeginScene(RuEventArgs *eventArgs);
	BOOL												HandleEvent_DeviceReset(RuEventArgs *eventArgs);

	// Mesh instantiator management
	void												ClearMeshInstantiators();
	BOOL												ClearMeshInstantiatorsCallback(const void *key, void *data);

	// Vertex buffer management
	VertexBufferPool*									GetVertexBufferPool(PTRVALUE poolKey, DWORD poolKeyHash);

	BOOL												DeleteInstancedVertexBufferPools();
	BOOL												DeleteInstancedVertexBufferPoolsCallback(const void *key, void *data);

	BOOL												ClearInstancedVertexBufferPools();
	BOOL												ClearInstancedVertexBufferPoolsCallback(const void *key, void *data);

	BOOL												ClearInstancedVertexBuffers(VertexBufferPool *vbPool);
	BOOL												ClearInstancedVertexBuffersCallback(const void *key, void *data);

	BOOL												GCInstancedVertexBufferPools();
	BOOL												GCInstancedVertexBufferPoolsCallback(const void *key, void *data);

	BOOL												GCInstancedVertexBuffers(VertexBufferPool *vbPool);
	BOOL												GCInstancedVertexBuffersCallback(const void *key, void *data);

	// Index buffer management
	BOOL												ClearInstancedIndexBuffers();
	BOOL												ClearInstancedIndexBuffersCallback(const void *key, void *data);

	BOOL												GCInstancedIndexBuffers();
	BOOL												GCInstancedIndexBuffersCallback(const void *key, void *data);

	// Texture management utilities
	CRuGUID												BuildTexturePoolKey(IRuBaseTexture *texture);
	IRuBaseTexture*										CreatePooledTexture(IRuBaseTexture *texture, PTRVALUE texturePool);
	IRuBaseTexture*										CreateScratchTexture(IRuBaseTexture *texture);

	// Instanced texture
	BOOL												ReleaseTextureInstance(CRuInstanceManagerD3D::TexDesc *texDesc);
	BOOL												ClearInstancedTextures();
	BOOL												ClearInstancedTexturesCallback(const void *key, void *data);
	BOOL												InstancedTextureGCCallback(const void *key, void *data);

	// Texture pool
	BOOL												TexturePoolGC();
	BOOL												TexturePoolGCCallback(const void *key, void *data);
	BOOL												ClearTexturePool();
	BOOL												ClearTexturePoolCallback(const void *key, void *data);
	BOOL												TexturePoolManifestCallback(const void *key, void *data);
};

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

#pragma managed(pop)
