(function ($) {
	var xFadeIndex = 0;

    $.fn.crossfade = function (params) {
		var defaults = {
			'url' : {},
			'type' : 'timer',
			'delay' : 1000,
			'callback' : null,
			'interval' : 3000,
			'transition' : 'crossfade'
        };
        
        var settings = {};
        settings = $.extend({}, defaults, params);
		
        // return this;
        return this.each(function (i) {
            var $$ = $(this)
				.attr('src', settings.url[0]);
				
            var hiddenImage = $$.wrap('<span />')
                .parent()
                .prepend('<img>')
                .find(':first-child')
				.css ('opacity', '0')
                .attr('src', settings.url[1]);
			
			// Apply relative positioning to the wrapper div by default
			if (!$$.css ('position') || $$.css ('position') == 'static')
				hiddenImage.parent ().css ('position', 'relative');
			else
				hiddenImage.parent ().css ('position', $$.css ('position'));
			
			// Copy any positioning css
			if ($$.css ('left')) hiddenImage.parent ().css ('left', $$.css ('left'));
			if ($$.css ('top')) hiddenImage.parent ().css ('top', $$.css ('top'));
                
            // CSS tweaks to position the starting image correctly
            if ($.browser.msie || $.browser.mozilla) {
                $$.css({
                    'position' : 'absolute', 
                    'left' : 0,
                    'background' : '',
                    'top' : '0'
                });
            } else if ($.browser.opera && $.browser.version < 9.5) {
                // opera < 9.5 has a render bug - so this is required to get around it
                // we can't apply the 'top' : 0 separately because Mozilla strips
                // the style set originally somehow...
                $$.css({
                    'position' : 'absolute', 
                    'left' : 0,
                    'background' : '',
                    'top' : "0"
                });
            } else {
                $$.css({
                    'position' : 'absolute', 
                    'left' : 0,
					'top' : 0,
                    'background' : ''
                });
            }

			var $$ = $(this);
			
			var doTransition = function () {
				// Calculate the correct image index to be shown next
				xFadeIndex++;
				if (xFadeIndex >= settings.url.length) { xFadeIndex = 0; }
				var i = xFadeIndex;
				
				switch (settings.transition) {
					case 'fade':
						if ($$.css ('opacity') != '0') {
							$$.prev ().attr('src', settings.url[i]);
							$$.stop().animate({
								opacity: 0
							}, settings.delay);
						} else {
							$$.attr('src', settings.url[i]);
							$$.stop().animate({
								opacity: 1
							}, settings.delay);
						}
						break;
						
					case 'crossfade':
						if ($$.css ('opacity') != '0') {
							$$.prev ().attr('src', settings.url[i]);
							$$.stop().animate({
								opacity: 0
							}, settings.delay);
							$$.prev ().stop ().animate ({
								opacity: 1
							}, settings.delay);
						} else {
							$$.attr('src', settings.url[i]);
							$$.stop().animate({
								opacity: 1
							}, settings.delay);
							$$.prev ().stop ().animate ({
								opacity: 0
							}, settings.delay);
						}
						break;
				}
			};
			
			if (!settings.type || settings.type == 'timer') {	
				var timer = setInterval (
					function () { doTransition (); }, 
					settings.interval
				);
			} else {
				$$.bind(settings.type, function () {					
					doTransition ();
				});
			}
        });
    };
    
})(jQuery);
