#include "Model.h"

namespace Brainstem
{
	Model::Model(IDirect3DDevice9* device, ID3DXEffect* effect, const char* filename) 
	{
		Device = device;
		Effect = effect;
		Filename = filename;
		Mesh = NULL; 

		SetTechnique("Default");
		SetDefaultProperties();
	}

	bool Model::Init() 
	{
		LPD3DXMESH CreationMesh;
		LPD3DXBUFFER pMaterialBuffer; 
		DWORD MaterialCount = 0;

		HRESULT hr = D3DXLoadMeshFromX(Filename, D3DXMESH_MANAGED, Device, NULL, &pMaterialBuffer, NULL, &MaterialCount, &CreationMesh); 
	
		if (FAILED(hr)) 
		{
			WRITE_ERROR(this, "Failed to Load Model [" << Filename << "]");
			return false;
		}

		D3DXComputeNormals(CreationMesh, 0);
		D3DXComputeTangentFrame(CreationMesh, 0);

		Mesh = new IMesh(CreationMesh);

		Vertex* pVerts;
		CreationMesh->LockVertexBuffer(0,(LPVOID*)&pVerts);
		const int numVerts = CreationMesh->GetNumVertices();

		for (int i = 0; i < numVerts; i++) {

			Mesh->Bounds.Set(Vector3<float>(pVerts->Position.x, 
				pVerts->Position.y, 
				pVerts->Position.z));

			pVerts++;
		}

		CreationMesh->UnlockVertexBuffer();

		size_t found;
		TCHAR prevDir[MAX_PATH];

		GetCurrentDirectory(MAX_PATH, prevDir);

		TCHAR fullPath[4096];
		TCHAR** lppPart = {NULL};
		GetFullPathName(Filename, 4096, fullPath, lppPart);

		std::string mediaDir = fullPath;
		
		found = mediaDir.find_last_of("\\");
		mediaDir = mediaDir.substr(0,found);

		SetCurrentDirectory(mediaDir.c_str());

		D3DXMATERIAL* pMaterials = (D3DXMATERIAL*)pMaterialBuffer->GetBufferPointer();

		for (DWORD i = 0; i < MaterialCount; i++) 
		{
			Mesh->Materials.push_back(pMaterials[i].MatD3D);

			if(pMaterials[i].pTextureFilename != NULL)
			{
				char ext[8]; char temp[256];
				_splitpath(pMaterials[i].pTextureFilename, NULL, NULL, temp, ext);

				std::string normalFilename(temp);
				normalFilename.append("n");
				normalFilename.append(ext);

				Mesh->Textures.push_back(new Texture(Device, pMaterials[i].pTextureFilename));
				Mesh->NormalMaps.push_back(new Texture(Device, normalFilename.c_str()));
			}
			else 
			{
				Mesh->Textures.push_back(NULL);
				Mesh->NormalMaps.push_back(NULL);
			}
		}

		pMaterialBuffer->Release();
		SetCurrentDirectory(prevDir);

		return true;
	}

	void Model::ApplyTexture(ITexture* texture)
	{
		Mesh->Textures.clear();
		Mesh->Textures.push_back(texture);
	}
	
	ITexture* Model::GetTexture()
	{
		return NULL;
	}

	void Model::Update()
	{
		Matrix4<float> scale;
		Matrix4<float> trans;
		Matrix4<float> rot;

		scale.SetScale(Scale);
		trans.SetTranslation(Position);
		rot.SetRotationRadians(Rotation);

		World = trans * rot * scale;
	}

	void Model::Render(ICamera* camera)
	{
		float textureScaling[2] = { TextureScaling.X, TextureScaling.Y };
		Effect->SetValue("textureScale", textureScaling, sizeof(textureScaling));

		Mesh->Render(Effect);
	}

	void Model::Release() 
	{
		SAFE_RELEASE(Mesh);
	}
}