/*
 * A simple carousel with the ability to load new elements via AJAX.
 *
 * This implementation borrowed a lot of code from jCarouselLite.
 *   http://www.gmarwaha.com/jquery/jcarousellite/
 *
 * Version 0.3 :: 2008-11-20
 * Copyright (C) 2008 Judd Vinet <jvinet@zeroflux.org>
 */

(function($) {
	$.fn.Carousel = function(o) {
		this.each(function(){
			new $.carousel(this, o);
		});
	};

	var defaults = {
		btnPrev: null,
		btnNext: null,
		speed: 200,       // msecs to transition to new slide
		auto: 0,          // msecs to auto-move to new slide (0 to disable)
		numVisible: 1,    // number of slides to show at one time
		vertical: false,
		circular: false,
		itemCallback: null
	};

	/**
	 * The object.
	 */
	$.carousel = function(e, o) {
		var self = this;

		this.o = $.extend({}, defaults, o || {});

		this.animProp = this.o.vertical ? "top" : "left";
		this.sizeProp = this.o.vertical ? "height" : "width";
		this.currentIdx = 0;

		this.div = $(e);
		this.ul = $("ul", this.div);
		this.li = $("li", this.ul);

		this.li.css({ overflow: "hidden", float: this.o.vertical ? "none" : "left" });
		this.ul.css({ margin: "0", padding: "0", position: "relative", "list-style-type": "none", "z-index": "1" });
		this.div.css({ overflow: "hidden", position: "relative", "z-index": "2", left: "0px" });

		if(this.o.btnPrev) {
			$(this.o.btnPrev).click(function() {
				self.go(self.currentIdx - 1, self.currentIdx);
				return false;
			});
		}
		if(this.o.btnNext) {
			$(this.o.btnNext).click(function() {
				self.go(self.currentIdx + 1, self.currentIdx);
				return false;
			});
		}

		/*
		 * Auto-move timer
		 */
		this.auto_move = function() {
			self.go(self.currentIdx + 1, self.currentIdx);
		}
		if(this.o.auto > 0) {
			setInterval(this.auto_move, this.o.auto);
		}

		/**
		 * Object methods
		 */

		/**
		 * Calculate the dimensions for the div/li/ul tags
		 */
		this.calc_dims = function() {
			var self = this;
			// make all <li> elements as wide/tall as the widest/tallest one
			this.liSize = 0;
			this.li.each(function(i) {
				if(self.o.vertical) {
					if($(this).height() > self.liSize) self.liSize = $(this).height();
				} else {
					if($(this).width() > self.liSize) self.liSize = $(this).width();
				}
			});
			this.ulSize = this.liSize * this.li.size();
			this.divSize = this.liSize * this.o.numVisible;

			this.li.css(this.sizeProp, this.liSize+"px");
			this.ul.css(this.sizeProp, this.ulSize+"px").css(this.animProp, "0px");
			this.div.css(this.sizeProp, this.divSize+"px");
		};

		/**
		 * Move to a different element
		 */
		this.go = function(idx, oldidx) {
			var oldidx = oldidx || this.currentIdx;
			if(idx < 0) {
				// out of elements on the left side - execute the callback
				// for more items
				if(this.o.itemCallback) {
					this.o.itemCallback(this, idx, oldidx);
				} else if(o.circular) {
					this.currentIdx = this.li.size()-1;
					this.ul.animate(this.animProp == "left" ? {left: -(this.currentIdx*this.liSize)} : {top: -(this.currentIdx*this.liSize)}, this.o.speed, null);
				} else {
					return this.bump('right');
				}
			} else {
				if(idx > this.li.size()-this.o.numVisible) {
					// out of elements on the right side - execute the callback
					// for more items
					if(this.o.itemCallback) {
						this.o.itemCallback(this, idx, oldidx);
					} else if(o.circular) {
						this.currentIdx = 0;
						this.ul.animate(this.animProp == "left" ? {left: -(this.currentIdx*this.liSize)} : {top: -(this.currentIdx*this.liSize)}, this.o.speed, null);
					} else {
						return this.bump('left');
					}
				} else {
					// more elements available - move to the next (right or left)
					this.currentIdx = idx;
					this.ul.animate(this.animProp == "left" ? {left: -(this.currentIdx*this.liSize)} : {top: -(this.currentIdx*this.liSize)}, this.o.speed, null);
				}
			}
		};

		/**
		 * Add a new element
		 */
		this.add = function(html) {
			// extend the list with a new element
			this.ul.append('<li>'+html+'</li>');
			this.li = $("li", this.ul);
			this.li.css({ overflow: "hidden", float: this.o.vertical ? "none" : "left" });

			this.calc_dims();
		};

		/**
		 * "Bump" the current panel to indicate that no more panels
		 * are available.
		 */
		this.bump = function(dir) {
			var self = this;
			var space = dir == 'left' ? 20 : -20;
			this.ul.animate(this.animProp == "left" ? {left: -(this.currentIdx*this.liSize)-space} : {top: -(this.currentIdx*this.liSize)-space}, this.o.speed, null,
				function(){
					self.ul.animate(self.animProp == "left" ? {left: -(self.currentIdx*self.liSize)} : {top: -(self.currentIdx*self.liSize)}, self.o.speed, null);
				});
		};

		this.calc_dims();
	};

})(jQuery);

