#include "texturemanager.h"
#include "devicestatemanager.h"

TextureManager::TextureManager(DeviceStateManager* const device) : m_Device(device)
{
	m_ManagedMemory = 0;
	m_DeviceMemory = 0;
	m_SystemMemory = 0;
}

TextureManager::~TextureManager(void)
{
	m_RenderSurfaces.Clear(); //rendertargets have textures, so they need to be deleted first
	m_Textures.Clear();
}

void TextureManager::MemoryAllocated(const unsigned bytes, const POOL pool)
{
	if (pool == POOL_MANAGED)
		m_ManagedMemory += bytes;
	else if (pool == POOL_DEFAULT)
		m_DeviceMemory += bytes;
	else if (pool == POOL_SYSTEMMEM)
		m_SystemMemory += bytes;
}

void TextureManager::MemoryReleased(const unsigned bytes, const POOL pool)
{
	if (pool == POOL_MANAGED)
		m_ManagedMemory -= bytes;
	else if (pool == POOL_DEFAULT)
		m_DeviceMemory -= bytes;
	else if (pool == POOL_SYSTEMMEM)
		m_SystemMemory -= bytes;
}

DXTexture* TextureManager::CreateTexture(const unsigned xl, const unsigned yl, const unsigned levels, const unsigned usage, const FORMAT format, const POOL pool)
{
	DXTexture *t = new DXTexture(this,xl,yl,levels,usage,format,pool);
	m_Textures.AddHead(t, (unsigned)t);
	return t;
}

DXTexture* TextureManager::CreateTexture(const XString& filename, const unsigned xl, const unsigned yl, const unsigned levels, const unsigned usage, const FORMAT format, const POOL pool)
{
	DXTexture *t;
	FOREACH(el, m_Textures, DXSurface)
	{
		if(el->GetInfo()->GetType() == DXST_TEXTURE)
		{
			t = (DXTexture*)el->GetInfo();
			if(t->GetFilename() == filename && t->GetFormat() == format && t->GetLevels() == levels && t->GetPool() == pool && t->GetUsage() == usage)
			{
				if((xl == D3DX_DEFAULT || xl == D3DX_DEFAULT_NONPOW2) && (yl == D3DX_DEFAULT || yl == D3DX_DEFAULT_NONPOW2) || t->GetXl() == xl && t->GetYl() == yl)
				{
					t->IncRefCount();
					return (DXTexture*)t;
				}
			}
		}
	}
	t = new DXTexture(this,filename,xl,yl,levels,usage,format,pool);
	m_Textures.AddHead(t, (unsigned)t);
	return t;
}

DXTexture* TextureManager::CreateTexture(const XString& filename, const FORMAT format, const POOL pool)
{
	return CreateTexture(filename,  D3DX_DEFAULT_NONPOW2,  D3DX_DEFAULT_NONPOW2, 0, 0, format, pool);
}

DXTexture* TextureManager::CreateTextureCopy(DXTexture* const tex, const POOL pool)
{
	DXTexture* const t = new DXTexture(this, tex, tex->GetXl(), tex->GetYl(), tex->GetLevels(), tex->GetUsage(), tex->GetFormat(), pool);
	m_Textures.AddHead(t,(unsigned)t);
	return t;
}

DXCubeTexture* TextureManager::CreateCubeTexture(const unsigned edgelength, const unsigned levels, const unsigned usage, const FORMAT format, const POOL pool)
{
	DXCubeTexture* const t = new DXCubeTexture(this, edgelength, levels, usage, format, pool);
	m_Textures.AddHead(t, (unsigned)t);
	return t;
}

DXCubeTexture* TextureManager::CreateCubeTexture(const XString& filename, const unsigned edgelength, const unsigned levels, const unsigned usage, const FORMAT format, const POOL pool)
{
	DXCubeTexture* t;
	FOREACH(el, m_Textures, DXSurface)
	{
		if(el->GetInfo()->GetType() == DXST_CUBETEXTURE)
		{
			t = (DXCubeTexture*)el->GetInfo();
			if(t->GetFilename() == filename && t->GetFormat() == format && t->GetLevels() == levels && t->GetPool() == pool && t->GetUsage() == usage)
			{
				if(edgelength == D3DX_DEFAULT || t->GetEdgeLength() == edgelength)
				{
					t->IncRefCount();
					return (DXCubeTexture*)t;
				}
			}
		}
	}

	t = new DXCubeTexture(this, filename, edgelength, levels, usage, format, pool);
	m_Textures.AddHead(t, (unsigned)t);
	return t;
}

DXCubeTexture* TextureManager::CreateCubeTexture(const XString& filename, const  FORMAT format, const POOL pool)
{
	return CreateCubeTexture(filename, D3DX_DEFAULT, 1, 0, format, pool);
}

OffscreenRenderTexture* TextureManager::CreateOffscreenRenderTexture(const unsigned xl, const unsigned yl, const FORMAT format, const bool autolock, const bool autorestore, const bool autoupdate)
{
	OffscreenRenderTexture* const rt = new OffscreenRenderTexture(this, xl, yl, format, autolock, autorestore, autoupdate);
	m_RenderSurfaces.AddTail(rt, (DWORD)rt);
	return rt;
}

DepthStencilBuffer* TextureManager::CreateDepthStencilBuffer(const unsigned xl, const unsigned yl, const FORMAT format)
{
	DepthStencilBuffer* const dsb = new DepthStencilBuffer(this, xl, yl, format);
	m_RenderSurfaces.AddTail(dsb, (DWORD)dsb);
	return dsb;
}

DepthStencilTexture* TextureManager::CreateDepthStencilTexture(const unsigned xl, const unsigned yl, const FORMAT format)
{
	DepthStencilTexture* const dst = new DepthStencilTexture(this, xl, yl, format);
	m_RenderSurfaces.AddTail(dst, (DWORD)dst);
	return dst;
}

RenderTexture* TextureManager::CreateRenderTexture(const unsigned xl, const unsigned yl, const FORMAT format)
{
	RenderTexture* const rt = new RenderTexture(this, xl, yl, format);
	m_RenderSurfaces.AddTail(rt, (DWORD)rt);
	return rt;
}

CubeRenderTexture* TextureManager::CreateCubeRenderTexture(const unsigned edgelength, const FORMAT format)
{
	CubeRenderTexture* const rt = new CubeRenderTexture(this, edgelength, format);
	m_RenderSurfaces.AddTail(rt, (DWORD)rt);
	return rt;
}

ViewPortRenderTexture* TextureManager::CreateViewPortRenderTexture(DXViewPort* const vp, const FORMAT format, const float scale)
{
	ViewPortRenderTexture* const rt = new ViewPortRenderTexture(this, vp, format, scale);
	m_RenderSurfaces.AddTail(rt, (DWORD)rt);
	return rt;
}

void TextureManager::Release(DXSurface* const t)
{
	ListElement<DXSurface> *el = m_Textures.GetElement((DWORD)t);
	if(el)
	{
		el->Unlink(); //info already deleted
		delete el;
		//el->Delete();
	}
}

void TextureManager::Release(RenderSurface* const rs)
{
	ListElement<RenderSurface> *el=m_RenderSurfaces.GetElement((DWORD)rs);
	if(el)
	{
		el->Delete();
	}
}

void TextureManager::Invalidate(void)
{
	FOREACH(el, m_Textures, DXSurface)
	{
		el->GetInfo()->Invalidate();
	}

	//surfaces are dxtextures and so already has been invalidated
	FOREACH(el, m_RenderSurfaces, RenderSurface)
	{
		el->GetInfo()->Invalidate();
	}	
}

void TextureManager::Restore(void)
{
	FOREACH(el, m_Textures, DXSurface)
	{
		el->GetInfo()->Restore();
	}

	FOREACH(el, m_RenderSurfaces, RenderSurface)
	{
		el->GetInfo()->Restore();
	}
}    

void TextureManager::PreLoad(void)
{
	FOREACH(el, m_Textures, DXSurface)
	{
		if (el->GetInfo()->GetSurface())
			el->GetInfo()->GetSurface()->PreLoad();
	}
}