/*
Script: Color.js
	Contains the Color class.

Authors:
	Michael Jackson <http://ajaxon.com/michael>, Valerio Proietti <http://mad4milk.net>

License:
	MIT-style license.
*/

/*
Class: Color
	Creates a new Color Object, which is an array with some color specific methods.
	
Arguments:
	color - the hex, the RGB array or the HSB array of the color to create. For HSB colors, you need to specify the second argument.
	type - a string representing the type of the color to create. needs to be specified if you intend to create the color with HSB values, or an array of HEX values. Can be 'rgb', 'hsb' or 'hex'.

Example:
	(start code)
	var black = new Color('#000');
	var purple = new Color([255,0,255]);
	// mix black with white and purple, each time at 10% of the new color
	var darkpurple = black.mix('#fff', purple, 10);
	$('myDiv').setStyle('background-color', darkpurple);
	(end)
*/

var Color = new Class({

	initialize: function(color, type){
		if (color.isColor) return color;
		color.isColor = true;
		type = type || (color.push) ? 'rgb' : 'hex';
		var rgb, hsb;
		switch(type){
			case 'rgb':
				rgb = color;
				hsb = rgb.rgbToHsb();
				break;
			case 'hsb':
				rgb = color.hsbToRgb();
				hsb = color;
				break;
			case 'hex':
				rgb = color.hexToRgb(true);
				hsb = rgb.rgbToHsb();
				break;
		}
		rgb.hsb = hsb;
		return Object.extend(rgb, Color.prototype);
	},
	
	/*
	Property: mix
		Mixes two or more colors with the Color.
		
	Arguments:
		color - a color to mix. you can use as arguments how many colors as you want to mix with the original one.
		alpha - if you use a number as the last argument, it will be threated as the amount of the color to mix.
	*/
	
	mix: function(){
		var colors = $A(arguments);
		var alpha = ($type(colors[colors.length-1]) == 'number') ? colors.pop() : 50;
		var rgb = this.copy();
		colors.each(function(color){
			color = new Color(color);
			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
		});
		return new Color(rgb, 'rgb');
	},
	
	/*
	Property: invert
		Inverts the Color.
	*/

	invert: function(){
		return new Color(this.map(function(value){
			return 255 - value;
		}), 'rgb');
	},
	
	/*
	Property: setHue
		Modifies the hue of the Color, and returns a new one.
		
	Arguments:
		value - the hue to set
	*/

	setHue: function(value){
		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
	},
	
	/*
	Property: setSaturation
		Changes the saturation of the Color, and returns a new one.
		
	Arguments:
		percent - the percentage of the saturation to set
	*/

	setSaturation: function(percent){
		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
	},
	
	/*
	Property: setBrightness
		Changes the brightness of the Color, and returns a new one.
		
	Arguments:
		percent - the percentage of the brightness to set
	*/

	setBrightness: function(percent){
		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
	}

});

/*
Function: $RGB
	Shortcut to create a new color, based on red, green, blue values.
*/

function $RGB(r, g, b){
	return new Color([r, g, b], 'rgb');
};

/*
Function: $HSB
	Shortcut to create a new color, based on hue, saturation, brightness values.
*/

function $HSB(h, s, b){
	return new Color([h, s, b], 'hsb');
};

/*
Class: Array
	A collection of The Array Object prototype methods.
*/

Array.extend({
	
	/*
	Property: rgbToHsb
		Converts a RGB array to an HSB array.

	Returns:
		the HSB array.
	*/
	
	rgbToHsb: function(){
		var red = this[0], green = this[1], blue = this[2];
		var hue, saturation, brightness;
		var max = Math.max(red, green, blue), min = Math.min(red, green, blue);
		var delta = max - min;
		brightness = max / 255;
		saturation = (max != 0) ? delta / max : 0;
		if (saturation == 0){
			hue = 0;
		} else {
			var rr = (max - red) / delta;
			var gr = (max - green) / delta;
			var br = (max - blue) / delta;
			if (red == max) hue = br - gr;
			else if (green == max) hue = 2 + rr - br;
			else hue = 4 + gr - rr;
			hue /= 6;
			if (hue < 0) hue++;
		}
		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
	},
	
	/*
	Property: hsbToRgb
		Converts an HSB array to an RGB array.

	Returns:
		the RGB array.
	*/
	
	hsbToRgb: function(){
		var red, green, blue;
		var hue = Math.round(this[0]), saturation = Math.round(this[1] / 100 * 255), brightness = Math.round(this[2] / 100 * 255);
		if (saturation == 0){
			red = green = blue = brightness;
		} else {
			var t1 = brightness;
			var t2 = (255 - saturation) * brightness / 255;
			var t3 = (t1 - t2) * (hue % 60) / 60;
			if (hue < 60) red = t1, green = t2 + t3, blue = t2;
			else if (hue < 120) red = t1 - t3, green = t1, blue = t2;
			else if (hue < 180) red = t2, green = t1, blue = t2 + t3;
			else if (hue < 240) red = t2, green = t1 - t3, blue = t1;
			else if (hue < 300) red = t2 + t3, green = t2, blue = t1;
			else if (hue < 360) red = t1, green = t2, blue = t1 - t3;
		}
		return [Math.round(red), Math.round(green), Math.round(blue)];
	}

});