(function($){

/*! 
 * jquery Step Fader plugin				
 * Turns an element into a sort of carosel, with a left and right arrow to step through child elements with a fade transition.
 * by Tim Kinnane www.owlandfox.com
 * v0.1 (June 2011)
 * Requires jQuery v1.4 or later
 * Settings:
 * stepNext - the left arrow element (required)*
 * stepPrev - the right arrow element (required)*
 * stepCount - the number of children to show (required)
 * fadeSpeed - the transition speed (default 'fast')
 * stepOffset - for not starting at the start (default 0)
 * stepSpeed - milisecond distance between steps
 * fadeOutSpeed - speed of fade out transition
 * fadeInSpeed - speed of fade in transition
 * equalHeights - if true, will match the child element heights
 * *Elements must be given as jQuery objects (not IDs)
 */	
	$.fn.stepFader = function( options ) {
		var settings = {
			stepCount : 5,
			fadeSpeed : 'fast',
			stepOffset : 0,
			stepSpeed : 100,
			fadeOutSpeed : 200,
			fadeInSpeed : 400,
			equalHeights : true,
			css : {
				display: 'block',
				float: 'left'
			}
		}
		
		return this.each(function() {
			var $this = $(this);
			var o = $.extend( true, {}, settings, options );
			
			var steps = $this.children();
			steps.css(o.css);
			
			// Don't do it at all if there isn't enough elements
			if (steps.length <= o.stepCount) return false;
			
			// First set heights if required
			if (o.equalHeights) {
				var tallest = 0;
				steps.each(function(){
					if ($(this).height() > tallest) tallest = $(this).height();
				});
				
				// for ie6, set height since min-height isn't supported
				if ($.browser.msie && $.browser.version == 6.0) { steps.css({'height': tallest}); }
				steps.css({'min-height': tallest});
			}
			
			// Make a div for hiding and stacking non-active steps
			// Allows each next step to be grabbed from the front and old ones inserted to the back
			var hiddenSteps = $('<div id="hiddenSteps">').insertAfter(this).hide();
			
			// Reference for visible step range
			var firstIndex = o.stepOffset;
			var lastIndex = o.stepOffset + (o.stepCount - 1);
			
			// set class markers on visible steps
			$(steps[firstIndex]).addClass('firstStep');
			$(steps[lastIndex]).addClass('lastStep');
				
			// put steps after the offset at the start of the stack
			steps.each(function(index) {	
				if (index > lastIndex) {
					$(this).hide();
					hiddenSteps.append(this);
				}
			});
			
			// put steps before the offset at the end of the stack
			steps.each(function(index) {
				if (index < firstIndex) {
					$(this).hide();
					hiddenSteps.append(this);
				}
			});
			
			// Step Through function replaces each visible step with the first or last from the hidden stack (depending on direction)
			var stepThrough = function(event) {
				var direction = event.data.direction;
				var currentSteps = $this.children();
				
				// Put elements in stack for timeout function to go through
				var transitionStack = new Array();
				
				for (var i=0; i < o.stepCount; i++) {
					transitionStack[i] = new Array();
					// Append and add classes to new steps before showing them
					if(direction == 'next') {
						transitionStack[i]['fromStep'] = $(currentSteps[i]);
						transitionStack[i]['fromEnd'] = 'start';
						if (i==0) {
							transitionStack[i]['class'] = 'firstStep';
						} else if (i==o.stepCount-1) {
							transitionStack[i]['class'] = 'lastStep';
						}
					} else {
						transitionStack[i]['fromStep'] = $(currentSteps[o.stepCount-i-1]);
						transitionStack[i]['fromEnd'] = 'end';
						if (i==0) {
							transitionStack[i]['class'] = 'lastStep';
						} else if (i==o.stepCount-1) {
							transitionStack[i]['class'] = 'firstStep';
						}
					}
				}
				
				var stepTransition = function(transitionStack) {
					// keep looping function untill stack is complete
					if (transitionStack.length > 0) {
						thisTransition = transitionStack.shift();
						fromStep = thisTransition['fromStep'];
						if (thisTransition['fromEnd'] == 'start') {
							toStep = hiddenSteps.children().first();
						} else {
							toStep = hiddenSteps.children().last();
						}
						
						//alert("from: " + fromStep.html() + "  to: " + toStep.html());
						
						if (thisTransition['class'] != "") toStep.addClass(thisTransition['class']);
						
						fromStep.after(toStep);
						fromStep.fadeOut(o.fadeOutSpeed);
						toStep.fadeIn(o.fadeInSpeed);
						fromStep.removeClass('firstStep lastStep');
						
						if (thisTransition['fromEnd'] == 'start') hiddenSteps.append(fromStep);
						else hiddenSteps.prepend(fromStep);
						
						setTimeout(function(){
							stepTransition(transitionStack);
						}, o.stepSpeed);
					} else return false;
				};
				
				// Trigger start of transition and give callback for when it finishes
				stepTransition(transitionStack);
			}
			
			// Assign actions to 'next' and 'prev' elements
			var stepNext = (o.stepNext.length > 0 ? o.stepNext : false);			
			var stepPrev = (o.stepPrev.length > 0 ? o.stepPrev : false);
			stepNext.bind('click', {direction:'next'}, stepThrough);
			stepPrev.bind('click', {direction:'prev'}, stepThrough);
		});
	};
	
})(jQuery);
