/**

 * jQuery.serialScroll

 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com

 * Dual licensed under MIT and GPL.

 * Date: 3/1/2008

 *

 * @projectDescription Animated scrolling of series.

 * @author Ariel Flesler

 * @version 1.1.0

 *

 * @id jQuery.serialScroll

 * @id jQuery.fn.serialScroll

 * @param {Object} settings Hash of settings, it is passed in to jQuery.ScrollTo, none is required.

 * @return {jQuery} Returns the same jQuery object, for chaining.

 *

 * http://flesler.blogspot.com/2008/02/jqueryserialscroll.html

 *

 * Notes:

 *	- The plugin requires jQuery.ScrollTo.

 *	- The hash of settings, is passed to jQuery.ScrollTo, so its settings can be used as well.

 */

;(function( $ ){



	var $serialScroll = $.serialScroll = function( settings ){

		$.scrollTo.window().serialScroll( settings );

	};



	//Many of these defaults, belong to jQuery.ScrollTo, check it's demo for an example of each option.

	//@see http://www.flesler.webs/jQuery.ScrollTo/

	$serialScroll.defaults = {//the defaults are public and can be overriden.

		duration:1000, //how long to animate.

		axis:'x', //which of top and left should be scrolled

		event:'click', //on which event to react.

		start:0, //first element (zero-based index)

		step:1, //how many elements to scroll on each action

		lock:true,//ignore events if already animating

		cycle:true //cycle endlessly ( constant velocity )

		/*

		interval:0, //it's the number of milliseconds to automatically go to the next

		lazy:false,//go find the elements each time (allows AJAX or JS content, or reordering)

		stop:false, //stop any previous animations to avoid queueing

		force:false,//force the scroll to the first element on start ?

		jump: false,//if true, when the event is triggered on an element, the pane scrolls to it

		items:null, //selector to the items (relative to the matched elements)

		prev:null, //selector to the 'prev' button

		next:null, //selector to the 'next' button

		onBefore: //function called before scrolling, if it returns false, the event is ignored

		*/		

	};



	$.fn.serialScroll = function( settings ){

		settings = $.extend( {}, $serialScroll.defaults, settings );

		var event = settings.event, //this one is just to get shorter code when compressed

			step = settings.step, // idem

			duration = settings.duration / step; //save it, we'll need it



		return this.each(function(){

			var 

				$pane = $(this),

				items = settings.lazy ? settings.items : $( settings.items, $pane ),

				actual = settings.start,

				timer; //for the interval



			if( settings.force )

				jump.call( this, {}, actual );//generate an initial call



			// Button binding, optional

			$(settings.prev||[]).bind( event, -step, move );

			$(settings.next||[]).bind( event, step, move );

			

			// Custom events bound to the container

			$pane.bind('prev.serialScroll', -step, move ) //you can trigger with just 'prev'

				 .bind('next.serialScroll', step, move ) //for example: $(container).trigger('next');

				 .bind('goto.serialScroll', jump ); //for example: $(container).trigger('goto', [4] );



			if( !settings.lazy && settings.jump )//can't use jump if using lazy items

				items.bind( event, function( e ){

					e.data = items.index(this);

					jump( e, this );

				});



			function move( e ){

				e.data += actual;

				jump( e, this );

			};			

			function jump( e, button ){

				if( typeof button == 'number' ){//initial or special call from the outside $(container).trigger('goto',[index]);

					e.data = button;

					button = this;

				}



				var 

					pos = e.data, elem,

					real = e.type, //is a real event triggering ?

					$items = $(items,$pane),

					limit = $items.length;



				if( real )//real event object

					e.preventDefault();



				pos %= limit; //keep it under the limit

				if( pos < 0 )

					pos += limit;



				elem = $items[pos];



				if( settings.interval ){

					clearTimeout(timer);//clear any possible automatic scrolling.

					timer = setTimeout(function(){ $pane.trigger('next.serialScroll'); }, settings.interval ); //I'll use the namespace to avoid conflicts

				}



				if( isNaN(pos) || real && actual == pos || //could happen, save some CPU cycles in vain

					settings.lock && $pane.is(':animated') || //no animations while busy

					!settings.cycle && !$items[e.data] || //no cycling

					real && settings.onBefore && //callback returns false ?

				 	settings.onBefore.call(button, e, elem, $pane, $items, pos) === false ) return;



				if( settings.stop )

					$pane.queue('fx',[]).stop();//remove all its animations



				settings.duration = duration * Math.abs( actual - pos );//keep constant velocity

				$pane.scrollTo( elem, settings );

				actual = pos;

			};

		});

	};



})( jQuery );
