#include "mof/private/Mesh.hpp"
#include "mof/GraphicsDevice.hpp"
#include "mof/private/MeshDisposer.hpp"
#include "mof/stream/Constant.hpp"
#include "mof/ConsoleIO.hpp"
#include "mof/MaterialBuilder.hpp"

struct mof::Mesh::Impl{
	
	std::shared_ptr<mof::MeshDisposer> pMeshDisposer;
	unsigned long nMaterials;
	Material* materials; 
	std::shared_ptr<Texture>* textures;

	Impl(
		std::shared_ptr<mof::MeshDisposer> pMeshDisposer_ ,
		unsigned long nMaterials_ 
		) : 
		pMeshDisposer(pMeshDisposer_) , 
		nMaterials(nMaterials_) , materials(NULL) , textures(NULL)
		{}

	~Impl(){
		delete[] materials;
		delete[] textures;
		}
}; 

mof::Mesh::Mesh(
	std::shared_ptr<mof::MeshDisposer> pMeshDisposer ,
	unsigned long nMaterials ,
	const Material* materials , 
	const std::shared_ptr<Texture>* textures 
	) : m_pImpl(new Impl(pMeshDisposer , nMaterials )){

	m_pImpl->materials = new mof::Material[nMaterials];
	m_pImpl->textures = new std::shared_ptr<mof::Texture>[nMaterials];	

	for(unsigned long i = 0 ; i < nMaterials ; i++ ){
		m_pImpl->materials[i] = materials[i];
		m_pImpl->textures[i] = textures[i];
	}
}

mof::Mesh::~Mesh(){
}
	


void mof::Mesh::setTexture( 
		unsigned int num ,
		const std::shared_ptr<mof::Texture>& pTexture){

	if(num < m_pImpl->nMaterials)m_pImpl->textures[num] = pTexture;	

}

/*
void mof::Mesh::setMaterialBuilder( 
		unsigned int num ,
		const std::shared_ptr<mof::MaterialBuilder>& material_builder)
{
	if(num < m_pImpl->nMaterials) m_pImpl->materials[num] = material_builder;	
}
*/

void mof::Mesh::setVisible(bool visible)
{
	// TODO
}


void mof::Mesh::update(){
	world_transform_.update();
	m_colorStream.update();
}

void mof::Mesh::draw() const{
	

	for( DWORD i = 0;  i < m_pImpl->nMaterials ; i++ )
	{
		Material mat = m_pImpl->materials[i];
		mof::Color4f col = m_colorStream.value();
		mat.ambientColor = mat.ambientColor * col;
		mat.diffuseColor = mat.diffuseColor * col;
      	mof::GraphicsDevice::setMaterial(mat);	
		mof::GraphicsDevice::setTexture(m_pImpl->textures[i].get());
		mof::GraphicsDevice::setWorldTransform(world_transform_.value());

		HRESULT hr = m_pImpl->pMeshDisposer->pMesh->DrawSubset( i );
		if(FAILED(hr))throw std::runtime_error("Failed --- DrawSubset");
	}
}

