#include "devicestatemanager.h"
#include "shadermanager.h"
#include "texturemanager.h"
#include "fontmanager.h"
#include "DXSwapChain.h"
#include "BufferManager.h"

VertexDeclaration::VertexDeclaration(DeviceStateManager* const device, const D3DVERTEXELEMENT9* decl)
{
	m_ElementCount = D3DXGetDeclLength(decl);

	if (m_ElementCount > 0)
	{
		m_pDeclElements = new D3DVERTEXELEMENT9[m_ElementCount + 1];
		memcpy(m_pDeclElements, decl, sizeof(D3DVERTEXELEMENT9) * (m_ElementCount + 1));
	}

	if(device)
	{
		device->GetDevice()->CreateVertexDeclaration(decl, &m_VDecl);
	}
	else
	{
		m_VDecl = NULL;
	}
}

VertexDeclaration::~VertexDeclaration()
{
	SAFERELEASE(m_VDecl);
	delete [] m_pDeclElements;
}

DeviceStateManager::DeviceStateManager(LPDIRECT3DDEVICE9 device, D3DApp*app)
{
	m_Device = device;
	
	m_App = app;

	m_Device->GetDeviceCaps(&m_Caps);

	m_ShaderManager = NULL;
	m_TextureManager = NULL;
	m_BufferManager = NULL;
	m_FontManager = NULL;
	m_pViewPort = NULL;

	m_ShaderManager = new ShaderManager(this);
	m_TextureManager = new TextureManager(this);
	m_BufferManager = new BufferManager(this);
	m_FontManager = new FontManager(this);
	m_pViewPort = new DXViewPort(this);

	Invalidate();
	Restore();
}

void DeviceStateManager::Invalidate(void)
{
	int i;

	//PPL Parameters
	m_VertexDeclaration = NULL;
	m_VertexShader = NULL;
	m_PixelShader = NULL;

	//StreamSources
	m_IndexBuffer = NULL;
	for(i=0;i<STREAMS;i++)
	{
		m_VertexStreams[i] = NULL;
		m_StartOffset[i] = 0;
		m_Stride[i] = 0;
	}

	ZeroMemory(m_Stages,sizeof(STStage)*SAMPLERSTAGES);

	//Flexible Vertex Format
	m_FVF = 0;

	//Material
	ZeroMemory(&m_Material,sizeof(D3DMATERIAL9)); //just set everything to zero

    //Transforms, all matrices have the identy matrix as default value
	D3DXMatrixIdentity((D3DXMATRIX*)&m_ViewMatrix);
	D3DXMatrixIdentity((D3DXMATRIX*)&m_ProjMatrix);
	D3DXMatrixIdentity((D3DXMATRIX*)&m_WorldMatrix);

	//Renderstates
	m_ZEnable = ZB_TRUE; //if no zbuffer D3DZB_FALSE
	m_Fillmode = FILL_SOLID;
	m_Shademode = SHADE_GOURAUD;
	m_ZWriteEnable = true;
	m_AlphaTestEnable = false;
	m_LastPixel = true;
	m_SrcBlend = BLEND_ONE;
	m_DestBlend = BLEND_ZERO;
	m_Cullmode = CULL_CCW;
	m_ZFunc = CMP_LESSEQUAL;
	m_AlphaRef = 0;
	m_AlphaFunc = CMP_ALWAYS;
	m_DitherEnable = false;
	m_AlphaBlendEnable = false;
	m_FogEnable = false;
	m_SpecularEnable = false;
	m_FogColor = 0;
	m_FogTablemode = D3DFOG_NONE;
	m_FogStart = 0.f;
	m_FogEnd = 1.f;
	m_FogDensity = 1.f;
    m_RangefogEnable = false;
	m_StencilEnable = false;
	m_StencilFail = D3DSTENCILOP_KEEP;
	m_StencilZFail = D3DSTENCILOP_KEEP;
	m_StencilPass = D3DSTENCILOP_KEEP;
	m_StencilFunc = CMP_ALWAYS;
	m_StencilRef = 0;
	m_StencilMask = 0xFFFFFFFF;
	m_StencilWritemask = 0xFFFFFFFF;

	m_TextureFactor = 0xFFFFFFFF;

	m_AmbientLight = 0;
	m_Lighting = true;
	m_Clipping = true;

	m_NormalizeNormals = false;
	m_Vertexblend = D3DVBF_DISABLE;

	m_ClipplaneEnable = 0;
	m_PointSize = -1.f; //we dont know the default value

	m_IndexedVertexblendEnable = false;
	m_ColorWriteEnable = 0xF;

	FOREACH(el, m_AddSwapChains, DXSwapChain)
	{
		el->GetInfo()->Invalidate();
	}

	if (m_FontManager)
		m_FontManager->Invalidate();

	if (m_TextureManager)
		m_TextureManager->Invalidate();

	if (m_ShaderManager)
		m_ShaderManager->Invalidate();

	if (m_BufferManager)
		m_BufferManager->Invalidate();
}


DXSwapChain* DeviceStateManager::CreateSwapChain(const STSelMode& mode, const int hwnd)
{
	DXSwapChain *c = new DXSwapChain(this, mode, (HWND)hwnd);
	m_AddSwapChains.AddTail(c, (DWORD)c);
	return c;
}

void DeviceStateManager::ReleaseSwapChain(DXSwapChain* sc)
{
	ListElement<DXSwapChain> *el = m_AddSwapChains.GetElement((DWORD)sc);
	if(el)
		el->Delete();
}

DeviceStateManager::~DeviceStateManager(void)
{
	m_AddSwapChains.Clear();

	delete m_pViewPort;
	delete m_FontManager;
	delete m_ShaderManager;
	delete m_TextureManager;
	delete m_BufferManager;

	wlog("Device Released");
}

void DeviceStateManager::Restore(void)
{
	D3DVIEWPORT9 VPDesc;

	m_Device->GetViewport(&VPDesc);

	if (m_pViewPort)
		m_pViewPort->SetRegion(VPDesc.X, VPDesc.Y, VPDesc.Width, VPDesc.Height, VPDesc.MinZ, VPDesc.MaxZ);

	if (m_BufferManager)
		m_BufferManager->Restore();

	if (m_FontManager)
		m_FontManager->Restore();

	if (m_TextureManager)
		m_TextureManager->Restore();

	if (m_ShaderManager)
		m_ShaderManager->Restore();

	FOREACH(el, m_AddSwapChains, DXSwapChain)
	{
		el->GetInfo()->Restore();
	}
}

/*void DeviceStateManager::Draw2DTexQuad(float xs,float ys,float xe,float ye)
{
	float vb[] = {xs,ys,0,0,1,  
				  xe,ys,0,1,1,
				  xs,ye,0,0,0,
				  xe,ye,0,1,0};

	D3DXMATRIX matid;
	D3DXMatrixIdentity(&matid);
	SetWorldMatrix(matid);
	SetViewMatrix(matid);
	SetProjMatrix(matid);
	SetCullmode(D3DCULL_NONE);
	SetZEnable(D3DZB_FALSE);
	SetLighting(false);
	SetFogEnable(false);
	SetZWriteEnable(false);
	SetAlphaBlendEnable(false);
	SetAlphaTestEnable(false);

	SetFVF(D3DFVF_XYZ|D3DFVF_TEX1);  

	DrawPrimitiveUP(PT_TRIANGLESTRIP,2,vb,sizeof(float)*6);
}

void DeviceStateManager::Draw2DTexSprite(float xcenter,float ycenter,float xl,float yl,float rotation)
{
	float avb[] = {-xl/2,-yl/2,0,1,1,  
				   xl/2,-yl/2,0,0,1,
				  -xl/2, yl/2,0,1,0,
				   xl/2, yl/2,0,0,0};

	D3DXMATRIX matrot;
	D3DXMatrixRotationZ(&matrot,rotation);
	D3DXMATRIX mattrans;
	D3DXMatrixTranslation(&mattrans,xcenter,ycenter,0);
	SetWorldMatrix(matrot * mattrans);

	D3DXMATRIX matid;
	D3DXMatrixIdentity(&matid);
	//SetViewMatrix(matid);
	//SetProjMatrix(matid);
	SetCullmode(D3DCULL_NONE);
	SetZEnable(D3DZB_FALSE);
	SetLighting(false);
	SetFogEnable(false);
	SetZWriteEnable(false);

	SetTexture(1,(DXTexture*)NULL);
	SetTexture(2,(DXTexture*)NULL);
	SetTexture(3,(DXTexture*)NULL);
	SetColorOperation(1, D3DTOP_DISABLE );
	SetAlphaOperation(1, D3DTOP_DISABLE );
	SetColorOperation(2, D3DTOP_DISABLE );
	SetAlphaOperation(2, D3DTOP_DISABLE );
	SetColorOperation(3, D3DTOP_DISABLE );
	SetAlphaOperation(3, D3DTOP_DISABLE );

	SetFVF(D3DFVF_XYZ|D3DFVF_TEX1);  

	DrawPrimitiveUP(PT_TRIANGLESTRIP,2,avb,sizeof(float)*5);
}*/