/**
 *	Color library
 */

#Const Version		"2014-10-13"
#Const ScriptName	"Color.Script.txt"

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib

// ---------------------------------- //
// Settings
// ---------------------------------- //


// ---------------------------------- //
// Globales
// ---------------------------------- //
#Const C_GoldenRatioInverse 0.618033988749895

declare Real[Text] G_ColorHue;	///< Last generated hue for clan color

// ---------------------------------- //
// Functions
// ---------------------------------- //

// ---------------------------------- //
/** Return the version number of the script
 *
 *	@return		The version number of the script
 */
Text GetScriptVersion() {
	return Version;
}

// ---------------------------------- //
/** Return the name of the script
 *
 *	@return		The name of the script
 */
Text GetScriptName() {
	return ScriptName;
}

// ---------------------------------- //
/// Unload the library
Void Unload() {
	G_ColorHue.clear();
}

// ---------------------------------- //
/// Load the library
Void Load() {
	Unload();
	G_ColorHue["LibColor_DefaultSet"] = MathLib::Rand(0., 1.);
}

// ---------------------------------- //
/** Convert a HSV color to a RGB color
 *
 *	@param	_HSV	The HSV values [0.-1.[
 *
 *	@return		The RGB values [0.-1.[
 */
Vec3 HsvToRgb(Vec3 _HSV) {
	declare RGB = <0., 0., 0.>;
	declare H = _HSV.X;
	declare S = _HSV.Y;
	declare V = _HSV.Z;
	
	declare Hi = MathLib::FloorInteger(H * 6.);
	declare F = (H * 6.) - Hi;
	declare P = V * (1. - S);
	declare Q = V * (1. - (F * S));
	declare T = V * (1. - ((1. - F) * S));
	
	switch(Hi) {
		case 0: RGB = <V, T, P>;
		case 1: RGB = <Q, V, P>;
		case 2: RGB = <P, V, T>;
		case 3: RGB = <P, Q, V>;
		case 4: RGB = <T, P, V>;
		default: RGB = <V, P, Q>;
	}
	
	return RGB;
}

// ---------------------------------- //
/** Convert a RGB color to a HSV color
 *
 *	@param	_RGB	The RGB values [0.-1.[
 *
 *	@return		The HSV values [0.-1.[
 */
Vec3 RgbToHsv(Vec3 _RGB) {
	declare Real R = _RGB.X;
	declare Real G = _RGB.Y;
	declare Real B = _RGB.Z;
	
	if(R < 0.) R = 0.;
	if(G < 0.) G = 0.;
	if(B < 0.) B = 0.;
	if(R > 1.) R = 1.;
	if(G > 1.) G = 1.;
	if(B > 1.) B = 1.;
	
	declare Real CMax = R;
	if(G > R && G > B) CMax = G;
	if(B > R && B > G) CMax = B;
	
	declare Real CMin = R;
	if(G <= R && G <= B) CMin = G;
	if(B <= R && B <= G) CMin = B;
	
	declare Real Delta = CMax - CMin;
	declare Real H = 0.;
	if(Delta > 0.) {
		if(CMax == R) {
			if(G > B) 	H = 		1./6 * (G - B) /Delta;
			else 		H = 1 - 	(1./6 * (B - G) /Delta);
		} else if(CMax == G) {
			if(B > R)	H = 2./6. + (1./6. * (B - R))/Delta;
			else		H = 2./6. - (1./6. * (R - B))/Delta;
		} else {
			if(R > G)	H = 4./6. + (1./6. * (R - G))/Delta;
			else		H = 4./6. - (1./6. * (G - R))/Delta;
		}
	}
	
	declare Real S = 0.;
	if(CMax > 0.) S = Delta / CMax;
	
	declare V = CMax;
	return <H, S, V>;
}

// ---------------------------------- //
/** Convert a value betwwen 0 and 15 to an hexadecimal value 
 *
 *	@param	_Dec	A decimal value [0 - 15]
 *
 *	@return		An hexadecimal value [0-F]
 */
Text DecToHex(Integer _Dec) {
	declare Hex = "F";
	
	if (_Dec >= 0 && _Dec <= 9) Hex = TextLib::ToText(_Dec);
	else {
		switch (_Dec) {
			case 10: Hex = "A";
			case 11: Hex = "B";
			case 12: Hex = "C";
			case 13: Hex = "D";
			case 14: Hex = "E";
			case 15: Hex = "F";
			default: Hex = "F";
		}
	}
	
	return Hex;
}

// ---------------------------------- //
/** Convert a RGB color to a Hexadecimal RGB code
 *
 *	@param	_RGB	The RGB color [0., 1.[
 *
 *	@return		The RGB hexadecimal code
 */
Text RgbToHex(Vec3 _RGB) {
	declare Hex = "000";
	declare Ri = MathLib::NearestInteger(_RGB.X * 15.);
	declare Gi = MathLib::NearestInteger(_RGB.Y * 15.);
	declare Bi = MathLib::NearestInteger(_RGB.Z * 15.);
	declare R = DecToHex(Ri);
	declare G = DecToHex(Gi);
	declare B = DecToHex(Bi);
	
	Hex = R^G^B;
	
	return Hex;
}

// ---------------------------------- //
/** Convert a RGB color to a Hexadecimal RGB code
 *
 *	@param	_RGB	The RGB color [0., 1.[
 *
 *	@return		The RGB hexadecimal code
 */
Text RgbToHex_New(Vec3 _RGB) {
	return TextLib::ColorToText(_RGB);
}

// ---------------------------------- //
/** Convert a HSV color to a Hexadecimal RGB code
 *
 *	@param	_HSV	The HSV color [0., 1.[
 *
 *	@return		The RGB hexadecimal code
 */
Text HsvToHex(Vec3 _HSV) {
	return RgbToHex(HsvToRgb(_HSV));
}

// ---------------------------------- //
/** Convert an Hexadecimal RGB color to an RGB code
 *
 *	@param	_Hex	The RGB hexadecimal code
 *
 *	@return		The RGB color [0., 1.[
 */
Vec3 HexToRgb(Text _Hex) {
	return TextLib::ToColor(_Hex);
}

// ---------------------------------- //
/** Convert an Hexadecimal RGB color to an HSV code
 *
 *	@param	_Hex	The RGB hexadecimal code
 *
 *	@return		The HSV color [0., 1.[
 */
Vec3 HexToHsv(Text _Hex) {
	return RgbToHsv(HexToRgb(_Hex));
}

// ---------------------------------- //
/** Create a new color set
 *
 *	@param	_SetName	The name of the new set
 */
Void CreateSet(Text _SetName) {
	G_ColorHue[_SetName] = MathLib::Rand(0., 1.);
}

// ---------------------------------- //
/** Destroy a color set
 *
 *	@param	_SetName	The name of the set
 */
Void DestroySet(Text _SetName) {
	declare Removed = G_ColorHue.removekey(_SetName);
}

// ---------------------------------- //
/** Darken an HSV color
 *
 *	@param	_Color	The HSV color to darken
 *	@param	_Power	The power of the darkening, from 0. to 1.
 *
 *	@return			The darkened HSV color
 */
Vec3 Darken(Vec3 _Color, Real _Power) {
	declare NewColor = _Color;
	NewColor.Z -= _Power;
	return NewColor;
}

// ---------------------------------- //
/** Generate a new color
 *	The generated colors are evenly distributed
 *
 *	@param	_Set	The set to use
 *
 *	@return		A RGB color
 */
Vec3 GetNewColor(Text _Set) {
	if (!G_ColorHue.existskey(_Set)) CreateSet(_Set);
	
	declare RGB = <0., 0., 0.>;
	
	G_ColorHue[_Set] += C_GoldenRatioInverse;
	G_ColorHue[_Set] = G_ColorHue[_Set] - (MathLib::FloorInteger(G_ColorHue[_Set])); ///< G_ColorHue %= 1;
	declare ColorSaturation = MathLib::Rand(0.6, 0.8);
	declare ColorValue = 0.8;
	RGB = HsvToRgb(<G_ColorHue[_Set], ColorSaturation, ColorValue>);
	
	return RGB;
}

// ---------------------------------- //
/** Generate a new color in a specific range [0..1[
 *	The generated colors are evenly distributed
 *
 *	@param	_Set		The set to use
 *	@param	_RangeMin	The start of the range
 *	@param	_RangeMax	The end of the range
 *
 *	@return		A RGB color
 */
Vec3 GetNewColor(Text _Set, Real _RangeMin, Real _RangeMax) {
	if (!G_ColorHue.existskey(_Set)) CreateSet(_Set);
	
	declare RGB = <0., 0., 0.>;
	declare Range = _RangeMax - _RangeMin;
	if (Range < 0) Range = 0.;
	
	G_ColorHue[_Set] += C_GoldenRatioInverse;
	G_ColorHue[_Set] = G_ColorHue[_Set] - (MathLib::FloorInteger(G_ColorHue[_Set])); ///< G_ColorHue %= 1;
	declare ColorHue = _RangeMin + (G_ColorHue[_Set] * Range);
	declare ColorSaturation = MathLib::Rand(0.6, 0.8);
	declare ColorValue = 0.8;
	
	RGB = HsvToRgb(<ColorHue, ColorSaturation, ColorValue>);
	
	return RGB;
}

// ---------------------------------- //
/// Get a new color in the default set
Vec3 GetNewColor() {
	return GetNewColor("LibColor_DefaultSet");
}

