(function($){
/*
 * jquery.citizenColor - Overwrite jQuery's animate function for color properties to add HSL colors support
 *
 * Copyright (c) 2008 lrbabe (/ɛlɛʁbab/ lrbabe.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 */
	
$.fn.extend({
	_animate: $.fn.animate,	
	animate: function(prop, speed, easing, callback){
		return this.each(function(i) {
			var $this = $(this);
			for(var p in prop) {
				// replace HSL color properties
				if(/[Cc]olor/.test(p) && /hsl/.test(prop[p])){
					// Look for hsl(num,num%,num%) as defined by w3c: http://www.w3.org/TR/css3-color/#hsl-color
					if (result = /hsl\(\s*([+-]=)?([0-9]{1,3})\s*,\s*([+-]=)?([0-9]{1,3})\%\s*,\s*([+-]=)?([0-9]{1,3})\%\s*\)/.exec(prop[p])) {
						// /!\ animate cannot be used on element with different colors /!\
						var currentRGB = getColor(this, p),
							currentRGBString = RGBtoString(currentRGB),
							dataRGBString = $this.data('rgb-'+p),
							// For a relative animation (using +=/-=), use cached HSL values if avalaible, when current rgb and cached rgb are equals.
							hsl = result[1] || result[3] || result[5]?
								(dataRGBString && currentRGBString == dataRGBString? $this.data('hsl-'+p) : RGBtoHSL(currentRGB)) :
								[0,0,0];
						// build hsl array of static values
						hsl = [
							(result[1]? hsl[0] : 0) + parseInt(result[2]) * (/-/.test(result[1])? -1 : 1),
							(result[3]? hsl[1] : 0) + parseInt(result[4]) * (/-/.test(result[3])? -1 : 1),
							(result[5]? hsl[2] : 0) + parseInt(result[6]) * (/-/.test(result[5])? -1 : 1)					
						];
						// Make sure values respect intervals
						hsl[0] %= 360;
						if(hsl[1] > 100) hsl[1] = 100;
						if(hsl[2] > 100) hsl[2] = 100;						
						// back to RGB !
						var rgb = HSLtoRGB(hsl);
						prop[p] = 'rgb('+rgb[0]+', '+rgb[1]+', '+rgb[2]+')';
						// cache result for performance and to avoid approximation
						$this.data('hsl-'+p, hsl);
						$this.data('rgb-'+p, RGBtoString(rgb));
					}			        
				}
			}
			// Use standard animate function and fire the callback only once.
			$this._animate(prop, speed, easing, i == 0? callback : false);
		});
	}
});

/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

// We override the animation for all of these color styles
jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i, attr){
    jQuery.fx.step[attr] = function(fx){
        if (fx.state == 0) {
            fx.start = getColor(fx.elem, attr);
            fx.end = getRGB(fx.end);
        }
        
        fx.elem.style[attr] = "rgb(" +
        [Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0), Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0), Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)].join(",") +
        ")";
    }
});

// Color Conversion functions from highlightFade
// By Blair Mitchelmore
// http://jquery.offput.ca/highlightFade/

// Parse strings looking for color tuples [255,255,255]
function getRGB(color){
    var result;
    
    // Check if we're already dealing with an array of colors
    if (color && color.constructor == Array && color.length == 3) 
        return color;
    
    // Look for rgb(num,num,num)
    if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) 
        return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];
    
    // Look for rgb(num%,num%,num%)
    if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) 
        return [parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55];
    
    // Look for #a0b1c2
    if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) 
        return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];
    
    // Look for #fff
    if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) 
        return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16)];
    
    // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
    if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) 
        return colors['transparent'];
    
    // Otherwise, we're most likely dealing with a named color
    return colors[jQuery.trim(color).toLowerCase()];
}

function getColor(elem, attr){
    var color;
    
    do {
        color = jQuery.curCSS(elem, attr);
        
        // Keep going until we find an element that has color, or we hit the body
        if (color != '' && color != 'transparent' || jQuery.nodeName(elem, "body")) 
            break;
        
        attr = "backgroundColor";
    }
    while (elem = elem.parentNode);
    
    return getRGB(color);
};

function HSLtoRGB(hsl){
	var h = hsl[0] /360,
		s = hsl[1] /100,
		l = hsl[2] /100,
		m2 = l <= .5? l * (s + 1) : l + s - l * s,
		m1 = l * 2 - m2;
	return [Math.round(hueToRGB(m1, m2, h+1/3) * 255), Math.round(hueToRGB(m1, m2, h) * 255), Math.round(hueToRGB(m1, m2, h-1/3) * 255)];
};

function hueToRGB(m1, m2, h){
	if (h < 0) h+=1;
	if (h > 1) h-=1;		
	if (h * 6 <1) return m1 + (m2 - m1) * h * 6;
	if (h * 2 <1) return m2;
	if (h * 3 <2) return m1 + (m2 - m1) * (2/3 - h) * 6;
	return m1;
};

function RGBtoHSL(rgb){
	var r = rgb[0] /255,
		g = rgb[1] /255,
		b = rgb[2] /255,
		max = Math.max(r, g, b),
		min = Math.min(r, g, b),
		delta = max-min,
		h = 0,
		l = (max+min)/2,
		s = delta == 0? 0 : (l < .5? delta/(max+min) : delta/(2 -max-min));
	if (s != 0)
		switch(max) {
			case r: h = (g-b)/delta; break;
			case g: h = 2 + (b-r)/delta; break;
			case b: h = 4 + (r-g)/delta; break;
		}
	return[h*60,s*100,l*100]
};

function RGBtoString(rgb) {
	return rgb[0]+'-'+rgb[1]+'-'+rgb[2];
}

// Some named colors to work with
// From Interface by Stefan Petre
// http://interface.eyecon.ro/

var colors = {
	aqua:[0,255,255],
	azure:[240,255,255],
	beige:[245,245,220],
	black:[0,0,0],
	blue:[0,0,255],
	brown:[165,42,42],
	cyan:[0,255,255],
	darkblue:[0,0,139],
	darkcyan:[0,139,139],
	darkgrey:[169,169,169],
	darkgreen:[0,100,0],
	darkkhaki:[189,183,107],
	darkmagenta:[139,0,139],
	darkolivegreen:[85,107,47],
	darkorange:[255,140,0],
	darkorchid:[153,50,204],
	darkred:[139,0,0],
	darksalmon:[233,150,122],
	darkviolet:[148,0,211],
	fuchsia:[255,0,255],
	gold:[255,215,0],
	green:[0,128,0],
	indigo:[75,0,130],
	khaki:[240,230,140],
	lightblue:[173,216,230],
	lightcyan:[224,255,255],
	lightgreen:[144,238,144],
	lightgrey:[211,211,211],
	lightpink:[255,182,193],
	lightyellow:[255,255,224],
	lime:[0,255,0],
	magenta:[255,0,255],
	maroon:[128,0,0],
	navy:[0,0,128],
	olive:[128,128,0],
	orange:[255,165,0],
	pink:[255,192,203],
	purple:[128,0,128],
	violet:[128,0,128],
	red:[255,0,0],
	silver:[192,192,192],
	white:[255,255,255],
	yellow:[255,255,0],
	transparent: [255,255,255]
};

})(jQuery);

