/*

	Plugin Name: 			High Roller
	Plugin Version: 		0.1
	Plugin Description:  	Creates a fancy style rolling slideshow of an element and
							its children and dynamically builds a navigation
	
	Author Name: 			Matt Scheurich
	Author Email: 			matt@hive.com.au
	Author URL: 			http://www.hive.com.au/
	
	Usage: 					jQuery(element(s) selector).highroller({
								buildNavigation: 	[Boolean],
								navLayout: 			[Array with accepted String values: 'prev', 'items', 'next'],
								allowAutoRoll: 		[Boolean],
								duration:			[Number > 0],
								pauseOnHover:		[Boolean],
								startOnItemIndex:	[Number > 0],
								displayItemTitle: 	[Boolean],
								animateType: 		[String: fade, slide, slide y, flash]
								animateDuration: 	[Number > 0],
								animateComplete: 	[Function]
							});
	
	What happens: 			This script will wrap your selected element(s) with a
							<div id="highroller-RANDOMSTRING" class="highroller">..</div>,
							remove the "highroller" class attached to it, format the visual
							style of the inner children and build any necessary navigation
							according to navLayout's ordering.
	
*/

(function(){

	jQuery.fn.highroller = function( options ) {
	
		var settings = jQuery.extend( {
			buildNavigation: 	1,
			navLayout: 			[ 'items', 'prev', 'next' ],
			allowAutoRoll: 		1,
			duration:			5000,
			pauseOnHover:		1,
			startOnItemIndex:	0,
			displayItemTitle: 	1,
			animateType: 		'fade',
			animateDuration: 	500,
			onloadinit: 		undefined,
			onloadcomplete: 	undefined,
			onbeforeroll: 		undefined,
			onafterroll: 		undefined
		}, options );
		
		// Process set options
		if ( settings.animateType == 'slide' ) settings.animateType = 'slide-x';
		if ( settings.buildNavigation && typeof settings.navLayout == 'string' ) {
			settings.navLayout = settings.navLayout.split(' ');
		}
		
		return this.each( function() {
		
			// Set object variables
			var $content = jQuery(this);
			var $items = $content.children();
			
			// Turn off autoroll if only one item
			if ( $items.length <= 1 ) settings.allowAutoRoll = 0;
			
			// Wrap in necessary HTML
			$content.wrap( '<div id="highroller-'+jQuery.randomString()+'" class="highroller '+( settings.allowAutoRoll ? ' autoroll' : '' )+'"></div>' );
			var $nav = 0;
			$content.addClass( 'highroller-content'+( settings.animateType.match(/^slide/i) ? ' slide ' : ' ' )+settings.animateType );
			
			// Set more object variables 
			var $roller = $content.parent();
			var root = $roller[0];

			// Set specific highroller config options (this is referenced later for the 'animate' event bound to $roller)
			root.highroller = {
				mouseOver: 					0,
				autoRollTimer: 				0, 
				flashColour: 				( settings.animateType.match(' ') ? settings.animateType.split(' ')[1] : '#FFFFFF' ),
				contentLength: 				0, 
				contentItemsLength: 		[],
				contentItemsLengthTotal: 	0,
				slideAnimSide: 				( settings.animateType.match(/^slide/i) && settings.animateType.match(/y$/i) ? 'height' : 'width' ),
				slideAnimPos: 				( settings.animateType.match(/^slide/i) && settings.animateType.match(/y$/i) ? 'top' : 'left' ),
				slidePos: 					0
			}
			
			// Build Navigation...
			if ( settings.buildNavigation && settings.navLayout.length > 0 ) {
				
				// ... doin' it!
				var navControls = '<div class="highroller-nav">';
				if ( settings.displayItemTitle ) navControls += '<p class="highroller-item-title"></p>';
				navControls += '<ul class="highroller-nav-controls">';
				
				// Build navigation depending on layout
				for( var i=0; i<settings.navLayout.length; i++ ) {
					
					// Display prev item
					if ( settings.navLayout[i] == 'prev' ) {
						navControls += '<li class="highroller-nav-prev"><a href="javascript:void(null)">&laquo; Prev</a></li>';
						
					// Display next item
					} else if ( settings.navLayout[i] == 'next' ) {
						navControls += '<li class="highroller-nav-next"><a href="javascript:void(null)">Next &raquo;</a></li>';

					// Display items
					} else {
						$items.each( function() {
							navControls += '<li title="'+$content.attr('title')+'" class="highroller-nav-item"><a href="javascript:void(null)">'+$content.attr('title')+'</a></li>';
						});
					}
					
				}
				
				// Finishin' it!
				navControls += '</ul></div>';
				$roller.append( navControls );
				
				// Assign $nav object variable
				$nav = $roller.find('.highroller-nav-controls:eq(0)');
			
			// ... or not!
			} else {
				if ( settings.displayItemTitle ) $roller.append( '<p class="highroller-item-title"></p>' );
			}
			
			// Depending on animateType, visually affect the items
			if ( !settings.animateType.match(/^slide/i) ) {
				$items.hide();
				
			} else {
				// Wrap with specific slider container
				$content.wrap( '<div class="highroller-slide"></div>' );
				
				// Set up for sliding on the y-axis
				if ( root.highroller.slideAnimSide == 'height' ) {
					root.highroller.contentLength = $content.parent().outerHeight(); // Height of highroller-slide wrapper
					$items.each( function(i) {
						root.highroller.contentItemsLength[i] = $items.filter(':eq('+i+')').outerHeight();
						root.highroller.contentItemsLengthTotal += root.highroller.contentItemsLength[i];
					});
					$items.css({
						clear: 		'both'
					});
					
				// Set up for sliding on the x-axis (default)
				} else {
					root.highroller.contentLength = $content.parent().outerWidth(); // Width of highroller-slide wrapper
					$items.each( function(i) {
						root.highroller.contentItemsLength[i] = $items.filter(':eq('+i+')').outerWidth();
						root.highroller.contentItemsLengthTotal += root.highroller.contentItemsLength[i];
					});
					
				}
				$content.css( root.highroller.slideAnimSide, (root.highroller.contentLength*$items.length)+'px' );
			}
			
			// This is the point where init has finished, so trigger the oninit event
			if ( typeof settings.onloadinit == 'function' ) settings.onloadinit(root);
			
			// Assign events
			// -- Auto timer
			$roller.bind( 'startAutoRoll', function(e, $data) {
				// Reset auto roll
				clearTimeout( root.highroller.autoRollTimer );
				
				// Set auto roll timer
				if ( settings.allowAutoRoll && $roller.hasClass('autoroll') && !root.highroller.mouseOver ) {
					root.highroller.autoRollTimer = setTimeout( function(){
						$roller.trigger( 'animate', ( $data && ($data.item.length > 0 || typeof $data.item != 'object') ? { item: $data.item } : undefined ) );
					}, settings.duration );
				}
				
			}).bind( 'stopAutoRoll', function(e) {
				clearTimeout( root.highroller.autoRollTimer );
			});
			
			// -- Animate
			$roller.bind( 'animate', function(e, $data) {
				
				var $roller = jQuery(this);
				var $content = $roller.find('.highroller-content:eq(0)');
				var $items = $content.children();
				var $nav = ( $roller.find('.highroller-nav-controls:eq(0)').length > 0 ? $roller.find('.highroller-nav-controls:eq(0)') : undefined );
				var $current = undefined;
				var $next = undefined;
				
				// Currently viewed item is marked with the class "current". If not there, then use the currently visible one
				$current = ( $items.filter('.current').length > 0 ? $items.filter('.current:eq(0)') : $items.filter(':visible').filter(':eq(0)') );
				
				// View specific item
				if ( $data ) {
					if ( $data.item.length == 0 || typeof $data.item != 'object' ) return error( '$data.item does not exist on page' );
					$next = $data.item;
					
				// Default to next item...
				} else {
					// If current is set, use next child
					if ( $current.length > 0 ) $next = $current.next();
					
					// ... or start from start
					if ( $next.length == 0 ) $next = $items.filter(':eq(0)');
				}
				
				// Update switcher
				if ( $nav ) {
					$nav.find('.highroller-nav-item').removeClass('current').filter(':eq('+$items.index( $next )+')').addClass('current');
				}

				// Update item title display
				if ( settings.displayItemTitle ) $roller.find('.highroller-item-title').text( $next.attr('title') );
				
				// onbeforeroll event
				if ( typeof settings.onbeforeroll == 'function' ) settings.onbeforeroll(root);
				
				// Animate display
				// -- Fade animation
				if ( settings.animateType.match(/^fade/i) ) {
					$current.removeClass('current');
					$next.addClass('current').fadeIn( settings.animateDuration, function() {
						$current.hide();
						$roller.trigger( 'startAutoRoll' );
						if ( typeof settings.onafterroll == 'function' ) settings.onafterroll(root);
					});
					
				// -- Slide animation
				} else if ( settings.animateType.match(/^slide/i) ) {
					contentPos = $roller.offset();
					currItemIndex = $items.index( $current ) || 0;
					itemIndex = $items.index( $next );
					$current.removeClass('current');
					$next.addClass('current');
					animateObj = {};
					this.highroller.slidePos = 0;
					// Step through each item to get the total slide offset length
					for( var i=0; i<itemIndex; i++ ) {
						this.highroller.slidePos -= this.highroller.contentItemsLength[i];
					}
					if ( this.highroller.slidePos < this.highroller.contentLength-this.highroller.contentItemsLengthTotal ) this.highroller.slidePos = -(this.highroller.contentItemsLengthTotal-this.highroller.contentLength);
					animateObj[this.highroller.slideAnimPos] = this.highroller.slidePos+'px';
					$content.animate( animateObj, {
						duration: 	settings.animateDuration,
						complete: 	function(e) {
							$roller.trigger( 'startAutoRoll' );
							if ( typeof settings.onafterroll == 'function' ) settings.onafterroll(root);
						} 
					});
					
				// -- Flash animation
				} else if ( settings.animateType.match(/^flash/i) ) {
					$roller.append( '<div class="highroller-flash" style="display: block; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: '+this.highroller.flashColour+'; z-index: 5;"></div>' );
					$current.hide().removeClass('current');
					$next.show().addClass('current');
					$roller.find('.highroller-flash').fadeOut( settings.animateDuration, function() {
						jQuery(this).remove();
						$roller.trigger( 'startAutoRoll' );
						if ( typeof settings.onafterroll == 'function' ) settings.onafterroll(root);
					});
				}
				
			});
			
			// -- Pause auto-animate
			$roller.bind( 'mouseenter', function(e) {
				root.highroller.mouseOver = 1;
				if ( settings.pauseOnHover ) $roller.trigger( 'stopAutoRoll' );
			}).bind( 'mouseleave', function(e) {
				root.highroller.mouseOver = 0;
				if ( settings.pauseOnHover ) $roller.trigger( 'startAutoRoll' );
			});
			
			// -- Nav function
			if ( $nav ) {
				$nav.click( function(e) {
					e.preventDefault();
					
					// Get list element that was clicked
					var $li = ( jQuery(e.target).is('li') ? jQuery(e.target) : jQuery(e.target).parents('li') );
					
					// Error check
					if ( !$li ) return false;
					if ( $li.hasClass('current') ) return false;
					
					// Determine itemIndex depending on nav item pressed (corresponds with $items within $content )
					var itemIndex = $items.index( $items.filter('.current:eq(0)') );
					if ( itemIndex == -1 ) itemIndex = 0;
					
					// -- Prev or Next button pressed
					if ( $li.is('.highroller-nav-prev') || $li.is('.highroller-nav-next') ) {
						$li.is('.highroller-nav-prev') ? itemIndex-=1 : itemIndex+=1;

						// Wrap to first
						if ( itemIndex > ($items.length-1) ) itemIndex = 0;
						
						// Wrap to last
						if ( itemIndex < 0 ) itemIndex = $items.length-1;

					// -- Specific item button pressed
					} else {
						itemIndex = $nav.find('.highroller-nav-item').index( $li );
					}
					
					// Trigger $roller 'animate' event
					$roller.trigger( 'animate', { item: $items.filter(':eq('+itemIndex+')') } );
					
				});
			}
			
			// Show the first item
			if ( parseInt(settings.startOnItemIndex) < 0 ) settings.startOnItemIndex = 0;
			
			// Start it off
			$roller.trigger( 'animate', { item: $items.filter(':eq('+settings.startOnItemIndex+')') } );
			
			if ( typeof settings.onloadcomplete == 'function' ) settings.onloadcomplete(root);
		
		});
	
	};
	
	jQuery.randomString = function() {
		var output = '';
		for ( var i=0; i<16; i++ ) {
			output += String.fromCharCode( 97 + Math.round(Math.random()*25) );
		}
		return output;
	};
	
	function echo() {
		if ( arguments.length == 0 ) return false;
		if ( window.console ) console.log( arguments );
	};
	
	function error() {
		if ( arguments.length == 0 ) return false;
		if ( window.console ) console.error( 'jQuery.highroller', arguments );
		return false;
	};

})();