/**
 * $().colorFlash() jQuery Extension
 * @version 0.9.2 (2008/06/25)
 * 
 * - Flashes a color for a specified parameter, repeating a specified number of times.
 * - Can be a smooth transition or rigid.
 * - Color values may be provided in 'rgb(r,g,b)', 'rgb(r%,g%,b%)', '#rrggbb', or '#rgb'
 * 
 * Syntax: jQuery(element).colorFlash( [{ param: value, param: value, ...}] );
 * 
 * @example
 * $("elements").colorFlash();
 *
 * @example
 * $(element).colorFlash({ smooth: true, speed: "fast", property: "borderColor", color: "#efb3cb" });
 * 
 * Currently Known Issues:
 * - Elements with different starting colors for the set property will end up with the same color when called together
 * - Internet Explorer has some issues.
 */
(function($) {
	
	$.fn.colorFlash = function(prm) {
		//var options = $.extend({},prm);
		
		//return this.each(function() {
		
			var $this = $(this);
			
			var params = $this.params = $.extend({
				// Defaults 						/* User-Definable parameters */
				smooth:			true,				// use smooth color transition (true or false) *not working
				speed:			"fast",				// milliseconds, or "fast" (100), "normal" (250), "slow" (500)
				repeat:			3,					// how many times to flash
				color:			"#ffa0a0",			// color to change [property] to
				property:		"backgroundColor"	// CSS property to change
			},prm,{
				// Internal
				iteration:		0,
				lastIteration:	-1,
				sleepTime:		50,
				count:			0,
				countRGB:		[0,0,0]
			});
			
			// Speed parameter - string alias values
			var speedOptions = { slow: 500, normal: 250, fast: 100 };
			var nanspd = isNaN(parseInt(params.speed));
			if(!speedOptions[params.speed] && nanspd) {
				params.speed = 250;
			}
			else if(nanspd) {
				params.speed = speedOptions[params.speed];
			}
			
			// Find the initial (default) color
			params.defColor = $this.css(params.property);
			if(params.defColor == "" || params.defColor == undefined) {
				params.defColor = "rgb(255,255,255)";
			}
			
			// set/convert rgb values
			params.colorRGB = parseRGB(params.color);
			params.defRGB = parseRGB(params.defColor);
			
			// difference between each value
			params.diffRGB = [
				Math.abs(params.colorRGB[0] - params.defRGB[0]),
				Math.abs(params.colorRGB[1] - params.defRGB[1]),
				Math.abs(params.colorRGB[2] - params.defRGB[2])
			];
			
			// total difference between the two colors
			params.step = params.diff = Math.abs(intColor(params.defRGB) - intColor(params.colorRGB));
			
			// Set step size
			if(params.smooth) {
				params.step = Math.floor(params.diff / (Math.round(params.speed / params.sleepTime))); // how big of a step per cycle
			}
			else {
				params.sleepTime = params.speed;
			}
			
			var cycleSize = Math.round(params.speed / params.sleepTime);
			params.stepRGB = [
				Math.floor(params.diffRGB[0] / cycleSize),
				Math.floor(params.diffRGB[1] / cycleSize),
				Math.floor(params.diffRGB[2] / cycleSize)
			];
			
			params.repeat *= 2;						// one iteration is 2 cycles
			params.dc = intColor(params.defRGB);	// integer representation of defColor
			params.c = intColor(params.colorRGB);	// integer representation of color
			
			$this.params = params; // make sure $this contains parameters
			
			params.interval = window.setInterval(function() {
				$this = $.fn.colorFlash.cycle($this);
				$this.css(params.property,$this.cssVal);
			},params.sleepTime);
			
			return $this;
			//$.fn.colorFlash.cycle($this);
		//});
	};
	
	$.fn.colorFlash.cycle = function($this,params) {
		var params = $this.params = $.extend({},$this.params,params); // slight overkill, perhaps.
		if(params.lastIteration != params.iteration) {
			var p = [["colorRGB","defRGB","c","dc"],["defRGB","colorRGB","dc","c"]];
			var it = params.iteration % 2;
			params.target = params[p[it][0]];
			params.start = params[p[it][1]];
			params.direction = ( (params[p[it][2]] - params[p[it][3]]) < 0) ? -1 : 1;
			params.lastIteration = params.iteration;
		}
		
		if(params.iteration < params.repeat) {
			var clrRGB = [];
			var clr = '';
			params.count += params.step;
			
			for(a in params.countRGB) {
				clrRGB[a] = params.start[a] + (params.countRGB[a] += params.stepRGB[a] * params.direction);
			}
			
			if(params.count >= params.diff) {
				params.count = 0;
				params.countRGB = [0,0,0];
				params.iteration++;
				$this.cssVal = "rgb("+params.target.join()+")";
			}
			else $this.cssVal = "rgb("+clrRGB.join()+")";
		}
		else {
			params.iteration = 0;
			$this.cssVal = params.defColor;
			window.clearInterval($this.params.interval);
		}
		$this.params = params;
		return $this;
	};
	
	// self explanatory...
	function intColor(value) {
		return value[0] + value[1] + value[2];
	};
	
	// returns [r,g,b] from '#rrggbb','#rgb', 'rgb(r,g,b)', or 'rgb(r%,g%,b%)'
	function parseRGB(value) {
		if(value.match("#")) {
			value = value.replace("#","");
			if(value.length == 3) value.replace(/(.)(.)(.)/,"$1$1$2$2$3$3");
			value = [parseInt(value.substr(0,2),16),parseInt(value.substr(2,2),16),parseInt(value.substr(4,2),16)];
		}
		else if(value.match("rgb")) {
			newvalue = value.replace(/(rgb\()((.?)+)(\))/,'$2').replace("%","").split(',');
			if(value.match("%")) {
				for(a in newvalue) newvalue[a] = Math.round(255 * ( newvalue[a] / 100 ));
			}
			else for(a in newvalue) newvalue[a] = parseInt(newvalue[a]);
			value = newvalue;
		}
		else {
			value = [0,0,0];
		}
		return value;
	};

})(jQuery);