/*
 * @projectDescription Creates a revolving series of content slides
 * @author Jon Frost <jon.frost@heathwallace.com>
 * @version 1.1
 * 
 */

(function($){
	
	$.fn.revolver = function(opts) {
		
		opts = $.extend({
			duration: 1000,
			interval: 6000,
			prev: null,
			next: null,
			slideSelector: null,
			pager: null,
			transition: 'slideLeft'
		}, opts);
		
		var $obj = this;
		$obj.currentPos = 0;
		$obj.totalSlides = this.children(opts.slideSelector).length;
		$obj.busy = false;
		$obj.window = null;
		
		if($obj.totalSlides < 2) return;
			
		return this.each(function() {
			var maxHeight = 0;
			var startPos = 0;
			
			if(opts.pager) $(opts.pager).empty();
			
			$obj.children(opts.slideSelector).each(function(i) {
				maxHeight = Math.max(maxHeight, $(this).outerHeight(true));

				i === 0 ? startPos = 0 : startPos = $obj.width();

				if(opts.transition != 'slideAll'){
					$(this).css({
						'width': $obj.width(),
						'position': 'absolute',
						'top': 0,
						'left': startPos
					});
				}
				
				if(opts.pager) {
					$(opts.pager).append('<a href="#"><span>'+(i+1)+'</span></a>');
				}
			});
			
			if(opts.transition == 'slideAll'){
				var $children = $obj.children(opts.slideSelector)
					.css({
						'float': 'left',
						'width': $(this).width()
					})
					.remove();
				$obj.window = $('<div class="window" />')
					.appendTo($(this))
					.css({
						position: 'absolute',
						width: $(this).width() * $obj.totalSlides
					});
				$obj.window.append($children);
			}
			
			$obj.css({
				'height': maxHeight,
				'overflow': 'hidden',
				'position': 'relative'
			});
			
			if(opts.prev) {
				enablePrev();					
			}				
			
			if(opts.next) {
				enableNext();
			}
			
			if(opts.pager) {
				$(opts.pager).show().find('a').bind('click', function(e) {
					moveTo($(opts.pager).find('a').index(e.target), e);
					return false;
				});
				$(opts.pager).find('a').eq(0).addClass('selected');
			}
			
			if(opts.interval > 0) {
				resume();
				
				/* $(opts.pager+', '+opts.prev+', '+opts.next).hover(function() {
					clearInterval($obj.autoplay);
				}, function() {
					resume();
				});	*/
				
				$('.homepageBanner').mouseover(function(){
					clearInterval($obj.autoplay);
				}).mouseout(function(){
					resume();
				});
				
			}
			
			if(opts.transition == 'slideAll'){
				setLinks($obj.currentPos);
			}
		});
		
		function enablePrev(){
			$(opts.prev)
				.unbind('click')
				.removeClass('disabled');
			$(opts.prev).show().bind('click', function(e) {
				moveTo($obj.currentPos === 0 ? $obj.totalSlides-1 : $obj.currentPos-1, e);
				return false;
			});
		}
		
		function enableNext(){
			$(opts.next)
				.unbind('click')
				.removeClass('disabled');
			$(opts.next).show().bind('click', function(e) {
				moveTo($obj.currentPos === $obj.totalSlides-1 ? 0 : $obj.currentPos+1, e);
				return false;
			});
		}
		
		function disableLinks($node){
			$node.addClass('disabled');
			$node.unbind('click');
		}
		
		function setLinks(position){
			if(position == $obj.totalSlides-1){
				disableLinks($(opts.next));
				enablePrev();
			}
			else if(position == 0){
				disableLinks($(opts.prev));
				enableNext();
			}
			else{
				enablePrev();
				enableNext();
			}
		}
		/*
		 * Animates the current slide out and the next slide in
		 * 
		 * @param {integer} nextSlide -  index of the next slide to be animated in
		 */
		function moveTo(nextSlide, e) {
			getAnimationProperties(opts.transition, nextSlide, e);
			if(!$obj.busy && $obj.currentPos != nextSlide) {
				$obj.busy = true;
				
				if(opts.transition == 'slideAll'){
					setLinks(nextSlide);
					$obj.window.animate({
						left: -$obj.width()*nextSlide
					}, opts.duration, function(){
						$obj.currentPos = nextSlide;
						$obj.busy = false;
					});
				}
				
				if(opts.cssBefore) $obj.children().eq(nextSlide).css(opts.cssBefore);
				
				$obj.children().eq($obj.currentPos).animate(opts.animOut, {
					duration: opts.duration,
					step: function(now) {
						getAnimationProperties(opts.transition, nextSlide, e, now);
						$obj.children().eq(nextSlide).css(opts.cssStep);
					},
					complete: function() {
						$obj.currentPos = nextSlide;
						$obj.busy = false;
					}
				});
				
				if(opts.pager) {
					$(opts.pager).find('a').removeClass('selected');
					$(opts.pager).find('a').eq(nextSlide).addClass('selected');			
				}				
			}		
		}
		
		/*
		 * Sets the interval for autoplay
		 */
		function resume() {
			$obj.autoplay = setInterval(function() {
				moveTo($obj.currentPos === $obj.totalSlides-1 ? 0 : $obj.currentPos+1, null);
			}, opts.interval);
		}
		
		/*
		 * Defines maps of CSS properties used by the jQuery animate method in the moveTo function
		 * 
		 * @param {string} transition - name of the transition defined in the options
		 * @param {integer} stepVal - the numeric value of the property being animated at each step  
		 */
		function getAnimationProperties(transition, nextSlide, e, stepVal) {
			switch(transition) {
				case 'slideLeft':
					opts.animOut = { left: -$obj.width() }
					opts.cssStep = { left: stepVal+$obj.width() }
					break;
				case 'slideRight':
					opts.animOut = { left: $obj.width() }
					opts.cssBefore = { left: -$obj.width() }
					opts.cssStep = { left: stepVal-$obj.width() }
					break;
				case 'slideX':
					if(nextSlide < $obj.currentPos && (e && e.target.id != opts.next.slice(1)) || (e && e.target.id === opts.prev.slice(1))) {
						opts.animOut = { left: $obj.width() }
						opts.cssBefore = { left: -$obj.width() }
						opts.cssStep = { left: stepVal-$obj.width() }
					}
					else {
						opts.animOut = { left: -$obj.width() }
						opts.cssBefore = { left: $obj.width() }
						opts.cssStep = { left: stepVal+$obj.width() }						
					}
					break;
				case 'slideUp':
					opts.animOut = { top: -$obj.height() }
					opts.cssBefore = { left: 0 }
					opts.cssStep = { top: stepVal+$obj.height() }
					break;
				case 'fade':
					opts.animOut = { opacity: 0 }
					opts.cssBefore = { left: 0 }
					opts.cssStep = { opacity: 1-stepVal }
					break;
			}
		}
		
	}	
	
})(jQuery);

