(function($){

$.fn.carousel = function(command, options) {
	return this.each(function() {
		if (typeof command == 'object') {
			options = command;
			command = 'init';
		} else if (options === undefined) {
			options = {};
		}
		
		if (command != 'init' && typeof $(this).data('carousel') == 'undefined') {
			return false;
		}
		
		$.carousel[command]($(this), options);
	});
};

$.carousel = {
	defaults: {
		params: {},
		duration: 10,
		easing: 'linear',
		callback: false,
		prev: null,
		next: null
	},
	
	init: function($this, options) {
		var options = $.extend(true, {}, $.carousel.defaults, options);
		
		// Setup basic settings
		$this.show();
		
		var items = $this.find('>*');
		var width = 0;
		items.each(function() {
			width += $(this).outerWidth(true);
		});
		options.totalWidth = width;
		
		if (options.width + 10 > options.totalWidth) {
			return;
		}
		
		// Carousel Content & Content wrapper
		$this.wrap('<div class="carousel-wrap"><div class="carousel-wrap-content"></div></div>');
		$this.parent().parent()
			.css({overflow: 'hidden', position: 'relative'})
			.width(options.width)
			.height(items.eq(0).outerHeight(true));
		$this.parent().css({position: 'absolute'});
		$this.parent().width(options.totalWidth * 2);
		$this.clone().insertAfter($this);
		
		$this.data('carousel', options);
		$this.data('carousel.started', true);
		
		$.carousel.bind($this);		
		// Prev
		if (options.prev != null) {
			$.carousel.bind($this, options.prev, 'right');
		}
		// Next
		if (options.next != null) {
			$.carousel.bind($this, options.next, 'left');
		}
		
		$.carousel.move($this);
	},
	
	toggle: function($this) {
		var options = $this.data('carousel');
		if (options.width + 10 > options.totalWidth) {
			return;
		}
		
		if ($this.data('carousel.started')) {
			$this.parent().stop();
		} else {
			$.carousel.move($this);
		}
		
		$this.data('carousel.started', !$this.data('carousel.started'));
	},
	
	bind: function($this, dom, direction) {
		if (typeof dom != 'undefined') {
			$(dom).bind('click', function(e) {
				var options = $this.data('carousel');
				var $real = $this.parent();
				if (options.width + 10 > options.totalWidth) {
					return;
				}
				
				$this.data('carousel.started', false);
				$real.stop();
				
				var cssLeft = 0 - parseInt($real.css('left'));
				if (isNaN(cssLeft)) {
					cssLeft = 0;
				}
				
				var totalWidth = 0;
				var found = false;
				$this.find('>*').each(function() {
					if (found) {
						return;
					}
					
					var width = $(this).outerWidth(true);
					if (totalWidth + width >= cssLeft) {
						found = true;
						if (direction == 'right') {
							return;
						}
						
						if (cssLeft > 0) {
							totalWidth += $(this).next().outerWidth(true);
						}
					}
					totalWidth += width;
				});
				
				if (totalWidth == 0) {
					$real.css('left', 0 - options.totalWidth);
				} else if (totalWidth >= options.totalWidth) {
					$real.css('left', 0);
				} else {
					$real.css('left', 0 - totalWidth);
				}
			});
		} else {
			$this.parent().hover(function(e) {
				var options = $this.data('carousel');
				if (options.width + 10 > options.totalWidth) {
					return;
				}
				
				if ($this.data('carousel.started')) {
					$this.parent().stop();
				}
			}, function(e) {
				var options = $this.data('carousel');
				if (options.width + 10 > options.totalWidth) {
					return;
				}
				
				if ($this.data('carousel.started')) {
					$.carousel.move($this);
				}
			});
		}
	},
	
	move: function($this) {
		var options = $this.data('carousel');
		var $real = $this.parent();
		
		var left = options.totalWidth;
		var cssLeft = parseFloat($real.css('left'));
		if (isNaN(cssLeft)) {
			cssLeft = 0;
		}
		var duration = (options.totalWidth + cssLeft) * options.duration;

		// Get animate settings
		options.params.left = -left;
		
		// Lets animate it
		$real.animate(options.params, duration, options.easing, function() {
			// Restart it
			$real.css('left', 0);
			$.carousel.move($this);
			
			// Call the callback
			if (typeof options.callback == 'function') {
				options.callback.apply($this);
			}
		});
	}
};

})(jQuery);