/*
 * jQuery swoosh
 * copyright 2009-2010 justin talbott - waymondo.com
 * released under the MIT and GPL licenses
 */

(function($){

  /*
   * jQuery Color Animations
   * Copyright 2007 John Resig
   * Released under the MIT and GPL licenses.
   *
   * RGBA support by Mehdi Kabab <http://pioupioum.fr>
   */

  jQuery.extend(jQuery.support, {
    "rgba": supportsRGBA()
  });

  // 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){
      var tuples = [];
      if ( !fx.colorInit ) {
        fx.start = getColor( fx.elem, attr );
        fx.end = getRGB( fx.end );
        if ( fx.start.length !== 4 ) {
          fx.start[3] = 1;
        }
        if ( fx.end.length !== 4 ) {
          fx.end[3] = 1;
        }
        fx.colorModel = jQuery.support.rgba ? 'rgba' : 'rgb';
        fx.colorInit = true;
      }

      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0) ); // R
      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0) ); // G
      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0) ); // B

      if ( fx.colorModel == 'rgba' ) { // Alpha
        tuples.push( Math.max(Math.min( parseFloat((fx.pos * (fx.end[3] - fx.start[3])) + fx.start[3]), 1), 0).toFixed(2) );
      }

      fx.elem.style[attr] = fx.colorModel + "(" + tuples.join(",") + ")";
      };
  });

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


  // Parse strings looking for color tuples [255,255,255[,1]]
  function getRGB(color) {
    var result, ret,
      ralpha = '(?:,\\s*((?:1|0)(?:\\.0+)?|(?:0?\\.[0-9]+))\\s*)?\\)',
      rrgbdecimal = new RegExp( 'rgb(a)?\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*' + ralpha ),
      rrgbpercent = new RegExp( 'rgb(a)?\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*' + ralpha );
    // Check if we're already dealing with an array of colors
    if ( color && color.constructor == Array && color.length >= 3 && color.length <= 4 ) {
      return color;
    }
    // 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 rgb[a](num,num,num[,num])
    if (result = rrgbdecimal.exec(color)) {
      ret = [parseInt(result[2]), parseInt(result[3]), parseInt(result[4])];
      // is rgba?
      if (result[1] && result[5]) {
        ret.push(parseFloat(result[5]));
      }
      return ret;
    }
    // Look for rgb[a](num%,num%,num%[,num])
    if (result = rrgbpercent.exec(color)) {
      ret = [parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55, parseFloat(result[4]) * 2.55];
      // is rgba?
      if (result[1] && result[5]) {
        ret.push(parseFloat(result[5]));
      }
      return ret;
    }
    // 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 supportsRGBA() {
    var s = jQuery('<div/>')[0].style;
    s.cssText = 'color:rgba(1,2,3,.5)';
    return s.color.indexOf( 'rgba' ) !== -1;
  };

  // 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: ( jQuery.support.rgba ) ? [0,0,0,0] : [255,255,255]
  };

  // shadow-izing added by justin talbott
  jQuery.each(['textShadow', 'boxShadow', 'MozBoxShadow', 'WebkitBoxShadow'], function(i, attr){
    jQuery.fx.step[attr] = function(fx){
      var tuples = [];
      var dimTuples = [];
      if ( !fx.colorInit ) {
        fx.start = getShadow( fx.elem, attr );
        fx.end = parseShadow( fx.end );
        if ( fx.start.length !== 7 ) {
          fx.start[6] = 1;
        }
        if ( fx.end.length !== 7 ) {
          fx.end[6] = 1;
        }
        fx.colorModel = jQuery.support.rgba ? 'rgba' : 'rgb';
        fx.colorInit = true;
      }

      dimTuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0) );
      dimTuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0) );
      dimTuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0) );

      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[3] - fx.start[3])) + fx.start[3]), 255), 0) ); // R
      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[4] - fx.start[4])) + fx.start[4]), 255), 0) ); // G
      tuples.push( Math.max(Math.min( parseInt( (fx.pos * (fx.end[5] - fx.start[5])) + fx.start[5]), 255), 0) ); // B

      if ( fx.colorModel == 'rgba' ) { // Alpha
        tuples.push( Math.max(Math.min( parseFloat((fx.pos * (fx.end[6] - fx.start[6])) + fx.start[6]), 1), 0).toFixed(2) );
      }
      fx.elem.style[attr] = fx.colorModel + "(" + tuples.join(",") + ") " + dimTuples.join("px ") + "px";
    };
  });

	function parseShadow(shadow) {
    var dimensions, color, r;
	  if (dimensions = /\s*([0-9]{1,3})px\s*([0-9]{1,3})px\s*([0-9]{1,3})px\s*/.exec(shadow)) {
	    if (color = getRGB(shadow)) {
        dimensions.shift();
        r = dimensions.concat(color);
        for (i in r) {
          r[i] = parseFloat(r[i]);
        }
		    return r;
		  };
	  };
	};

  function getShadow(elem, attr) {
    var shadow;
    do {
      shadow = jQuery.curCSS(elem, attr);
      // Keep going until we find an element that has a shadow, or we hit the body
      if ( shadow != '' && shadow != 'none' && shadow != 'transparent' || jQuery.nodeName(elem, "body") )
        break;

    } while ( elem = elem.parentNode );

    return parseShadow(shadow);
  }

$.fn.swoosh = function(options) {

	var settings = $.extend({}, $.fn.swoosh.settings, options),
    hover = $("<div id='"+settings.swooshID+"' style='display:none;'/>").appendTo("body");

	$(this).each(function(){
    var $o = $(this),
		props = [
		  'color',
		  'background-color',
		  'border-bottom-color',
		  'border-left-color',
		  'border-right-color',
		  'border-top-color',
		  'outline-color',
      'text-shadow',
      'box-shadow',
      '-moz-box-shadow',
      '-webkit-box-shadow'
		],
 		camelProps = [
		  'color',
		  'backgroundColor',
		  'borderBottomColor',
		  'borderLeftColor',
		  'borderRightColor',
		  'borderTopColor',
		  'outlineColor',
      'textShadow',
      'boxShadow',
      'MozBoxShadow',
      'WebkitBoxShadow'
		],
	  inStyles = {}, outStyles = {}, inColor, outColor, tst = document.createElement('tst');

	  $.each(props, function(i, p) {

		  inColor = hover.css(p),
        outColor = $o.css(p);

		  if (tst.style[camelProps[i]] !== undefined && inColor && inColor != '' && inColor != 'transparent' && inColor != 'none' && inColor != 'rgba\(0, 0, 0, 0\)') {
		    inStyles[camelProps[i]] = inColor;
		  }

		  if (tst.style[camelProps[i]] !== undefined && outColor && outColor != '' && outColor != 'transparent'  && outColor != 'none' && outColor != 'rgba\(0, 0, 0, 0\)') {
		    outStyles[camelProps[i]] = outColor;
		  }

	  });

	  $o.bind(settings.startEvent, function(){
      $(this).stop().animate(inStyles, {
		    queue: false,
		    duration: settings.speedIn,
		    easing: settings.easingIn
		  });
    }).bind(settings.endEvent, function(){
	    $(this).stop().animate(outStyles, {
		    queue: false,
		    duration: settings.speedOut,
		    easing: settings.easingOut
		  });
	  });

	});
	return this;
};

$.fn.swoosh.settings = {
	speedIn    : 64,
	speedOut   : 256,
	swooshID   : 'swoosh',
	easingIn   : 'swing',
	easingOut  : 'swing',
	startEvent : 'mouseover',
	endEvent   : 'mouseout'
};
})(jQuery);
