/**
 * xCarousel jQuery carousel plugin made by Alex Shustov
 * The progenitor of this plugin was bxSlider plugin made by Steven Wanderski (http://bxslider.com)
 *
 * Released under the GPL license: http://www.gnu.org/licenses/gpl.html
 * Features:
 * - numeric or graphic pager
 * - prev/next buttons
 * - ability to show and scroll any amount of frames at a time
 * - any direction sliding animation
 * - auto scrolling
 *
 * v 1.0
 */
(function($){
	$.fn.xCarousel=function(options) {
		var defaults={
			speed:500,			// animation speed
			start:0,			// initially selected frame
			interval:2000,		// interval between animations
			direction:'left',	// left, right, top, bottom
			scroll:1,			// number of frames to scroll at a time
			auto:false,			// auto scroll
			pager:false,		// show pager
			arrows:false		// show forward backward buttons
		};

		var o=$.extend(defaults, options);
		return this.each(function(){
			var $this=$(this).addClass('xCarousel').wrapInner('<div/>');
			var $clip=$this.children().eq(0).addClass('clip').css({'overflow':'hidden', 'position':'relative', 'width':$this.width(), 'height':$this.height()});
			var $list=$clip.children().eq(0); // ul | ol
			var $frames=$list.children().addClass('frame'); // li
			var length=$frames.length; // total amount of frames
			var currentIndex=o.start;
			var winSize, width, height, timer, $pager;
			var upright=o.direction=='top' || o.direction=='bottom'; // vertical or horizontal orientation
			var preorder=o.direction=='left' || o.direction=='top'; // straight or reverse order

			if(upright){
				height=$frames.eq(currentIndex).outerHeight(true);
				winSize=Math.ceil($clip.height()/height);
				rewindIndex(currentIndex); // rewinds index if there is no place for the next iteration
				$list.css({'position':'relative', 'top':-(currentIndex+winSize)*height, 'height':height*(length+2*winSize)});
			}else{
				width=$frames.eq(currentIndex).outerWidth(true);
				winSize=Math.ceil($clip.width()/width);
				rewindIndex(currentIndex); // rewinds index if there is no place for the next iteration
				$frames.css({'float':'left'});
				$list.css({'position':'relative', 'left':-(currentIndex+winSize)*width, 'width':width*(length+2*winSize)});
			}

			// appending/prepending winSize cloned frames
			$list.append($frames.slice(0, winSize).clone()).prepend($frames.slice(-winSize).clone());

			// arrows control
			if(o.arrows){
				$this.append($('<a/>').addClass('prev').attr('href', '#prev').click(function(event){
					if(!$list.is(':animated'))
						nextFrame(currentIndex-o.scroll);
					event.preventDefault();
				}));
				$this.append($('<a/>').addClass('next').attr('href', '#next').click(function(event){
					if(!$list.is(':animated'))
						nextFrame(currentIndex+o.scroll);
					event.preventDefault();
				}));
			}

			// pager control
			if(o.pager){
				var isGraphic=$list.is('ul');
				var $a;
				$pager=$('<div/>').addClass(isGraphic ? 'graphicPager' : 'numericPager').click(function(event){
					var $target=$(event.target);
					if($target.is('a')){
						nextFrame($target.attr('href').substring(1)-1);
						event.preventDefault();
					}
				});
				$frames.each(function(index){
					$a=isGraphic ? $('<a/>') : $('<a>'+(index+1)+'</a>');
					$a.attr('href', '#'+(index+1));
					$pager.append($a);
				});
				$this.append($pager);
				updatePager();
			}

			// auto rotation
			if(o.auto){
				timer=initTimer();
				$this.hover(function(){
					clearInterval(timer);
					timer=undefined;
				}, function(){
					if(timer==undefined)
						timer=initTimer();
				});
			}

			function updatePager(){
				var $links=$pager.children();
				$links.removeClass('active').eq(currentIndex).addClass('active');
			}

			function initTimer(){
				return setInterval(function(){
					nextFrame();
				}, o.interval);
			}

			function nextFrame(index){
				var params={};
				if(index!=undefined)
					currentIndex=index;
				else
					currentIndex=preorder ? currentIndex + o.scroll : currentIndex - o.scroll;
				$list.stop(); // stop current animation
				params[upright ? 'top' : 'left']=-(upright ? height : width)*(currentIndex+winSize);
				$list.animate(params, o.speed, 'linear', function(){
					if(rewindIndex())
						$list.css(upright ? 'top' : 'left', -(upright ? height : width)*(currentIndex+winSize));
					updatePager();
				});
			}

			// rewinds index if there is no place for next iteration
			function rewindIndex(){
				if(length-currentIndex < winSize){
					currentIndex-=length;
					return true;
				}else if(currentIndex < 0){
					currentIndex+=length;
					return true;
				}
				return false;
			}
		});
	};
})(jQuery)
