//------------------------------------------------------------------------------
// Lamp : Open source game middleware
// Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/** @file
 * 三要素キャラクタカラーヘッダ
 * @author Junpee
 */

#ifndef COLOR_3C_H_
#define COLOR_3C_H_

#include <Core/System/Math.h>

namespace Lamp{

class Color4c;
class Color3f;
class Color4f;

//------------------------------------------------------------------------------
/**
 * 三要素キャラクタカラー
 *
 * このクラスは継承しないで下さい。
 */
class Color3c{
public:
	//--------------------------------------------------------------------------
	// メンバ変数
	//--------------------------------------------------------------------------
	/// メンバ変数
	union{
		/// 各要素
		struct{
			/// 赤
			u_char r;
			/// 緑
			u_char g;
			/// 青
			u_char b;
		};

		/// 配列
		u_char array[3];
	};

	//--------------------------------------------------------------------------
	// 定数
	//--------------------------------------------------------------------------
	/// 白
	static const Color3c white;

	/// 灰色
	static const Color3c gray;

	/// 黒
	static const Color3c black;

	/// 赤
	static const Color3c red;

	/// 緑
	static const Color3c green;

	/// 青
	static const Color3c blue;

	/// 黄
	static const Color3c yellow;

	/// 青緑
	static const Color3c cyan;

	/// 赤紫
	static const Color3c magenta;

	//--------------------------------------------------------------------------
	// コンストラクタ
	//--------------------------------------------------------------------------
	/**
	 * コンストラクタ
	 *
	 * このコンストラクタは初期値の設定を行わないため値は不定です。
	 */
	Color3c(){}

	/**
	 * コンストラクタ
	 * @param sourceR 赤の初期値
	 * @param sourceG 緑の初期値
	 * @param sourceB 青の初期値
	 */
	inline Color3c(u_char sourceR, u_char sourceG, u_char sourceB) :
		r(sourceR), g(sourceG), b(sourceB){
	}

	/**
	 * コンストラクタ
	 * @param source 設定する色
	 */
	explicit Color3c(const Color4c& source);

	/**
	 * コンストラクタ
	 * @param source 設定する色
	 */
	explicit Color3c(const Color3f& source);

	/**
	 * コンストラクタ
	 * @param source 設定する色
	 */
	explicit Color3c(const Color4f& source);

	//--------------------------------------------------------------------------
	// 値の設定
	//--------------------------------------------------------------------------
	/**
	 * 値の設定
	 * @param sourceR 赤の設定値
	 * @param sourceG 緑の設定値
	 * @param sourceB 青の設定値
	 */
	inline void set(u_char sourceR, u_char sourceG, u_char sourceB){
		r = sourceR;
		g = sourceG;
		b = sourceB;
	}

	/**
	 * 四要素キャラクタカラーの設定
	 * @param source 設定する色
	 */
	void set(const Color4c& source);

	/**
	 * 三要素実数カラーの設定
	 * @param source 設定する色
	 */
	void set(const Color3f& source);

	/**
	 * 四要素実数カラーの設定
	 * @param source 設定する色
	 */
	void set(const Color4f& source);

	/**
	 * ARGBカラーの設定
	 * @param source
	 */
	void setARGB(u_int source){
		r = (u_char)((source & 0xff0000) >> 16);
		g = (u_char)((source & 0xff00) >> 8);
		b = (u_char)(source & 0xff);
	}

	//--------------------------------------------------------------------------
	// 値の取得
	//--------------------------------------------------------------------------
	/**
	 * ARGBカラーの取得
	 * @return ARGBカラー
	 */
	u_int getARGB() const{
		return (0xff000000 | ((u_int)r << 16) | ((u_int)g << 8) | ((u_int)b));
	}

	//--------------------------------------------------------------------------
	// 演算
	//--------------------------------------------------------------------------
	/**
	 * 加算
	 * @param addColor 加算する色
	 * @return 加算された色
	 */
	inline Color3c operator +(const Color3c& addColor) const{
		int addR = (int)r + addColor.r;
		if(addR > 255){ addR = 255; }
		int addG = (int)g + addColor.g;
		if(addG > 255){ addG = 255; }
		int addB = (int)b + addColor.b;
		if(addB > 255){ addB = 255; }
		return Color3c(addR, addG, addB);
	}

	/**
	 * 減算
	 * @param subColor 減算する色
	 * @return 減算された色
	 */
	inline Color3c operator -(const Color3c& subColor) const{
		int subR = (int)r - subColor.r;
		if(subR < 0){ subR = 0; }
		int subG = (int)g - subColor.g;
		if(subG < 0){ subG = 0; }
		int subB = (int)b - subColor.b;
		if(subB < 0){ subB = 0; }
		return Color3c(subR, subG, subB);
	}

	/**
	 * 乗算
	 * @param mulColor 乗算する色
	 * @return 乗算された色
	 */
	inline Color3c operator *(const Color3c& mulColor) const{
		int mulR = ((int)r * mulColor.r) / 255;
		int mulG = ((int)g * mulColor.g) / 255;
		int mulB = ((int)b * mulColor.b) / 255;
		return Color3c(mulR, mulG, mulB);
	}

	/**
	 * 乗算
	 * @param mulValue 乗算する値
	 * @return 乗算された色
	 */
	inline Color3c operator *(float mulValue) const{
		int mulR = (int)(r * mulValue);
		if(mulR > 255){
			mulR = 255;
		}else if(mulR < 0){
			mulR = 0;
		}
		int mulG = (int)(g * mulValue);
		if(mulG > 255){
			mulG = 255;
		} else if(mulG < 0){
			mulG = 0;
		}
		int mulB = (int)(b * mulValue);
		if(mulB > 255){
			mulB = 255;
		}else if(mulB < 0){
			mulB = 0;
		}
		return Color3c(mulR, mulG, mulB);
	}

	/**
	 * 乗算
	 * @param mulValue 乗算する値
	 * @param mulColor 乗算される色
	 * @return 乗算された色
	 */
	inline friend Color3c operator *(float mulValue, const Color3c& mulColor){
		int mulR = (int)(mulColor.r * mulValue);
		if(mulR > 255){
			mulR = 255;
		}else if(mulR < 0){
			mulR = 0;
		}
		int mulG = (int)(mulColor.g * mulValue);
		if(mulG > 255){
			mulG = 255;
		} else if(mulG < 0){
			mulG = 0;
		}
		int mulB = (int)(mulColor.b * mulValue);
		if(mulB > 255){
			mulB = 255;
		}else if(mulB < 0){
			mulB = 0;
		}
		return Color3c(mulR, mulG, mulB);
	}

	//--------------------------------------------------------------------------
	// 代入演算
	//--------------------------------------------------------------------------
	/**
	 * 代入加算
	 * @param addColor 加算する色
	 * @return 加算された色
	 */
	inline Color3c& operator +=(const Color3c& addColor){
		int addR = (int)r + addColor.r;
		if(addR > 255){ addR = 255; }
		int addG = (int)g + addColor.g;
		if(addG > 255){ addG = 255; }
		int addB = (int)b + addColor.b;
		if(addB > 255){ addB = 255; }
		set(addR, addG, addB);
		return (*this);
	}

	/**
	 * 代入減算
	 * @param subColor 減算する色
	 * @return 減算された色
	 */
	inline Color3c& operator -=(const Color3c& subColor){
		int subR = (int)r - subColor.r;
		if(subR < 0){ subR = 0; }
		int subG = (int)g - subColor.g;
		if(subG < 0){ subG = 0; }
		int subB = (int)b - subColor.b;
		if(subB < 0){ subB = 0; }
		set(subR, subG, subB);
		return (*this);
	}

	/**
	 * 代入乗算
	 * @param mulColor 乗算する色
	 * @return 乗算された色
	 */
	inline Color3c& operator *=(const Color3c& mulColor){
		int mulR = ((int)r * mulColor.r) / 255;
		int mulG = ((int)g * mulColor.g) / 255;
		int mulB = ((int)b * mulColor.b) / 255;
		set(mulR, mulG, mulB);
		return (*this);
	}

	/**
	 * 代入乗算
	 * @param mulValue 乗算する値
	 * @return 乗算された色
	 */
	inline Color3c& operator *=(float mulValue){
		int mulR = (int)(r * mulValue);
		if(mulR > 255){
			mulR = 255;
		}else if(mulR < 0){
			mulR = 0;
		}
		int mulG = (int)(g * mulValue);
		if(mulG > 255){
			mulG = 255;
		} else if(mulG < 0){
			mulG = 0;
		}
		int mulB = (int)(b * mulValue);
		if(mulB > 255){
			mulB = 255;
		}else if(mulB < 0){
			mulB = 0;
		}
		set(mulR, mulG, mulB);
		return (*this);
	}

	//--------------------------------------------------------------------------
	// 色演算
	//--------------------------------------------------------------------------
	/**
	 * 反対色
	 * @return 反転された色
	 */
	inline Color3c& negative(){
		set(255 - r, 255 - g, 255 - b);
		return (*this);
	}

	/**
	 * 色の線形補間
	 * @param source 開始色
	 * @param target 対象色
	 * @param alpha ブレンド係数
	 * @return 線形補間された色
	 */
	inline static Color3c lerp(
		const Color3c& source, const Color3c& target, float alpha){
		float beta = 1.f - alpha;
		Color3c result;
		result.r = (u_char)(source.r * beta + target.r * alpha);
		result.g = (u_char)(source.g * beta + target.g * alpha);
		result.b = (u_char)(source.b * beta + target.b * alpha);
		return result;
	}

	//--------------------------------------------------------------------------
	// 論理演算
	//--------------------------------------------------------------------------
	/**
	 * 同じ値かどうか
	 * @param target 比較するカラー
	 * @return 同じ値であればtrueを返す
	 */
	inline bool operator ==(const Color3c& target) const{
		return ((r == target.r) && (g == target.g) && (b == target.b));
	}

	/**
	 * 同じ値でないかどうか
	 * @param target 比較するカラー
	 * @return 同じ値でなければtrueを返す
	 */
	inline bool operator !=(const Color3c& target) const{
		return ((r != target.r) || (g != target.g) || (b != target.b));
	}

	//--------------------------------------------------------------------------
	// その他
	//--------------------------------------------------------------------------
	/**
	 * 文字列化
	 * @return ベクトルの文字列表記
	 */
	inline String toString() const{
		String returnString;
		returnString.format("( %d, %d, %d )", r, g, b);
		return returnString;
	}

	//--------------------------------------------------------------------------
private:

};

//------------------------------------------------------------------------------
} // End of namespace Lamp
#endif // End of COLOR_3C_H_
//------------------------------------------------------------------------------
