// color.js

function Color() {

	this.red   = null;
	this.green = null;
	this.blue  = null;

	if (arguments.length == 1) {

		if (arguments[0].constructor == Object) {

			if (arguments[0].H !== undefined && arguments[0].S !== undefined && (arguments[0].B !== undefined || arguments[0].V !== undefined)) {

				var rgb = hsb2rgb(arguments[0].H, arguments[0].S, arguments[0].B || arguments[0].V);
				if (rgb !== undefined) {
					this.red   = rgb.red;
					this.green = rgb.green;
					this.blue  = rgb.blue;
				}

			}
			else if (arguments[0].R !== undefined && arguments[0].G !== undefined && arguments[0].B !== undefined) {

					this.red   = arguments[0].R;
					this.green = arguments[0].G;
					this.blue  = arguments[0].B;

			}
			else if (arguments[0].C !== undefined && arguments[0].M !== undefined && arguments[0].Y !== undefined) {

				var rgb = cmy2rgb(arguments[0].C, arguments[0].M, arguments[0].Y);
				if (rgb !== undefined) {
					this.red   = rgb.red;
					this.green = rgb.green;
					this.blue  = rgb.blue;
				}

			}

		} else if (arguments[0].constructor == String) {
			var cparts = (arguments[0].match(/#([0-9A-F]+)/i))
				? hex2rgb(arguments[0])
				: arguments[0].match(/rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/).slice(1);
			this.red   = parseInt(cparts[0]);
			this.green = parseInt(cparts[1]);
			this.blue  = parseInt(cparts[2]);
		}
	} else if ( arguments.length == 3 ) {
		this.red   = parseInt(arguments[0]);
		this.green = parseInt(arguments[1]);
		this.blue  = parseInt(arguments[2]);
	}
}

Color.prototype.rgb = function() {
	return 'rgb(' + this.red + ', ' + this.green + ', ' + this.blue + ')';
}
Color.prototype.hex = function() {
	return '#' + dec2hex(this.red,2) + dec2hex(this.green,2) + dec2hex(this.blue,2);
}
Color.prototype.hsb = function() {
	return rgb2hsb( this.red, this.blue, this.green )
}


Color.prototype.clone = function(){
	return new Color( this.red, this.green, this.blue );
}

Color.prototype.fade = function(pc) {
	pc = (parseInt(pc)) / 100;
	return new Color( this.red + (255-this.red)*pc, this.green + (255-this.green)*pc, this.blue + (255-this.blue)*pc );
}

Color.prototype.blend = function(destination,pc){
	//pc = (parseInt(pc)) / 100;
	if (destination.constructor.toString().substr(8,7) != ' Color(') {
		destination = new Color( destination );
	}
	//alert("Moving red to "+pc+" of " + this.red + " and " + destination.red + " = " + (((this.red   - destination.red  ) * pc) + destination.red));
	return new Color(
		((destination.red   - this.red  ) * pc) + this.red,
		((destination.green - this.green) * pc) + this.green,
		((destination.blue  - this.blue ) * pc) + this.blue
	);
}

Color.prototype.setHSB = function(H,S,B){
	rgb = hsb2rgb( H, S, B );
	this.red   = rgb.red;
	this.green = rgb.green;
	this.blue  = rgb.blue;
	return this;
}

Color.prototype.setSaturation = function(S){
	var hsb = rgb2hsb( this.red, this.green, this.blue );
	rgb = hsb2rgb( hsb.hue, S, hsb.brightness );
	this.red   = rgb.red;
	this.green = rgb.green;
	this.blue  = rgb.blue;
	return this;
}

Color.prototype.setHue = function(H){
	var hsb = rgb2hsb( this.red, this.green, this.blue );
	rgb = hsb2rgb( H, hsb.saturation, hsb.brightness );
	this.red   = rgb.red;
	this.green = rgb.green;
	this.blue  = rgb.blue;
	return this;
}

Color.prototype.setBrightness = function(B){
	var hsb = rgb2hsb( this.red, this.green, this.blue );
	rgb = hsb2rgb( hsb.hue, hsb.saturation, B );
	this.red   = rgb.red;
	this.green = rgb.green;
	this.blue  = rgb.blue;
	return this;
}



function hex2rgb(hex) {
	hex = hex.replace(/^#/,'');
	if (hex.length != 3 && hex.length != 6)
		return [0,0,0];
	var R = (hex.length == 3)
		? parseInt(hex.substr(0,1) + hex.substr(0,1), 16)
		: parseInt(hex.substr(0,2), 16);
	var G = (hex.length == 3)
		? parseInt(hex.substr(1,1) + hex.substr(1,1), 16)
		: parseInt(hex.substr(2,2), 16);
	var B = (hex.length == 3)
		? parseInt(hex.substr(2,1) + hex.substr(2,1), 16)
		: parseInt(hex.substr(4,2), 16);
	return new Array(R,G,B);
}

function dec2hex(dec,size){
	var rv = dec.toString(16);
	while(rv.length < size)
		rv = '0' + rv;
	return rv;
}


// The following two utility functions come from http://blog.elinc.ca/rod/files/rgbhsv/rgbhsv.js

function hsb2rgb(H, S, V) {
	H = H % 360;
	if (S < 0) {
		S = 0;
	}
	if (S > 100) {
		S = 100;
	}
	S /= 100;
	if (V < 0) {
		V = 0;
	}
	if (V > 100) {
		V = 100;
	}
	V /= 100;
	if (S == 0) {
		R = V;
		G = V;
		B = V;
	} else {
		if (H == 360) {
			hTemp = 0;
		} else {
			hTemp = H;
		}
		hTemp = hTemp / 60;
		fi = Math.floor(hTemp);
		fr = hTemp - fi;
		p = V * (1 - S);
		q = V * (1 - (S * fr));
		t = V * (1 - (S * (1 - fr)));
		if (fi == 0) {
			R = V;
			G = t;
			B = p;
		} else if (fi == 1) {
			R = q;
			G = V;
			B = p;
		} else if (fi == 2) {
			R = p;
			G = V;
			B = t;
		} else if (fi == 3) {
			R = p;
			G = q;
			B = V;
		} else if (fi == 4) {
			R = t;
			G = p;
			B = V;
		} else {
			R = V;
			G = p;
			B = q;
		}
	}
//	alert({red:R, green:G, blue:B}.toSource());
	return {red:Math.floor(R*255), green:Math.floor(B*255), blue:Math.floor(G*255)};
}


function rgb2hsb(R,G,B) {
	minVal=Math.min(Math.min(R, G), B);
	V=Math.max(Math.max(R, G), B);
	Delta=V-minVal;

	// Calculate saturation: saturation is 0 if r, g and b are all 0
	if (V == 0.0){
		S = 0.0;
	} else {
		S = Delta / V;
	}
	if (S == 0.0){
		H = 0.0;    // Achromatic: When s = 0, h is undefined but who cares
	} else {       // Chromatic
		if (R == V){ // between yellow and magenta [degrees]
			H = 60.0*(G-B)/Delta;
		} else {
			if (G == V){ // between cyan and yellow
				H = 120.0+60.0*(B-R)/Delta;
			} else { // between magenta and cyan
				H = 240.0+60.0*(R-G)/Delta;
			}
		}
	}
	if (H<0.0) H=H+360.0;
	return {hue: Math.floor(H), saturation: Math.floor(S*100), brightness: Math.floor(V/2.55)};
}

function rgb2cmy(R,G,B) {
	return { cyan: Math.abs ( Math.ceil ( R / 256 * 100 ) - 100), magenta: Math.abs ( Math.ceil ( G / 256 * 100 ) - 100), yellow: Math.abs ( Math.ceil ( B / 256 * 100 ) - 100) }
}

function cmy2rgb( C, M, Y ) {
	return { red: (100 - C) * 2.56, green: (100 - M) * 2.56, blue: (100 - Y) * 2.56 }
}





















