#include "../NULL/RuResourceManager_NULL.h"

// Instance manager base
#include "../Engine/Base/RuInstanceManagerBase.h"

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

// Rune base entity system core
#include "../Scene/Base/RuEntityBase.h"
#include "../Scene/Base/RuEntityACT.h"

#include <tchar.h>
#include "../../Tools/FilePackage/cFilePackage.h"

#pragma unmanaged

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

CRuResourceManager_NULL::CRuResourceManager_NULL()
{
	// Create file manager
	m_filePackage = ruNEW cFilePackage();

	// Create resource dictionary hash tables
	m_animationHash = ruNEW CRuStringHash<CRuAnimation *>(4096);
	m_animationHash_GR2 = ruNEW CRuStringHash<CRuAnimation_GR2 *>(4096);
	m_entityHash = ruNEW CRuStringHash<IRuObject *>(4096);
	m_genericObjectTree = ruNEW CRuTernaryStringTree<IRuObject *>();
}

CRuResourceManager_NULL::~CRuResourceManager_NULL()
{
	// Release animations held by the dictionary
	ClearAnimationDictionary();
	ClearAnimationDictionary_GR2();

	// Release entities held by the dictionary
	ClearEntityDictionary();

	// Clear generic object dictionary
	ClearGenericObjectDictionary();

	// Release file manager
	delete m_filePackage;

	// Release resource dictionaries
	delete m_animationHash;
	delete m_animationHash_GR2;
	delete m_entityHash;
	delete m_genericObjectTree;
}

IRuEngine *CRuResourceManager_NULL::GetEngine()
{
	return NULL;
}

const char *CRuResourceManager_NULL::GetRootDirectory()
{
	return m_filePackage->GetDirectory();
}

void CRuResourceManager_NULL::SetRootDirectory(const char *rootDirectory)
{
	if(m_filePackage)
	{
		delete m_filePackage;
	}

	m_filePackage = ruNEW cFilePackage();
	m_filePackage->SetDirectory(rootDirectory);
}

void CRuResourceManager_NULL::LoadPackageFile(const char *filename)
{
	if ( m_filePackage )
	{
		//m_filePackage->LoadFromFile(filename);

		if ( m_filePackage )
		{
			char fullPath[2048];
			sprintf(fullPath, "%s\\%s", m_filePackage->GetDirectory(), filename);

			m_filePackage->LoadFromFile(fullPath);

			printf( "CRuResourceManager_NULL::LoadPackageFile( %s )\n", fullPath ); fflush( NULL );
		}
	}
}

BOOL CRuResourceManager_NULL::FileExists(const char* filename)
{
	if ( m_filePackage && m_filePackage->FileExists(filename) )
	{
		return TRUE;
	}
	return FALSE;
}

BOOL CRuResourceManager_NULL::SetObjectDequeueRate(REAL dequeueRate)
{
	return TRUE;
}

BOOL CRuResourceManager_NULL::SetTextureDequeueRate(REAL dequeueRate)
{
	return TRUE;
}

IRuStream *CRuResourceManager_NULL::LoadStream(const char *resourceName)
{
	return m_filePackage->GetIRuStream(resourceName);
}

BOOL CRuResourceManager_NULL::LoadStream(const char *resourceName, IRuStream **streamOut)
{
	*streamOut = m_filePackage->GetIRuStream(resourceName);
	return TRUE;
}

BOOL CRuResourceManager_NULL::AddTexture(IRuBaseTexture *texture)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::RemoveTexture(IRuBaseTexture *texture)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::RemoveTexture(const char *textureName)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::TextureExistsInCache(const char *textureName)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::EnableTextureGarbageCollection(IRuBaseTexture *texture, BOOL enableGC)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::PinTexture(IRuBaseTexture *texture, BOOL pinTexture)
{
	return FALSE;
}

IRuTexture *CRuResourceManager_NULL::LoadTexture(const char *textureName, RuSurfaceFormat surfaceFormat, UINT32 maxMipLevel, BOOL async)
{
	return NULL;
}

BOOL CRuResourceManager_NULL::CreateRenderTargetPool(INT32 poolSize, INT32 rtSize, RuSurfaceFormat rtFormat)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::ResetRenderTargetPools()
{
	return TRUE;
}

IRuTexture *CRuResourceManager_NULL::GetPooledRenderTarget(INT32 rtSize, RuSurfaceFormat rtFormat)
{
	return NULL;
}

BOOL CRuResourceManager_NULL::FreePooledRenderTarget(IRuTexture *renderTarget)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::CreateRenderTargetSubAtlas(INT32 subAtlasSize, INT32 pageSize, RuSurfaceFormat rtFormat)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::RestoreRenderTargetView(IRuTextureView *textureView)
{
	return FALSE;
}

BOOL CRuResourceManager_NULL::ResetRenderTargetViews()
{
	return FALSE;
}

CRuAnimation *CRuResourceManager_NULL::LoadAnimation(const char *animationName)
{
	CRuAnimation *animation = NULL;

	if(animationName)
	{
		if(m_animationHash->Get(animationName, animation))
		{
			animation->AddRef();

			return animation;
		}

		IRuStream *srcStream = m_filePackage->GetIRuStream(animationName);

		if(srcStream)
		{
			animation = LoadRuAnimation(srcStream);

			if(animation)
			{
				animation->AddRef();
				m_animationHash->Add(animationName, animation);
			}

			delete srcStream;
		}
	}

	return animation;
}

CRuAnimation_GR2 *CRuResourceManager_NULL::LoadAnimation_GR2(const char *animationName)
{
	CRuAnimation_GR2 *animation = NULL;

	if(animationName)
	{
		if(m_animationHash_GR2->Get(animationName, animation))
		{
			animation->AddRef();

			return animation;
		}

		IRuStream *srcStream = m_filePackage->GetIRuStream(animationName);

		if(srcStream)
		{
			animation = ruNEW CRuAnimation_GR2();

			if(animation->SerializeFrom(srcStream) == FALSE)
			{
				ruSAFE_RELEASE(animation);
			}
			else
			{
				animation->AddRef();
				m_animationHash_GR2->Add(animationName, animation);
			}

			delete srcStream;
		}
	}

	return animation;
}

BOOL CRuResourceManager_NULL::AddEntity(const char *entityName, CRuEntity *entity)
{
	IRuObject *existingEntity;

	// Look for the entity in the hash
	if(m_entityHash->Get(entityName, existingEntity) == FALSE)
	{
		existingEntity->AddRef();

		// Add template to the entity hash
		m_entityHash->Add(entityName, entity);

		return TRUE;
	}

	return FALSE;
}

CRuEntity *CRuResourceManager_NULL::LoadEntity(const char *entityName)
{
	IRuObject *object = NULL;

	if(entityName == NULL)
	{
		return NULL;
	}

	// Look for the entity in the hash
	if(m_entityHash->Get(entityName, object))
	{
		// Custom processing based on object type
		if(object->GetType().IsSubClassOf(CRuEntity::Type))
		{
			// Return a clone of the entity
			IRuObject *clone = object->Clone();

			if(clone->GetType().IsSubClassOf(CRuEntity::Type))
				return static_cast<CRuEntity *>(clone);
			else
				return NULL;
		}
		else if(object->GetType().IsSubClassOf(CRuACTTemplate::Type))
		{
			// Construct an object from the ACT template and return it
			return static_cast<CRuACTTemplate *>(object)->Construct();
		}
		else if(object->GetType().IsSubClassOf(CRuPaperdollTemplate::Type))
		{
			// Construct an object from the paperdoll template and return it
			return static_cast<CRuPaperdollTemplate *>(object)->Construct();
		}
	}

	// Attempt to retrieve the named stream from the data store
	IRuStream *stream = m_filePackage->GetIRuStream(entityName);

	if(stream)
	{
		// Create object using the object factory
		IRuObject *entityObject = g_ruObjectFactory.CreateObject(stream);

		// Destroy the data stream
		delete stream;

		if(entityObject)
		{
			// Set the object's resource name
			entityObject->SetResourceName(entityName);

			if(entityObject->GetType().IsSubClassOf(CRuEntity::Type))
			{
				// Add entity to the entity hash
				CRuEntity *entity = static_cast<CRuEntity *>(entityObject);
				m_entityHash->Add(entityName, entity);

				// Return a clone of the entity
				IRuObject *clone = entity->Clone();

				// If the clone is valid, return it
				if(clone && clone->GetType().IsSubClassOf(CRuEntity::Type))
					return static_cast<CRuEntity *>(clone);

				// Release clone
				ruSAFE_RELEASE(clone);

				return NULL;
			}
			else if(entityObject->GetType() == CRuACTTemplate::Type)
			{
				// Construct an object from the ACT template
				CRuEntity *entity = static_cast<CRuACTTemplate *>(entityObject)->Construct();

				// Add template to the entity hash
				m_entityHash->Add(entityName, entityObject);

				// Return the constructed ACT entity
				return entity;
			}
			else if(entityObject->GetType() == CRuPaperdollTemplate::Type)
			{
				// Construct an object from the paperdoll template
				CRuEntity *entity = static_cast<CRuPaperdollTemplate *>(entityObject)->Construct();

				// Add template to the entity hash
				m_entityHash->Add(entityName, entityObject);

				// Return the constructed paperdoll entity
				return entity;
			}
			else
			{
				// Unrecognized object, release it and return NULL
				entityObject->Release();

				return NULL;
			}
		}
	}

	// Could not find object in the hash and could not read from data store, return NULL
	return NULL;
}

BOOL CRuResourceManager_NULL::LoadEntity(const char *entityName, CRuEntity **entityOut)
{
	*entityOut = LoadEntity(entityName);

	return entityOut != NULL;
}

BOOL CRuResourceManager_NULL::AddGenericObject(const char *objectName, IRuObject *obj)
{
	IRuObject *existingObject = NULL;

	// Make sure the object does not already exist in the dictionary
	if(m_genericObjectTree->Get(objectName, existingObject) == FALSE)
	{
		// Add object to the dictionary
		obj->AddRef();
		m_genericObjectTree->Add(objectName, obj);

		return TRUE;
	}

	return FALSE;
}

IRuObject *CRuResourceManager_NULL::GetGenericObject(const char *objectName)
{
	IRuObject *existingObject = NULL;

	// Look for generic object in the dictionary
	m_genericObjectTree->Get(objectName, existingObject);

	if(existingObject)
	{
		existingObject->AddRef();
	}

	return existingObject;
}

BOOL CRuResourceManager_NULL::ClearTextureDictionary()
{
	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearAnimationDictionary()
{
	// Release all animations held in the dictionary
	m_animationHash->ForAllElements(ClearAnimationDictionaryCallback, this);

	// Clear all animation entries
	m_animationHash->Clear();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearAnimationDictionary_GR2()
{
	// Release all animations held in the dictionary
	m_animationHash_GR2->ForAllElements(ClearAnimationDictionaryCallback_GR2, this);

	// Clear all animation entries
	m_animationHash_GR2->Clear();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearEntityDictionary()
{
	// Release all entities held in the dictionary
	m_entityHash->ForAllElements(ClearEntityDictionaryCallback, this);

	// Clear all entity entries
	m_entityHash->Clear();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearGenericObjectDictionary()
{
	// Release all generic objects held in the dictionary
	m_genericObjectTree->ForAllElements(boost::bind(&CRuResourceManager_NULL::ClearGenericObjectDictionaryCallback, this, _1, _2));

	// Clear all entries
	m_genericObjectTree->Clear();

	return TRUE;
}

BOOL CRuResourceManager_NULL::IsObjectWorkQueueEmpty()
{
	return TRUE;
}

BOOL CRuResourceManager_NULL::IsTextureWorkQueueEmpty()
{
	return TRUE;
}

BOOL CRuResourceManager_NULL::OutputResourceManifest()
{
	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearAnimationDictionaryCallback(const void *key, const void *data, void *userData)
{
	// Release animation
	(*((CRuAnimation **) data))->Release();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearAnimationDictionaryCallback_GR2(const void *key, const void *data, void *userData)
{
	// Release animation
	(*((CRuAnimation_GR2 **) data))->Release();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearEntityDictionaryCallback(const void *key, const void *data, void *userData)
{
	// Release object
	(*((IRuObject **) data))->Release();

	return TRUE;
}

BOOL CRuResourceManager_NULL::ClearGenericObjectDictionaryCallback(const void *key, void *data)
{
	IRuObject *objDesc = *reinterpret_cast<IRuObject **>(data);

	ruSAFE_RELEASE(objDesc);

	return TRUE;
}

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

#pragma managed
