/*
     _ _____ _ 
  __| |___ /(_)
 / _` | |_ \| |
| (_| |___) | |
 \__,_|____/|_|

d3i Paging View : A jQuery Plugin
Created by Michael Waterfall on 02/11/2010.
Copyright 2010 d3i. All rights reserved.

Notes:

Requires that the container object has it's dimensions specifically set
Container div is set to position:relative
Child divs are set to position:absolute and positioned accordingly

Navigation:

If provided, the `navigation` option must be a container element which
contains a child element for each page that will be displayed. When a page
is selected, the correspoding child element will have a CSS class assigned
to it to indicate it's highlighted state. This plugin will add a click event
handler to handle changing pages. If a child navigation element contains an
anchor <a> tag then that is the tag which will have the event attached to it. 
Otherwise, clicks on the child element itself will be handled. Either way, 
the highlighted class will always be on the child element, not any anchors 
contained within it.

The elements passed as navigationPrevious & navigationNext options will 
have event handlers directly added to them and no highlighting 
will take place.

*/

// jQuery Plugin
(function($){

	// Methods
	var methods = {
	
		// Initialise
		init : function (options) {
		
			// Object
			var object = $(this);
			if (object.children().length > 0) {
		
				// Default Options	
				var defaults = {
				
					// General
					wrap: true, // Whether the paging wraps from last>first or first<last
				
					// Cycling
					cycle: false, // Whether pages automatically change
					cycleDelay: 5000, // Delay between page changes
					cycleManualDelay: 5000, // Delay that occurs with manual page change
					cycleOneWay: true, // Cycle animation goes right even when wrapping
					
					// Animation
					animation: 'crossfade', // Can be 'none', 'slide', 'crossfade', 'fade', 'slidefade'
					animationDuration: 300, // Page change duration
					animationEasing: 'swing', // Animation easing
					
					// Navigation
					navigation: null, // Container element for navigation items
					navigationHighlightClass: 'highlight', // Class to apply to highlighted nav elements
					navigationPrevious: null, // Previous page nav
					navigationNext: null // Next page nav
					
				};
				if (options) $.extend(defaults, options);
				
				// Setup container object
				object.css({
					'overflow': 'hidden',
					'position': 'relative'
				});
			
				// Setup page elements
				var numberOfPages = object.children().length;
				object.children().each(function (i) {
					var object = $(this);
					if (i > 0) object.hide();
					$(this).css({ 
						'position': 'absolute',
						'top': '0px',
						'left': '0px'
					});
				});
				
				// Store initial data
				object.data('d3iPagingView', {
					defaults: defaults,
					index: 0
				});
				
				// Setup navigation buttons
				if (defaults.navigation) {
					defaults.navigation.children().each(function(i) {
					
						// Get correct element
						// If there is an anchor within each element then 
						// attach to that, otherwise just attach to the element
						var button = $(this);
						if (this.tagName != 'a') {
						
							// Button is not a link so see if there are
							// any anchors to attach click events to
							var link = $(this).find('a:first');
							if (link.length) button = link;

						}
						
						// Handle click
						button.click(function() {
							
							// Show page & delay cycle
							object.d3iPagingView('show', i, true);
							if (defaults.cycle) object.d3iPagingView('cycle', defaults.cycleManualDelay);
							return false;
						
						});
						
						// Highlight first
						if (i == 0) $(this).addClass(defaults.navigationHighlightClass);
						
					});
				}
				
				// Setup prev/next navigation buttons
				if (defaults.navigationPrevious) {
					defaults.navigationPrevious.click(function() {
						object.d3iPagingView('previous'); // Show
						if (defaults.cycle) object.d3iPagingView('cycle', defaults.cycleManualDelay); // Delay
						return false;
					});
				}
				if (defaults.navigationNext) {
					defaults.navigationNext.click(function() {
						object.d3iPagingView('next'); // Show
						if (defaults.cycle) object.d3iPagingView('cycle', defaults.cycleManualDelay); // Delay
						return false;
					});
				}
				
				// Begin cycle if needed
				if (defaults.cycle) object.d3iPagingView('cycle', defaults.cycleDelay);
			
			}
			
			// Finish
			return object;

		},
		
		// Cycle automatically through pages
		cycle : function (delay) {
		
			// Object
			var object = $(this),
				data = object.data('d3iPagingView'),
				defaults = object.data('d3iPagingView').defaults;
				
			// Set timeout to show next page & recycle
			if (data.timeoutID) clearTimeout(data.timeoutID);
			data.timeoutID = setTimeout(function() { 
			
				// Show and recycle
				object.d3iPagingView('show');
				object.d3iPagingView('cycle', defaults.cycleDelay);
				
			}, delay);
		
		},
		
		// Show next page
		next : function () {

			// Object
			var object = $(this),
				data = object.data('d3iPagingView'),
				defaults = object.data('d3iPagingView').defaults;
			
			// Show	
			object.d3iPagingView('show', data.index+1, true);
				
		},
		
		// Show previous page
		previous : function () {

			// Object
			var object = $(this),
				data = object.data('d3iPagingView'),
				defaults = object.data('d3iPagingView').defaults;
			
			// Show	
			object.d3iPagingView('show', data.index-1, true);
				
		},
		
		// Show a page
		show : function (index, wasManual) {

			// Object
			var object = $(this),
				data = object.data('d3iPagingView'),
				defaults = object.data('d3iPagingView').defaults;
			
			// Wrap index if needed
			var numberOfPages = object.children().length;
			if (defaults.wrap) {
				if (typeof(index) == 'undefined') index = data.index+1;
				if (index < 0) index = numberOfPages-1;
				else if (index > numberOfPages-1) index = 0;
			} else {
				if (index < 0 || index > numberOfPages-1) return;
			}

			// Prepare & validate
			var currentIndex = data.index;
			if (currentIndex == index) return false;
			var animating = data.animating;
			if (animating) return false;

			// Start
			var width = object.width();
			var current = object.children(':nth-child('+(currentIndex+1)+')');
			var next = object.children(':nth-child('+(index+1)+')');
			
			// Animation
			if (defaults.animation == 'slide' || defaults.animation == 'slidefade') { // Slide or slide fade
	
				// Animate
				data.animating = true;

				// Setup page positions ready for animation
				var directionRight = index > currentIndex || (!wasManual && defaults.cycleOneWay);
				if (directionRight) { // Right
					current.css({'left': '0px', 'display': 'block'});
					next.css({'left': width+'px', 'display': 'block'});
					object.get(0).scrollLeft = 0;
				} else { // Left
					current.css({'left': width+'px', 'display': 'block'});
					next.css({'left': '0px', 'display': 'block'});
					object.get(0).scrollLeft = width;
				}
				
				// Animate fading
				if (defaults.animation == 'slidefade') {
					current.show();
					next.hide();
					current.fadeOut(defaults.animationDuration, defaults.animationEasing);
					next.fadeIn(defaults.animationDuration, defaults.animationEasing);
				}
				
				// Animate scroll
				object.animate({'scrollLeft': (directionRight ? width : 0) }, defaults.animationDuration, defaults.animationEasing, function() {
					current.css('display', 'none');
					data.animating = false;
				});
			
			} else if (defaults.animation == 'crossfade') { // Crossfade
	
				// Animate
				data.animating = true;
			
				// Setup page positions ready for animation
				current.css({'left': '0px', 'display': 'block', 'z-index': 2});
				next.css({'left': '0px', 'display': 'block', 'z-index': 1});
	
				// Animate
				current.fadeOut(defaults.animationDuration, defaults.animationEasing, function() {
					current.css('display', 'none');
					data.animating = false;
				});
			
			} else if (defaults.animation == 'fade') { // Fade
	
				// Animate
				data.animating = true;
			
				// Setup page positions ready for animation
				current.css({'left': '0px', 'display': 'block', 'z-index': 2});
				next.css({'left': '0px', 'display': 'none', 'z-index': 1});
	
				// Animate
				current.fadeOut(defaults.animationDuration, defaults.animationEasing, function() {
					next.fadeIn(defaults.animationDuration, defaults.animationEasing, function() {
						current.css('display', 'none');
						data.animating = false;
					});
				});
			
			} else {
			
				// None
				current.css({'left': '0px', 'display': 'none'});
				next.css({'left': '0px', 'display': 'block'});
			
			}
			
			// Update selected
			data.index = index;
			
			// Navigation highlight
			if (defaults.navigation) {
				defaults.navigation.children(':nth-child('+(index+1)+')')
								   .addClass(defaults.navigationHighlightClass);
				defaults.navigation.children(':not(:nth-child('+(index+1)+'))')
								   .removeClass(defaults.navigationHighlightClass);
			}
			
			// Finish
			return object;
					
		}

	};
	
	// Main
	$.fn.d3iPagingView = function(method) {
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if ( typeof method === 'object' || ! method ) {
			return methods.init.apply( this, arguments );
		} else {
			$.error('Method ' + method + ' does not exist on jQuery.d3iPagingView');
		}    
	};

})(jQuery);
