/*
	infiniteSlider v1.0

	Enhanced by Kai Johnson
	From anythingSlider work by Chris Coyier: http://css-tricks.com
	With major improvements by Doug Neiner: http://pixelgraphics.us/
	Originally based on work by Remy Sharp: http://jqueryfordesigners.com/

	To use the navigationFormatter function, you must have a function that
	accepts two paramaters, and returns a string of HTML text.
	
	index = integer index (1 based);
	panel = jQuery wrapped LI item this tab references
	@return = Must return a string of HTML/Text
	
	navigationFormatter: function(index, panel){
		return index + " Panel"; // This would have each tab with the text 'X Panel' where X = index
	}
*/

(function($){
	
	$.infiniteSlider = function(el, options){

		var base = this; // To avoid scope issues, use 'base' instead of 'this' to reference this class from internal events and functions.
		base.$el = $(el); // Access to jQuery and DOM versions of element
		base.el = el; 
		base.currentPage = 1; // Set up a few defaults
		base.nextPage = base.currentPage + 1;
		base.prevPage = base.currentPage - 1;
		base.timer = null;
		base.playing = false;
		base.$el.data("InfiniteSlider", base); // Add a reverse reference to the DOM object
	  				
		base.init = function(){
			base.options  = $.extend({},$.infiniteSlider.defaults, options);
			base.$wrapper = base.$el.find('> div').css('overflow', 'hidden'); // Cache existing DOM elements for later 
			base.$slider  = base.$wrapper.find('> ul');
			base.$items   = base.$slider.find('> li');
			base.$single  = base.$items.filter(':first');
			if(base.options.offset) base.$slider.css({'left':base.options.offset}); // Set the offset if needed
			if(base.options.buildNavigation) base.buildNavigation(); // Build the navigation if needed
			if(base.options.buildPrevNext) base.buildPrevNextButtons(); // Setup our forward/backward navigation
			base.singleWidth = base.$single.outerWidth(true); // The width of one panel (+ margins)
			if(base.options.continuous) base.continuousDelay = Math.ceil(base.options.animationTime/base.singleWidth);
			base.pages = base.$items.length; // Counts the number of 'li' items and stores it in a var
			base.visible = Math.ceil((base.$el.outerWidth()+Math.abs(base.options.offset))/base.singleWidth);
			if(base.visible < 2) base.visible = 2;
			base.pad = base.visible - 1; // Top and tail with a padded number of items
			base.$items.filter(':first').before(base.$items.slice(base.pages-base.pad,base.pages).clone().addClass('cloned')); // Top and tail the list with 'visible' number of items, top has the last section, and tail has the first
			base.$items.filter(':last').after(base.$items.slice(0,base.pad).clone().addClass('cloned')); // This supports the "infinite" scrolling
			base.$items = base.$slider.find('> li'); // We need to re-grab the list set, this time with the newly cloned items
			if(base.options.fades){ // Set the initial fade if the option is selected
				base.$items.css({'opacity':'0.5'});
				$('#slidearrows img').css({'opacity':'0'});	
			}
			if(base.options.autoPlay) { // If autoPlay functionality is included, then initialize the settings
				base.playing = !base.options.startStopped; // Sets the playing variable to false if startStopped is true
				base.buildAutoPlay();
			};
			if(base.options.pauseOnHover) { // If pauseOnHover then add hover effects
				base.$el.hover(function(){
					base.clearTimer();
				}, function(){
					base.startStop(base.playing);
				});
			}
			if((base.options.hashTags == true && !base.gotoHash()) || base.options.hashTags == false){ // If a hash can not be used to trigger the plugin, then go to page 1
				base.setCurrentPage(1);
			};
			if(base.options.rollin){
				base.$slider.css({'padding-left':'4000px'}).animate({paddingLeft:'0',left:base.options.offset}, 1000, base.options.easing);
			}
		};
		
		base.gotoPage = function(page, autoplay){
			if(autoplay !== true) autoplay = false; // When autoplay isn't passed, we stop the timer
			if(base.options.startButton && !autoplay) base.startStop(false); // Stop on click, must press startButton to resume -- turned off when startButton is false
			if(base.options.fades){
				base.$items.fadeTo(200,0.5,function(){
					$(this).removeClass('current');
				});
			} else {
				base.$items.removeClass('current');
			}
			if(typeof(page) == "undefined" || page == null) {
				alert('page was undefined'); // For troubleshooting purposes only
				base.setCurrentPage(1);
			};
			base.setCurrentThumb(page);		
			if(!base.options.continuous && page > base.pages + 1) page = base.pages; // Just check for bounds
			if(page < 0 ) page = 1;
			var dir = page < base.currentPage ? -1 : 1;
			var	n = Math.abs(base.currentPage - page);
			var	left = base.singleWidth * dir * n;
			if (base.options.continuous) left = 1;
			if (page == 0) {
				base.$wrapper.scrollLeft(base.singleWidth * (base.pages+1));
				page = base.pages;
				base.setCurrentThumb(page);
			} else if ((!base.options.continuous && page > base.pages) || (base.options.continuous && page > (base.singleWidth*base.pages))) {
				base.$wrapper.scrollLeft(base.pages);
				base.startStop(false);
				page = 1; // reset back to start position to create the infinite effect
				base.setCurrentThumb(page);
			} 
			base.$wrapper.filter(':not(:animated)').animate({
				scrollLeft : '+=' + left
			}, base.options.continuous ? 0 : base.options.animationTime, base.options.easing, function () {
				base.startStop(true);
				base.setCurrentPanel(page);
				$('#prevnext a').show();
				$('#slidearrows').show();		
				base.currentPage = page;
			});
		};
		
		base.setCurrentPage = function(page, move){
			base.setCurrentThumb(page);
			base.setCurrentPanel(page);
			if(move !== false) base.$wrapper.scrollLeft(base.singleWidth * page); // Only change left if move does not equal false
			base.currentPage = page; // Update local variable
		};
		
		base.setCurrentThumb = function(page){
			if(base.options.buildNavigation){ // Set visual
				if(base.options.fades){
					base.$nav.find('.cur').fadeTo(100,0.5,function(){
						$(this).removeClass('cur');
					});
					$(base.$navLinks[page - 1]).addClass('cur').fadeTo(100,1); 
				} else {
					base.$nav.find('.cur').removeClass('cur');
					$(base.$navLinks[page - 1]).addClass('cur');
				}
			}
		}
		
		base.setCurrentPanel = function(page){
			if(base.options.buildNavigation){ // Set visual
				if(base.options.fades){
					base.$items.filter('li:eq('+(page+1)+')').addClass('current').fadeTo(200,1);
				} else {
					base.$items.filter('li:eq('+(page+1)+')').addClass('current');
				}
			}
		}
		
		base.goForward = function(autoplay){
			if(autoplay !== true) autoplay = false;
			base.gotoPage(base.currentPage + 1, autoplay);
		};
		
		base.goBack = function(autoplay){
			if(autoplay !== true) autoplay = false;
		//	if(base.currentPage == 0) base.currentPage = 1; // Prevent failure on load
			base.gotoPage(base.currentPage - 1, autoplay);
		};
			  
		base.gotoHash = function(){
			if(/^#?panel-\d+$/.test(window.location.hash)){ // This method tries to find a hash that matches panel-X
				var index = parseInt(window.location.hash.substr(7)); // If found, it tries to find a matching item
				var $item = base.$items.filter(':eq(' + index + ')');
				if($item.length != 0){ // If that is found as well, then that item starts visible
					base.setCurrentPage(index);
					return true;
				};
			};
			return false; // A item wasn't found;
		};
        
		base.buildNavigation = function(){ // Creates the numbered navigation links
			base.$nav = $('#slidethumbnav'); // $("<div id='thumbNav'></div>").appendTo(base.$el);
			base.$items.each(function(i,el){
				var index = i + 1;
				var $a = $('#slidethumbnav a:eq('+(i)+')');//$("<a href='#'></a>");
				$a.css({'opacity':'0.5'});
				if( typeof(base.options.navigationFormatter) == "function"){ // If a formatter function is present, use it
					$a.html(base.options.navigationFormatter(index, $(this)));
				} else {
			//	$a.text(index);
				}
				if (base.options.fades){
					$a.hover(function(){					
						$(this).fadeTo(200,1);
						}, function(){
						$(this).not('.cur').fadeTo(200,0.5);
					});
				}
				$a.click(function(e){
				   base.gotoPage(index);
				if (base.options.hashTags) base.setHash('panel-' + index);
					e.preventDefault();
				});
			//	base.$nav.append($a);
			});
			base.$navLinks = base.$nav.find('> a');
		};
				
		base.buildPrevNextButtons = function(){ // Creates the Forward/Backward buttons
			var $prevnext = $('<div id="prevnext"></div>').prependTo(base.$el);
			var $next = $('<a class="next">Next</a>').appendTo($prevnext);
			var	$prev = $('<a class="prev">Prev</a>').appendTo($prevnext);
			
			var	$clearer = $('#prevnext a'); // sets up clearing the hover queue for next and prev "links"
			$clearer.click(function(){
				$(this).hide();
				$('#slidearrows').hide();
			});
			if (base.options.continuous){
				$prev.hover(function(e){ // Bind to the forward and back buttons
					base.options.animationTime = base.options.animationTime - 10000;
					e.preventDefault();
				},function(e){
					base.options.animationTime = base.options.animationTime + 10000;
					e.preventDefault();
				});
				$next.hover(function(e){
					base.options.animationTime = base.options.animationTime - 10000;
					e.preventDefault();
				},function(e){
					base.options.animationTime = base.options.animationTime + 10000;
					e.preventDefault();
				});
			}
			$prev.click(function(e){ // Bind to the forward and back buttons
				base.goBack();
			//	e.preventDefault();
            });
            $next.click(function(e){
				base.goForward();
			//	e.preventDefault();
            });
			if(base.options.fades){
				$next.hover(function(){
					base.$items.filter(':eq('+(base.currentPage+2)+')').fadeTo(200,1);
					$('#slidearrows .arrowright').fadeTo(200,1);
				}, function(){
					base.$items.filter(':eq('+(base.currentPage+2)+')').not('.current').fadeTo(200,0.5);
					$('#slidearrows .arrowright').fadeTo(200,0);
				});
				$prev.hover(function(){
					base.$items.filter(':eq('+(base.currentPage)+')').fadeTo(200,1);
					$('#slidearrows .arrowleft').fadeTo(200,1);
					}, function(){
					base.$items.filter(':eq('+(base.currentPage)+')').not('.current').fadeTo(200,0.5);
					$('#slidearrows .arrowleft').fadeTo(200,0);
				});
			}
		};
		
		base.buildAutoPlay = function(){ // Creates the Start/Stop button
			base.$startStop = $("<a href='#' id='start-stop'></a>").html(base.playing ? base.options.stopText : base.options.startText);
			if(!base.options.startButton) base.$startStop.hide(); // Hide the start/stop button if not requested
			base.$el.append(base.$startStop); // Insert the start/stop into the DOM            
			base.$startStop.click(function(e){
				base.startStop(!base.playing);
				e.preventDefault();
			});
			base.startStop(base.playing); // Use the same setting, but trigger the start;
		};
		
		base.startStop = function(playing){
			if(playing !== true) playing = false; // Default if not supplied is false
			base.playing = playing; // Update variable
			if(base.options.autoPlay) base.$startStop.toggleClass("playing", playing).html( playing ? base.options.stopText : base.options.startText ); // Toggle playing and text
			if(playing){
				base.clearTimer(); // Just in case this was triggered twice in a row
				base.timer = window.setInterval(function(){
					base.goForward(true);
				}, base.options.continuous ? base.continuousDelay : base.options.delay);
			} else {
				base.clearTimer();
			};
		};
		
		base.clearTimer = function(){
			if(base.timer) window.clearInterval(base.timer); // Clear the timer only if it is set
		};
		
		base.setHash = function(hash){ // Taken from AJAXY jquery.history Plugin
			if (typeof window.location.hash !== 'undefined'){ // Write hash
				if (window.location.hash !== hash){
					window.location.hash = hash;
				};
			} else if (location.hash !== hash){
				location.hash = hash;
			};
			return hash; // Done
		}; // <-- End AJAXY code
		
		base.init(); // Trigger the initialization
   };

	$.infiniteSlider.defaults = {
		easing: "swing",                // Anything other than "linear" or "swing" requires the easing plugin
		autoPlay: true,                 // This turns off the entire FUNCTIONALY, not just if it starts running or not
		continuous: false,				// Scroller will continuously scroll without stop
		startButton: true,				// true displays the start/stop button; false hides it
		startStopped: false,            // If autoPlay is on, this can force it to start stopped
		delay: 3000,                    // How long between slide transitions in AutoPlay mode
		animationTime: 600,             // How long the slide transition takes
		hashTags: true,                 // Should links change the hashtag in the URL?
		buildNavigation: true,          // If true, builds and list of anchor links to link to each slide
		buildPrevNext: true,			// If true, includes a <div> with id 'prevnext' containing anchors with classes 'next' and 'prev'
		pauseOnHover: true,             // If true, and autoPlay is enabled, the show will pause on hover
		startText: "Start",             // Start text
		stopText: "Stop",               // Stop text
		navigationFormatter: null,      // Details at the top of the file on this use (advanced use)
		offset: 0,						// Sets the offset value of the left side of the ul in px (can be negative)
		rollin: false,						  // Makes the slider panels "slide" into place at load
		fades: false,						  // Creates a fade in/out effect on panels as they become "active"
		fadein: 1,							  // 'fades' option must be true to set fadein / fadeout values
		fadeout: 0.5						  // Opacity value when item fades out
//TODO^
	};
	
   $.fn.infiniteSlider = function(options){
		if(typeof(options) == "object"){
			return this.each(function(i){			
				(new $.infiniteSlider(this, options)); // This plugin supports multiple instances, but only one can support hash-tag support
				options.hashTags = false; // This disables hash-tags on all items but the first one
	      });	
		} else if (typeof(options) == "number") {
			return this.each(function(i){
				var anySlide = $(this).data('infiniteSlider');
				if(anySlide){
					anySlide.gotoPage(options);
				}
			});
		}
   };
	
})(jQuery);
