/**
 * Created: 8 Jun 2010
 * By: Dave Elkan, Jens Korff, Krishan Rodrigo
 *
 * Rotate a give list of items periodically
 * Applies to items that attaches to .rotator class
 * 
 * HTML Requirement:
 * 			Class 'rotator': Add to the mqin rotator container
 *			Class 'rotList': Add to Rotatee elements container 
 * 			Class 'selected': Optional. Required if 'random' option is not set
 *							  Add to the currenly selected rotatee element
 * 			
 *			Optional:	
 * 				Class 'rotNavControls': Add to element containing rotation control elements
 *				Class 'rotNav': Add to container of rotation controllers; Eg: Prev, Next, Play/Pause
 * 				Class 'entryNav': Add to single entry controller element
 * 
 * Options include: 
 *			interval: time between transition in seconds
 *			start: if set to 'random', rotator will start from a random element OR 
 *					will start from the currently 'selected' item
 *			selector: Indicates the items that needs to rotate
 *			entryNavSelector: Indicates the single entry navigation items to be selected
 */
 
/**
 * Namespacing the function and creating a plug-in
 */
$.fn.fdRotator = function(options) {
	var
	
	rotator = $(this),
	
	/**
	 * Defining the defaults for the function
	 */
	defaults = {
		selector: "li",
		entryNavSelector: ".entryNav li",	// KR
		interval: 5,	//Interval time in seconds
		clickTarget: "li"	// When clicking on a control and if it's not a link, we need to find this parent element type
	},	
	options = $.extend(defaults, {}, options),	//Combine user defined defaults with function defaults
	rotatees = rotator.find(options.selector),
	entryNavElements = rotator.find(options.entryNavSelector), // KR: Find all entry nav items
	
	/**
	 * IntervalID is a handler to start/stop rotation when needed
	 */
	intervalID,
	
	/**
	 * Indicates that the user has clicked on any navigation control ('rotNav' OR 'entryNav')
	 * Defaults to not clicked status
	 */
	userHasClicked = false,
	
	/**
	 * Index of currently visible rotatee
	 */
	currentRotateeIndex,
	
	/**
	 * Number of rotating elements
	 */
	rotateesCount = rotatees.length;
	
	/**
	 * Starts the rotation
	 */	
	function startRotation() {
		if ( !userHasClicked ) {
			stopRotation();
			intervalID = setInterval( rotateNext, options.interval * 1000 );
		}
	}
	
	/**
	 * Stops the rotation
	 */	
	function stopRotation() {
		clearInterval(intervalID);
	}
	
	/**
	 * Rotate one element by a given direction
	 * Direction is either forward or backward
	 * Forward = 1 | Backward = -1
	 * Forms the basis for rotateNext and rotatePrevious functions
	 */	
	function rotate(direction) {
		var nextRotateeIndex = getNextRotateeIndex(direction);
		
		rotatees.removeClass('selected');
		$(rotatees.get(nextRotateeIndex)).addClass('selected');

		currentRotateeIndex = nextRotateeIndex;
		
		/**
		 * KR: 
		 * Find and add class to the associated entryNav navigation item 
		 * of the currently visible rotatee
		 */		
		handleEntryNav(currentRotateeIndex);
	}
	
	/**
	 * Rotate to the next element
	 */	
	function rotateNext() {
		rotate(1);
	}
	
	/**
	 * Rotate to the previous element
	 */		
	function rotatePrevious() {
		rotate(-1);
	}
	
	/**
	 * Returns the index number of the next available rotatee item from the list of items
	 */	
	function getNextRotateeIndex(direction) {
		var nextRotateeIndex = currentRotateeIndex + direction;
		
		if ( nextRotateeIndex >= rotateesCount ) {
			nextRotateeIndex = 0;
		} else if ( nextRotateeIndex < 0 ) {
			nextRotateeIndex = rotateesCount - 1;
		}
		
		return nextRotateeIndex;
	}
	
	/**
	 * Stops the defaults link behaviour and 
	 * stop them from happening later in the jquery chain of events
	 */	
	function stopEvent(event) {
		if ( event ) {
			event.preventDefault();		// stop default action
			event.stopPropagation();	// stop event from bubbling up
		}
	}
	
	/**
	 * Returns the element of a clicked event
	 */	
	function getTarget(event) {
		var target = $(event.target);
		if ( !target.is(options.clickTarget) ) {		// if clicked on parent of anchor...
			target = target.parent(options.clickTarget);  // ...get parent
		}
		return target;
	}
	
	/**
	 * Add / Remove 'selected' class to the associated 
	 * entryNav element as click events and auto-rotations occur
	 */
	function handleEntryNav() {
		entryNavElements.removeClass('selected');
		$(entryNavElements.get(currentRotateeIndex)).addClass('selected');
		//alert(currentRotateeIndex);	//KR
	}
	
	/**
	 * KR
	 * Add / Remove 'play' class from play/pause button
	 * Associated with all click events
	 */
	function handlePlayBtn() {		
		var pauseElement = rotator.find('.rotNavControls .pause');
		if ( !pauseElement.hasClass('play') ) {
			pauseElement.addClass('play');
			userHasClicked = true;
		} else {
			pauseElement.removeClass('play');
			//userHasClicked = false;
			startRotation();
		}
	}
	
	/**
	 * Associated with the 'rotNav' control navigation
	 * Catches and handles events as users interact with the navigation
	 */
	function catchRotNavClick(event) {
		var target = getTarget(event);
		stopEvent(event);
		stopRotation();
		userHasClicked = true;

		if ( target.hasClass('previous') ) {
			rotatePrevious();
			/**
			 * KR
			 * Add class play to the entry nav upon any click
			 */
			handlePlayBtn();
			
			/**
			 * KR: 
			 * Find and add class to the associated entryNav navigation item
			 */		
			handleEntryNav();
		} else if ( target.hasClass('next') ) {
			rotateNext();
			/**
			 * KR
			 * Add class play to the entry nav upon any click
			 */
			handlePlayBtn();
			/**
			 * KR: 
			 * Find and add class to the associated entryNav navigation item
			 */		
			handleEntryNav();
		} else if ( target.hasClass('pause') ) {	// This element will always have class 'pause'. 'play' is added if user clicks on Pause.
			/**
			 * KR - Handled within handlePlayBtn()
			 */
				/*if ( target.hasClass('play') ) {
					target.removeClass('play');
					userHasClicked = false;
					startRotation();
				} else {
					target.addClass('play');
				}*/	
			
			/**
			 * KR
			 * Add class play to the entry nav upon any click
			 */
			handlePlayBtn();
		}
	}
	
	/**
	 * Associated with the 'entryNav' control navigation
	 * Catches and handles events as users interact with the navigation
	 */
	function catchEntryNavClick(event) {
		var target = getTarget(event);
		stopEvent(event);
		stopRotation();
		//userHasClicked = true;	//KR - moved to handlePlayBtn()

		var clickedElement = target.index();	//get the currently selected/clicked on element
		rotatees.removeClass('selected');
		$(rotatees.get(clickedElement)).addClass('selected');
		currentRotateeIndex = clickedElement;	// KR get the currently clicked element's index and assign it for future reference
		
		/**
		 * KR: 
		 * Find and add class to the associated entryNav navigation item
		 */		
		handleEntryNav();
		
		/**
		 * KR
		 * Add class play to the entry nav upon any click
		 */
		handlePlayBtn();
	}	
	
	/**
	 * Main function that initiates the rotation functionality
	 * Runs as soon as the end of the script is reached
	 */
	(function init() {
		if ( !options.start && options.start != 0 ) {
			currentRotateeIndex = rotator.find('.selected').prevAll().length; // index of current rotatee with class "selected"			
		} else if ( options.start == "random" ) {
			currentRotateeIndex = (rotateesCount > 1) ? Math.floor(Math.random() * (rotateesCount) + 1) - 1 : 0;
		} else {
			currentRotateeIndex = options.start;
		}
		/**
		 * KR: 
		 * Find and add class to the associated rotList item
		 */	
		rotatees.removeClass('selected');
		$(rotatees.get(currentRotateeIndex)).addClass('selected');
		
		/**
		 * KR: 
		 * Find and add class to the associated entryNav navigation item
		 */		
		handleEntryNav();
		
		rotator.mouseenter(stopRotation);
		rotator.mouseleave(startRotation);
		rotator.find('.rotNav').click( catchRotNavClick );
		rotator.find('.entryNav').click( catchEntryNavClick );
		startRotation();
	})();
	
};
