#include "mof/Color.hpp"
#include <d3dx9.h>
#include "mof/ConsoleIO.hpp"
#include "mof/tstring.hpp"


mof::Color4f::Color4f() : 
	alpha(0) , red(1) , green(1) , blue(1)
{
}

mof::Color4f::Color4f(float alpha_ , float red_ , float green_ , float blue_) : 
	alpha(alpha_) , red(red_) , green(green_) , blue(blue_)
{
}

mof::Color4f::Color4f( float red_ , float green_ , float blue_) : 	
	alpha(1) , red(red_) , green(green_) , blue(blue_)		
{
}

mof::Color4f::Color4f(mof::Color color) : 
	alpha(static_cast<float>(getAlpha(color)) / 255) ,
	red(static_cast<float>(getRed(color)) / 255) , 
	green(static_cast<float>(getGreen(color)) / 255) ,
	blue(static_cast<float>(getBlue(color)) / 255 )
{
}

mof::Color mof::Color4f::toColorCode() const{
	return createColor(
		static_cast<ColorChannel>(alpha * 255) ,
		static_cast<ColorChannel>(red * 255) ,
		static_cast<ColorChannel>(green * 255) ,
		static_cast<ColorChannel>(blue * 255) 
		);
}

mof::Color4f mof::Color4f::operator +(const mof::Color4f& rhs) const{
	return mof::Color4f(
		alpha + rhs.alpha , 
		red + rhs.red ,
		green + rhs.green ,
		blue + rhs.blue );
}

mof::Color4f mof::Color4f::operator -(const mof::Color4f& rhs) const{
	return mof::Color4f(
		alpha - rhs.alpha , 
		red - rhs.red ,
		green - rhs.green ,
		blue - rhs.blue );
}

mof::Color4f mof::Color4f::operator *(const Color4f& color ) const
{
	return mof::Color4f(color.alpha * alpha , color.red * red , color.green * green , color.blue * blue );
}

mof::Color4f mof::operator *(const Color4f& color , float f){
	return mof::Color4f(color.alpha * f , color.red * f , color.green * f , color.blue * f);
}
		
mof::Color4f mof::operator *(float f ,  const mof::Color4f & color){
	return mof::Color4f(color.alpha * f , color.red * f , color.green * f , color.blue * f);
}



unsigned char hex2Decimal(const TCHAR* code){
	unsigned char a = *code;
	if(a < '0')return 0;//error
	else if( a <= '9')return a - '0';
	else if( a < 'A')return 0;//error
	else if( a <=  'Z')return a - 'A'+10;
	else if( a < 'a')return 0;//error
	else if( a <= 'z')return a - 'a'+10;
	else return 0;//error
}

char decimal2hex(unsigned char n){
	if( n >= 16)return '-';//error
	return "0123456789abcdef"[n];
}

mof::Color mof::createColor(unsigned char r , unsigned char g , unsigned char b){
	return D3DCOLOR_XRGB(r , g , b);
}

mof::Color mof::createColor(unsigned char a , unsigned char r , unsigned char g , unsigned char b){
	return D3DCOLOR_ARGB(a , r , g , b);
}


mof::Color mof::createColor(const mof::tstring& code){
	const TCHAR* pBuffer = code.c_str();
	unsigned char a , r , g , b;
	if(code.size() == 8)a = ( hex2Decimal(pBuffer++) << 4 ) + hex2Decimal(pBuffer++);
	else if(code.size() != 6)return 0;//error
	else a = 0xff;
	r = (hex2Decimal(pBuffer++) << 4)  + hex2Decimal(pBuffer++);
	g = (hex2Decimal(pBuffer++) << 4)  + hex2Decimal(pBuffer++);
	b = (hex2Decimal(pBuffer++) << 4)  + hex2Decimal(pBuffer++);
	return createColor(a , r , g , b);
}

unsigned char mof::getAlpha(const mof::Color& color){
	return (unsigned char)((color >> 24) & 0xff);
}


unsigned char mof::getRed(const mof::Color& color){
	return (unsigned char)((color >> 16) & 0xff);
}

unsigned char mof::getGreen(const mof::Color& color){
	return (unsigned char)((color >> 8) & 0xff);
}


unsigned char mof::getBlue(const mof::Color& color){
	return (unsigned char)(color & 0xff);
}


mof::Color mof::blendColor( mof::Color a , mof::Color b , float rate ){
	return createColor(
		static_cast<unsigned char>(getAlpha(a) * rate + getAlpha(b) * (1 - rate)) , //alpha
		static_cast<unsigned char>(getRed(a) * rate + getRed(b) * (1 - rate)) , //red
		static_cast<unsigned char>(getGreen(a) * rate + getGreen(b) * (1 - rate)) , //green
		static_cast<unsigned char>(getBlue(a) * rate + getBlue(b) * (1 - rate)) ); //blue
}

mof::Color mof::inverseColor(mof::Color src){
	return createColor(
		255 - getAlpha(src)  , //alpha
		255 - getRed(src)  , //red
		255 - getGreen(src)  , //green
		255 - getBlue(src) ); //blue
}


mof::tstring mof::toColorCode(mof::Color color){
	mof::otstringstream os;
	unsigned char a = getAlpha(color);
	unsigned char r = getRed(color);
	unsigned char g = getGreen(color);
	unsigned char b = getBlue(color);
	os  << decimal2hex(a >> 4) << decimal2hex(a & 0x0f) 
		<< decimal2hex(r >> 4) << decimal2hex(r & 0x0f) 
		<< decimal2hex(g >> 4) << decimal2hex(g & 0x0f) 
		<< decimal2hex(b >> 4) << decimal2hex(b & 0x0f) ;
	return os.str();

}


std::ostream& mof::operator <<(std::ostream& os, const mof::Color4f& color) 
{
	mof::Color code = color.toColorCode();
	os 
		<< "(" 
		<< static_cast<int>(mof::getAlpha(code)) << ", "
		<< static_cast<int>(mof::getRed(code)) << ", "
		<< static_cast<int>(mof::getGreen(code)) << ", "
		<< static_cast<int>(mof::getBlue(code))
		<< ")";
	return os;
}
