(function($) {
	$.fn.carousel = function(options) {
		
		function repeat(str, num) {
			return new Array(num + 1).join(str);
		}
		
		var defaults = {
			visible		: 3, 
			direction	: 'top'
		};
		
		var options = $.extend(defaults, options);

		return this.each(function() {
			
			var $wrapper		= $('> div', this).css('overflow', 'hidden'), 
				$slider			= $wrapper.find('> ul'), 
				$items			= $slider.find('> li'), 
				$single			= $items.filter(':first'), 
				
				singleWidth		= $single.outerWidth(), 
				singleHeight	= $single.outerHeight(), 
				visible			= options.visible, 
				currentPage		= 1, 
				pages			= Math.ceil($items.length);
			
			var pad;
			if(options.direction == 'top') {
				pad = (($wrapper.height() - singleHeight) / visible) / Math.floor(visible);
				$items.css('margin', pad+'px 0 -'+pad+'px 0');
			} else {
				pad = (($wrapper.width() - singleWidth) / 2) / Math.floor(visible);
				$items.css('margin', '0 -'+pad+'px 0 '+pad+'px');
			}
			
			// Top and tail the list with 'visible' number of items, top has the last section, and tail has the first
			$items.filter(':first').before($items.slice(- visible).clone().addClass('cloned'));
			$items.filter(':last').after($items.slice(0, visible).clone().addClass('cloned'));
			$items = $slider.find('> li');
			
			// Initial states
			$('li:eq(' + (Math.floor(visible) - 1) + ')', this).addClass('active');
			$('li:eq(' + (Math.floor(visible) - 3) + ')', this).addClass('prev');
			$('li:eq(' + (Math.floor(visible) + 1) + ')', this).addClass('next');
			
	        // Set the left position to the first 'real' item
			if(options.direction == 'top') {
				$wrapper.scrollTop(singleHeight);
			}
			else if(options.direction == 'left') {
				$wrapper.scrollLeft(singleWidth);
			}
			
			// Paging
			function gotoPage(page) {

				var dir		= page < currentPage ? -1 : 1;
	                n		= Math.abs(currentPage - page);
					ori		= options.direction == 'top' ? singleHeight : singleWidth;
					next	= $slider.find('.active');
					nextn	= $slider.find('.active').next().next().next();
					nextp	= $slider.find('.active').prev();
				
				// Remove all classes
				$items.removeClass('active');
				$items.removeClass('next');
				$items.removeClass('prev');
				
				// Apply classes
				if(next.next().hasClass('cloned'))
				{
					var first = $slider.find('li[class=""]:first');
					first.addClass('active');
					nextn.addClass('next');
					nextp.addClass('prev');
				}
				else
				{
					next.next().addClass('active');
					nextn.addClass('next');
					nextp.addClass('prev');
				}
				
				if(options.direction == 'top') {
					$wrapper.filter(':not(:animated)').animate({
						scrollTop : '+=' + ori
		            }, 500, function() {
						if(page == 0)
						{
							$wrapper.scrollTop(singleHeight);
							page = pages;
		                }
						else if(page > pages)
						{
							$wrapper.scrollTop(singleHeight);
							page = 1;

							// Apply classes
							$('li:eq(' + (Math.floor(visible) - 1) + ')', this).addClass('active');
							$('li:eq(' + (Math.floor(visible) - 3) + ')', this).addClass('prev');
							$('li:eq(' + (Math.floor(visible) + 1) + ')', this).addClass('next');
						} 
						currentPage = page;
					});
				} else {
					$wrapper.filter(':not(:animated)').animate({
						scrollLeft : '+=' + ori
		            }, 500, function() {
						if(page == 0)
						{
							$wrapper.scrollLeft(singleWidth);
							page = pages;
		                }
						else if(page > pages)
						{
							$wrapper.scrollLeft(singleWidth);
							page = 1;

							// Apply classes
							$('li:eq(' + (Math.floor(visible) - 1) + ')', this).addClass('active');
							$('li:eq(' + (Math.floor(visible) - 3) + ')', this).addClass('prev');
							$('li:eq(' + (Math.floor(visible) + 1) + ')', this).addClass('next');
						} 
						currentPage = page;
					});
				}

				return false;
			}
			
			// Repeat
			$(this).bind('next', function() {
				gotoPage(currentPage + 1);
			});
			
		});

	};

})(jQuery);
