/*
Eg. :


*/

/*

To do : multiple banners on a page

*/

(function($){
	$.fn.cycler = function( opts ) {
		var	o = {
			selectorText : {
				viewPort : '.viewport',
				slidesContainer : '.contentSlider',
				slide : '.contentContainer',
				navParent : '.navParent'
			},
			settings : {
				type : 'fade',						// Sets the type of anim.  Possible values are : slide,fade,hard. //
				direction : 'down',					// Sets the direction of the anim  if type is 'slide'. Possible values are : up,down,left,right. //
				createNav : false,					// Sets to show numbers to navigate or not . Possible values are : true, false. //
				animDuration : 500,						// Anim time in milliseconds. //
				easing : 'easeInOutQuint',							// Easing to apply. //
				delay : 5000,
				useTimer : true
			},
			classes : {
				navContainer : 'navContainer',
				navBtn : 'navBtn',
				navSelect : 'selected',
				unqiqueSlide : '_jsSlide_',
				unqiqueSlideBtn : '_jsSlideBtn_'
			},
			handlers : {
				forEachSlide : null,
				onAnimEnd : null,
				onAnimStart : null
			},
			gotoFunctions : [
				/*{
					selector : $('p'),
					event : 'click',
					goto : 0,							// Can be a zero based interger, or 'next' or 'previous'
					preventDefault : true
				},
				[$('p'),'click',0,true]*/
			]
			
		};
		$.extend( true, o, opts );
		return this.each(function(){
			
/*==================== CACHE SELECTORS ====================*/

			var	$this				= $(this),
				$viewport			= $this.find(o.selectorText.viewPort),
				$slidesContainer	= $viewport.find(o.selectorText.slidesContainer),
				$slide				= $slidesContainer.find(o.selectorText.slide),
				$nav				= $('<div>', { 'class' : o.classes.navContainer }),
				$navParent			= $this.find(o.selectorText.navParent),
				$extraSlide			= $('');
			
			
/*==================== DEFINE VARS ====================*/

			var	slideTotal			= $slide.size(),
				slideCurrent		= 0,
				isAnimating			= false
				slideH				= $slide.first().height(),
				slideW				= $slide.first().width();
			cyclerNextSlideTimeout	= 0;
			
			
/*==================== RETURN OR CALL SOME FUNCTIONS ====================*/

			if( slideTotal < 1 ) return this; // Return if there is only 1 slide. //
			changeCss( o.settings.type, o.settings.direction ); // Change css. //
			if( o.settings.createNav ) $navParent.append($nav); // Create Nav container. //
			
			
/*==================== GIVE EACH SLIDE A UNIQUE CLASS TO BE REFERENCED BY & HIDE IT IF IT'S NOT THE FIRST ONE ====================*/

			$slide.each(function( i ){
				$(this)
					.addClass(o.classes.unqiqueSlide+i)
					.relToData();
				if( o.handlers.forEachSlide ) o.handlers.forEachSlide( $(this), i, slideTotal );
				if( o.settings.createNav ){
					var $a = $('<a>',{ 'class' : o.classes.navBtn, html : i });
					$nav.append($a);
				}
			});
			
			
/*==================== INTERACTIVITY FOR BUTTONS ====================*/

			$navBtn = $nav.find('.'+o.classes.navBtn);
			$navBtn.each(function( i ){
				var selected;
				i > 0 ? selected = '' : selected = o.classes.navSelect;
				$(this)
					.addClass(o.classes.unqiqueSlideBtn+i+' '+selected)
					.click(function(e){
						e.preventDefault();
						showSlide( i );
					});
			});
			
			
/*==================== GOTO FUNCTIONS ====================*/

			$.each(o.gotoFunctions,function( key, value ){
				if( !(value.selector) ){
					value[0].bind( value[1], function( event ){
						if( value[3] ) event.preventDefault();
						if( value[2] == 'previous' ) showSlide(slideCurrent-1);
						else if( value[2] == 'next' ) showSlide(slideCurrent+1);
						else showSlide(value[2]);
					});
				}else{
					(value.selector).bind( value.event, function( event ){
						if( value.preventDefault ) event.preventDefault();
						if( value.goto == 'previous' ) showSlide(slideCurrent-1);
						else if( value.goto == 'next' ) showSlide(slideCurrent+1);
						else showSlide(value.goto);
					});
				}
			});
			
			
			
/*==================== WHEN HOVERING OVER THE CYCLER, NO ANIMATING ====================*/

			$this.data('hover',false).hover(function(){
				$this.data('hover', true);
				clearTimeout(cyclerNextSlideTimeout);
			},function(){
				$this.data('hover', false);
				startNextSlideTimer( o.settings.delay*.5 );
			});
			

/*==================== THE MAIN SHOW SLIDE FUNCTION ====================*/	
		
			function showSlide( num ){
				if( num == slideCurrent || isAnimating ) return false;
				
				// Define vars. //
				var isFaking		= false;
				var animDuration	= o.settings.animDuration;
				var animEasing		= o.settings.easing;
				var type			= o.settings.type;
				var direction		= o.settings.direction;
				var delay			= o.settings.delay;
				
				// Conditionals. //
				if( type == 'slide' ){
					if( num > slideTotal ) slideCurrent = 0;
					else if( num > slideTotal-1 ){
						isFaking = true;
						slideCurrent = num;
					}else if( num < 0 ) slideCurrent = slideTotal-1;
					else slideCurrent = num;
				}else{
					if( num > slideTotal-1 ) slideCurrent = 0;
					else if( num < 0 ) slideCurrent = slideTotal-1;
					else slideCurrent = num;
				}
				
				
				// Call Callback & set isAnimating. //
				isAnimating = true;
				if( o.handlers.onAnimStart ) o.handlers.onAnimStart( $this, slideCurrent, slideTotal );
				
				
				// Cache selectors. //
				var $slideCurrent = $slidesContainer.find('.'+o.classes.unqiqueSlide+slideCurrent);
				if( isFaking ) $slideCurrent = $slidesContainer.find('.'+o.classes.unqiqueSlide+0);
				var $slideNonCurrent = $slideCurrent.siblings();
				if( !$slideCurrent.size() ) isAnimating = false;
				
				
				// Override settings with inline data from rel tag. //
				if( $slideCurrent.data('easing') ) animEasing		= $slideCurrent.data('easing');
				if( $slideCurrent.data('duration') ) animDuration	= $slideCurrent.data('duration');
				if( $slideCurrent.data('delay') ) delay				= $slideCurrent.data('delay');
				
				if( type == 'slide' ){
				
					if( direction == 'up'){
						$slidesContainer.animate({ 'top' : -slideH*slideCurrent }, { duration : animDuration, easing : animEasing, complete : function(){
							if( isFaking ){
								$slidesContainer.css({'top':0});
								slideCurrent = 0;
							}
							onAnimEnd();
						}});
					}else if( direction == 'down' ){
						$slidesContainer.animate({'bottom' : -slideH*slideCurrent}, {duration : animDuration, easing : animEasing, complete : function(){
							if( isFaking ){
								$slidesContainer.css({ 'bottom' : 0 });
								slideCurrent = 0;
							}
							onAnimEnd();
						}});
					}else if( direction == 'left' ){
						$slidesContainer.animate({'left':-slideW*slideCurrent}, {duration : animDuration, easing : animEasing, complete : function(){
							if( isFaking ){
								$slidesContainer.css({ 'left' : 0 });
								slideCurrent = 0;
							}
							onAnimEnd();
						}});
					}else if( direction == 'right' ){
						$slidesContainer.animate({'right':-slideW*slideCurrent}, {duration : animDuration, easing : animEasing, complete : function(){
							if( isFaking ){
								$slidesContainer.css({ 'right' : 0 });
								slideCurrent = 0;
							}
							onAnimEnd();
						}});
					}
						
				}else if( type == 'fade' || type == 'hard' ){
					$slideCurrent.hide();
					$slidesContainer.append($slideCurrent);
					if( type == 'hard' ){
						$slideCurrent.show();
						$slideNonCurrent.hide();
						onAnimEnd();
					}else{
						$slideCurrent.fadeIn( o.settings.animDuration, o.settings.easing, function(){
							$slideNonCurrent.hide();
							onAnimEnd();
						});
					}
				}
				
				
				// Change current nav btn class. //
				isFaking ? setNav( 0 ) : setNav( slideCurrent );
					
				
				// Start next slide timer. //
				function onAnimEnd(){
					isAnimating = false;
					startNextSlideTimer( delay );
					if( o.handlers.onAnimEnd ) o.handlers.onAnimEnd( $this, slideCurrent, slideTotal );
				}
			}
	

/*==================== CHANGE CSS FUNCTION ====================*/

			function changeCss( type, direction ){
				if( type == 'slide' ){
					$extraSlide = $slide.first().clone();
					$extraSlide.appendTo( $slidesContainer );
					
					
					$slidesContainer.css({ position : 'absolute' });
					
					if( direction == 'up' || direction == 'down' ){
						$slide.siblings( $extraSlide ).andSelf().css({
							clear : 'both',
							float : 'none',
							position : 'relative'
						});
						if( direction == 'up') $slidesContainer.css({ top : 0 });
						else if( direction == 'down' ) $slidesContainer.css({ bottom : 0 });
						
						var combinedSlidesHeight = ($slide.size()+1)*($slide.first().height());
						$slidesContainer.height(combinedSlidesHeight);
					}else if( direction == 'left' || direction == 'right' ){
						$slide.siblings( $extraSlide ).andSelf().css({
							float : 'left',
							position: 'relative'
						});
						if( direction == 'left') $slidesContainer.css({ left : 0 });
						else if( direction == 'right' ) $slidesContainer.css({ right : 0 });
						
						var combinedSlidesWidth = ($slide.size()+1)*($slide.first().width());
						$slidesContainer.width(combinedSlidesWidth);
					}
				}else if( type == 'fade' || type == 'hard' ){
					if( !$.support.opacity ) o.settings.type = 'hard';
					$extraSlide.remove();
					$slide.css({
						left : 0,
						position : 'absolute',
						top : 0,
						float : 'none',
						clear : 'none'
					});
					$slidesContainer.css({ position : 'relative' });
				}
				
				$slide.each(function( i ){
					if( type == 'slide' ) $(this).show();
					else{
						if( i != slideCurrent ) $(this).hide();
						else $(this).show();
					}
				});
			}
			
				
/*==================== NAV FUNCTION ====================*/

			function setNav( num ){
				$navBtn
					.not('eq('+num+')').removeClass(o.classes.navSelect).end()
					.eq(num).addClass(o.classes.navSelect);
			}


/*==================== TIMER FUNCTION ====================*/
			
			function startNextSlideTimer( delay ){
				clearTimeout(cyclerNextSlideTimeout);
				if( !o.settings.useTimer ) return false;
				if( $this.data('hover') ) return false;
				else{
					if( !delay ) delay = o.settings.delay;
					cyclerNextSlideTimeout = setTimeout(function(){
						showSlide( slideCurrent+1 );
					}, delay);
				}
			}
			
/*==================== SHOW INITIAL STATE ====================*/
			
			startNextSlideTimer();
			return this;
		});
	};
})(jQuery);
