// 
//  jquery.rotator.js
//  
//  Created by Jesse Bunch on 2011-03-30.
//  Copyright 2011 Jesse Bunch (www.GetBunch.com). All rights reserved.
// 


(function($) {

	/**
	 * Rotator
	 * 
	 * CONFIGURATION OPTIONS
	 * intSlideLength - The length of time (ms) between slides
	 * intTransitionLength - The lengh of time (ms) for the transition in use
	 * boolCrossfade - If fade transition name, should we crossfade? (requires absolute pos)
	 * strNextButtonSelector - Selector for next button
	 * strPreviousButtonSelector - Selector for previous button
	 * 
	 * Usage: $("#mycontainer").rotator();
	 * 
	 */
    $.fn.rotator = function(objOptionOverrides) {
		
		// -------------------------------------
		// 	Make sure we have elements to work with
		// -------------------------------------
		
        if (!this.length) {
	
            return this;

        }
		
		// -------------------------------------
		// 	Plugin defaults
		// -------------------------------------
		
		var objOptions = {

			boolCrossfade: false,
			intSlideLength: 5000,
			intTransitionLength: 1000,
			strNextButtonSelector: '',
			strPreviousButtonSelector: '',
			strTransitionName: 'fade',
			strCaptionsContainer: ''
			
		};
			
		// -------------------------------------
		// 	Effect Definitions
		// -------------------------------------
		
		var effects = {
			
			/**
			 * Fade transition, performs a back-to-back
			 * or crossfade transision based on the boolean
			 * set in the options object.
			 */
			fade: function(elemFrom, elemTo) {
				
				var $from = $(elemFrom);
				var $to = $(elemTo);
				
				if (objOptions.boolCrossfade) {
					
					$from.fadeOut(objOptions.intTransitionLength);
					$to.fadeIn(objOptions.intTransitionLength);
					
				} else {
					
					$from.fadeOut(objOptions.intTransitionLength, function() {
						$to.fadeIn(objOptions.intTransitionLength);
					});
					
				}
				
			}
			
			
		};
		
		// -------------------------------------
		// 	Plugin Methods
		// -------------------------------------

		var methods = {
			
			/**
			 * Begins the auto advance process
			 * Note: function checks for a slide length of 0
			 * which would indicate that auto advance not be enabled.
			 */
			begin_auto_advance: function(elemParent) {
				
				if (objOptions.intSlideLength > 0) {
					
					// alert('fire');
					
					var $parent = $(elemParent);

					setInterval(function() {

						methods._show_next_element($parent);

					}, objOptions.intSlideLength);
					
				}
				
			},
			
			/**
			 * Advances to the next item and caption (if needed)
			 */
			advance_next: function(elemParent) {
				
				// Show the next main item
				methods._show_next_element(elemParent);
				
				// Caption? show the next
				if (objOptions.strCaptionsContainer) {
					
					methods._show_next_element($(objOptions.strCaptionsContainer));
					
				}
				
			},
			
			/**
			 * Advances to the previous item and caption (if needed)
			 */
			advance_previous: function(elemParent) {
				
				// Show the previous main item
				methods._show_previous_element(elemParent);
				
				// Caption? show the previous
				if (objOptions.strCaptionsContainer) {
					
					methods._show_previous_element($(objOptions.strCaptionsContainer));
					
				}
				
			},
			
			/**
			 * Transitions forward one step
			 */
			_show_next_element: function(elemParent) {
				
				var $parent = $(elemParent);
				var $children = methods._get_children($parent);
				var $current = methods._get_current_element($children);
				var $next = methods._get_next_element($current);
				
				// Make sure no other children are animating or shown
				// other than those we are working with. Avoids bug if
				// the user clicks the button really fast.
				$children.not($current).not($next).stop().hide();
				
				methods._do_transition($current, $next);
				
			},
			
			/**
			 * Transistions backward one step
			 */
			_show_previous_element: function(elemParent) {
			
				var $parent = $(elemParent);
				var $children = methods._get_children($parent);
				var $current = methods._get_current_element($children);
				var $prev = methods._get_previous_element($current);
				
				// Make sure no other children are animating or shown
				// other than those we are working with. Avoids bug if
				// the user clicks the button really fast.
				$children.not($current).not($prev).stop().hide();
				
				methods._do_transition($current, $prev);
				
			},
			
			/**
			 * Internal Method - Performs the actual
			 * transistions based on the transition name
			 * set in the options object.
			 */
			_do_transition: function(elemFrom, elemTo) {
				
				var $from = $(elemFrom);
				var $to = $(elemTo);
				
				$from.removeClass('visible');
				$to.addClass('visible');
				
				eval("effects." + objOptions.strTransitionName + "($from, $to);");
				
			},
			
			/**
			 * Internal Method - Fetches the children
			 * of the parent element provided
			 */
			_get_children: function(elemParent) {
			
				return $(elemParent).children();
				
			},
			
			/**
			 * Internal Method - Fetches the currently visible
			 * element.
			 */
			_get_current_element: function(elemsChildren) {
				
				return $(elemsChildren).filter(".visible").first();
				
			},
			
			/**
			 * Internal Method - Fetches the next element to show.
			 * Returns the first element if there isn't a "next" item.
			 */
			_get_next_element: function(elemCurrent) {
				
				var $current = $(elemCurrent);
				var $next = $current.next();
				
				if ($next.length == 0)
					$next = $current.parent().children().first();
					
				return $next;
				
			},
			
			/**
			 * Internal Method - Fetches the previous element. Returns
			 * the last element if there isn't a "previous" item.
			 */
			_get_previous_element: function(elemCurrent) {
				
				var $current = $(elemCurrent);
				var $prev = $current.prev();
				
				if ($prev.length == 0)
					$prev = $current.parent().children().last();
					
				return $prev;
				
			}
			
			
		};

		// -------------------------------------
		// 	Process each element
		// -------------------------------------
        return this.each(function() {
	
			// Instance Variables
			var $this = null;
			var	$children = null;
			
			// Override defaults with user options
			$.extend(objOptions, objOptionOverrides);
			
			// Set IVars
            $this = $(this);
           	$children = $this.children(objOptions.strChildSelector);

			// Initially, only show the first child
			$children.removeClass('visible').first().addClass('visible');
			
			// Captions? Only show the first child
			if (objOptions.strCaptionsContainer) {
				$(objOptions.strCaptionsContainer).children().hide().removeClass('visible').first().show().addClass('visible');
			}
			
			// Previous button?
			if (objOptions.strPreviousButtonSelector)
				$(objOptions.strPreviousButtonSelector).click(function() { methods.advance_previous($this); return false; });
			
			// Next button?
			if (objOptions.strNextButtonSelector)
				$(objOptions.strNextButtonSelector).click(function() { methods.advance_next($this); return false; });
			
			// Begin auto advance (if slide length > 0)
			methods.begin_auto_advance(this);

        });

    };

})(jQuery);
