/**
 * 
 * NOTE: the carousel arguemnt is always the UL-list
 */
var VAL = window.VAL || {};
(function($) {
				
	VAL.CarouselMethods = (function() {
		
		var uniqueInstance;
		
		// Buld a index based navigation and
		// appends it to the carousel.
		function buildNavigation(carousel) {
			
			var options = carousel.data('options');
			var props = carousel.data('props');
			
			var $container = $('<div></div>').addClass('carousel-nav');
			var $ul = $('<ul></ul>');
			var i = 0;
			
			while(props.slideCount !== i) {
				var $li = $('<li></li>');
				var $a = $('<a></a>').attr('href', '#').append($('<span></span>').html(i+1)).click((function(i) {
					return function() {
						Move.byIndex(carousel, i+1);
						Controls.pause(carousel);
						return false;
					};
				})(i));
				$li.append($a).appendTo($ul);
				i++;
			}
			
			var $prev = $('<li></li>').html($('<a></a>').attr('href', '#').append($('<span>&nbsp;</span>')).addClass('prev')).click(function() {
				Move.prev(carousel);
				Controls.pause(carousel);
				return false;
			});
			var $next = $('<li></li>').html($('<a></a>').attr('href', '#').append($('<span>&nbsp;</span>')).addClass('next')).click(function() {
				Move.next(carousel);
				Controls.pause(carousel);
				return false;
			});
			$ul.find('li').eq(0).addClass('current');
			$prev.prependTo($ul);
			$next.appendTo($ul);
			$ul.hide();
			$container.append($ul.fadeIn('slow')).insertAfter(carousel.closest('div'));
		}
		
		// Set the active index in the index based navigation
		function setActiveIndex(carousel, props, index) {
			var nav = carousel.closest('div').next('div');
			if(typeof index === 'undefined') {
				index = Math.round(Math.abs(carousel.position().left / props.slideWidth));
			}
			nav.find('li').eq(index).addClass('current').siblings().removeClass();
		}
		
		// This function pads the carousel with
		// slides to the left and right to enable
		// the carousel to rotate in infinity.
		function padCarouselSlides(carousel) {
			carousel.find('li:last').clone(true).prependTo(carousel);
		}
		
		// Are we at the end?
		function isEnd(carousel, props) {
			// left variable is a fix since position().left isn't returned correctly in Internet Explorer 8
			var left = Math.abs(parseInt(carousel.css('left').replace('px', '')));
			var totalWidth = props.carouselInitWidth;
			return left === totalWidth;
		}
		
		// Are we in the beginning?
		function isBeginning(carousel) {
			// left variable is a fix since position().left isn't returned correctly in Internet Explorer 8
			var left = Math.abs(parseInt(carousel.css('left').replace('px', '')));
			return left === 0;
		}
		
		// Move the carousel
		var Move = {
			// Move the carousel to the left
			isAnimating: false,
			prev: function(carousel) {
				
				if (!Move.isAnimating) {
					Move.isAnimating = true;
					var options = carousel.data('options');
					var props = carousel.data('props');
					
					if (isBeginning(carousel)) {
						carousel.css({
							left: '-' + props.carouselInitWidth + 'px'
						});
					}
					carousel.animate({
						left: '+=' + props.slideWidth
					}, options.animationSpeed, options.easing, function() {
						if (isBeginning(carousel)) {
							carousel.css({
								left: '-' + props.carouselInitWidth + 'px'
							});
						}
						setActiveIndex(carousel, props);
						Move.isAnimating = false;
					});
				}
				
			},
			// Move the carousel to the right
			next: function(carousel) {
				
				if (!Move.isAnimating) {
					Move.isAnimating = true;
					var options = carousel.data('options');
					var props = carousel.data('props');
					
					if (isEnd(carousel, props)) {
						carousel.css({
							left: 0
						});
					}

					carousel.animate({
						left: '-=' + props.slideWidth
					}, options.animationSpeed, options.easing, function(){
						if (isEnd(carousel, props)) {
							carousel.css({
								left: '-' + props.carouselInitWidth + 'px'
							});
						}
						setActiveIndex(carousel, props);
						Move.isAnimating = false;
					});
				}
			},
			// Move the carousel to a defined index
			byIndex: function(carousel, index) {
				
				var props = carousel.data('props');
				var options = carousel.data('options');

				carousel.animate({
					left: '-' + props.slideWidth * index + 'px'
				}, options.animationSpeed, options.easing, function() {
					setActiveIndex(carousel, props, index);
				});
				
			}
		};
		
		// Playing and pausing the carousel
		var Controls = {
			play: function(carousel) {
				carousel.data('props').intervalVariable = setInterval(function() {
					Move.next(carousel);
				}, carousel.data('options').autoPlayInterval);
			},
			pause: function(carousel) {
				clearInterval(carousel.data('props').intervalVariable);
			}
		};
		
		
		function constructor() {
			return {
				init: function(carousel, options, props) {
					
					// Attach the options and utility properties to the carousel
					carousel.data('options', options);
					carousel.data('props', props);
					
					// Pad to enable an endless loop
					padCarouselSlides(carousel);
					
					// Build the navigation
					if (options.buildNavigation) {
						buildNavigation(carousel);
					}
					
					// Initially positions the carousel to the second slide, which is the first :)
					carousel.css({
						left: '-' + props.slideWidth + 'px',
						width: (carousel.find('li').size() * props.slideWidth) + 'px'
					}).addClass('carousel-list');
					
					if(options.autoPlay) {
						Controls.play(carousel);
					}
				},
				play: Controls.play,
				pause: Controls.pause,
				next: Move.next,
				prev: Move.prev
			};
		}
		
		return {
			getInstance: function() {
				if(!uniqueInstance) {
					uniqueInstance = constructor();
				}
				return uniqueInstance;
			}
		};
		
	})();


	
	$.fn.carousel = function(settings) {
		// Overrideable options
		var options = $.extend({
			animationSpeed: 400,
			autoPlay: false,
			autoPlayInterval: 5000,
			buildNavigation: true,
			easing: null
		}, settings);
		
		// Utility properties
		var props = {
			slideWidth: 0,
			carouselInitWidth: 0,
			slideCount: 0,
			intervalVariable: null
		};
		
		return this.each(function() {
			$(this).wrap($('<div></div>').addClass('carousel-container'));
			props.slideWidth = $(this).width();
			props.slideCount = $(this).find('li').size();
			props.carouselInitWidth = props.slideCount * props.slideWidth;
			VAL.CarouselMethods.getInstance().init($(this).find('ul:eq(0)'), options, props);
		});
	};
	
})(jQuery);



