#include "mof/MaterialBuilder.hpp"
#include "mof/Material.hpp"
#include "mof/private/GraphicsDeviceImpl.hpp"
#include "mof/stream/Constant.hpp"

struct mof::MaterialBuilder::Impl{

	Impl(
		const mof::Manipulator<mof::Color4f>::Handler& ambient_ ,
		const mof::Manipulator<mof::Color4f>::Handler& diffuse_ ,
		const mof::Manipulator<mof::Color4f>::Handler& specular_ ,
		const mof::Manipulator<float>::Handler& specularPower_ ,
		const mof::Manipulator<mof::Color4f>::Handler& emissive_)
	: diffuse(diffuse_) , ambient(ambient_) , specular(specular_) ,
	specularPower(specularPower_) , emissive(emissive_) , pMaterial(NULL) , frame(0) {
	}

	~Impl(){
		delete pMaterial;
	}

	mof::Material* pMaterial;
	FrameNumber frame;
	mof::Manipulator<mof::Color4f>::Handler diffuse;
	mof::Manipulator<mof::Color4f>::Handler ambient;
	mof::Manipulator<mof::Color4f>::Handler specular;
	mof::Manipulator<float>::Handler specularPower;
	mof::Manipulator<mof::Color4f>::Handler emissive;

	
};



	
mof::MaterialBuilder::MaterialBuilder( )
: m_pImpl(new Impl( 
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ,
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ,
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ,
		  mof::makeConstantHandler(0.0f) , 
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) 
		  ) )
{
	m_pImpl->pMaterial = new Material;
}


mof::MaterialBuilder::MaterialBuilder( mof::Color4f ambient )
: m_pImpl(new Impl( 
		  mof::makeConstantHandler(ambient) ,
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ,
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ,
		  mof::makeConstantHandler(0.0f) , 
		  mof::makeConstantHandler(mof::Color4f(0 , 0 , 0)) ))
{
	m_pImpl->pMaterial = new Material;
	construct();
}


mof::MaterialBuilder::MaterialBuilder( mof::Color4f ambient , mof::Color4f diffuse , 
									   mof::Color4f specular , float power , mof::Color4f emissive )
: m_pImpl(new Impl(
		  mof::makeConstantHandler(ambient) ,
		  mof::makeConstantHandler(diffuse) ,
		  mof::makeConstantHandler(specular) ,
		  mof::makeConstantHandler(power) , 
		  mof::makeConstantHandler(emissive) ))
{
	m_pImpl->pMaterial = new Material;
	construct();
}

mof::MaterialBuilder::MaterialBuilder(const mof::Material& material)
: m_pImpl(new Impl(
		  mof::makeConstantHandler(material.ambientColor) ,
		  mof::makeConstantHandler(material.diffuseColor) ,
		  mof::makeConstantHandler(material.specularColor) ,
		  mof::makeConstantHandler(material.power) , 
		  mof::makeConstantHandler(material.emissiveColor) ))
{
	m_pImpl->pMaterial = new Material;
	construct();
}


mof::MaterialBuilder::MaterialBuilder(
			const mof::Manipulator<mof::Color4f>::Handler& ambient_ , 
			const mof::Manipulator<mof::Color4f>::Handler& diffuse_ ,
			const mof::Manipulator<mof::Color4f>::Handler& specular_ ,
			const mof::Manipulator<float>::Handler& power_ ,
			const mof::Manipulator<mof::Color4f>::Handler& emissive_ )
: m_pImpl(new Impl( ambient_ , diffuse_ , specular_ , power_ , emissive_ ))
{
	m_pImpl->pMaterial = new Material;
	construct();
}

mof::MaterialBuilder::~MaterialBuilder(){
}

void mof::MaterialBuilder::setFrameNumber(mof::FrameNumber frame){
	m_pImpl->frame = frame;
}

void mof::MaterialBuilder::nextFrame(){
	setFrameNumber(m_pImpl->frame + 1 );
}

void mof::MaterialBuilder::prevFrame(){
	if(m_pImpl->frame > 0)setFrameNumber(m_pImpl->frame - 1);
}



mof::Color4f mof::MaterialBuilder::getDiffuseColor() const{
	return m_pImpl->diffuse->value(m_pImpl->frame);
}

mof::Color4f mof::MaterialBuilder::getAmbientColor() const{
	return m_pImpl->ambient->value(m_pImpl->frame);
}

mof::Color4f mof::MaterialBuilder::getSpecularColor() const{
	return m_pImpl->specular->value(m_pImpl->frame);
}

mof::Color4f mof::MaterialBuilder::getEmissiveColor() const{
	return m_pImpl->emissive->value(m_pImpl->frame);
}

float mof::MaterialBuilder::getSpecularPower() const{
	return m_pImpl->specularPower->value(m_pImpl->frame);
}


const mof::Material& mof::MaterialBuilder::construct() const{
	
	m_pImpl->pMaterial->diffuseColor = m_pImpl->diffuse->value(m_pImpl->frame);
	m_pImpl->pMaterial->ambientColor = m_pImpl->ambient->value(m_pImpl->frame);
	m_pImpl->pMaterial->specularColor = m_pImpl->specular->value(m_pImpl->frame);
	m_pImpl->pMaterial->power = m_pImpl->specularPower->value(m_pImpl->frame);
	m_pImpl->pMaterial->emissiveColor = m_pImpl->emissive->value(m_pImpl->frame);

	return *(m_pImpl->pMaterial);
}
