/*!
 * jQuery Plugin
 * spot-media carusel
 *
 * Copyright 2011, spot media
 * Author: Mathias Nitzsche
 *
 * Date: Tue Mai 17 12:00:00 2011 +0100
 */
(function ($) {
	var methods = {
		// init carusel on <ul> or <ol>
		init : function (options) {
			return this.each(function () {
				var $this = $(this), data = $this.data('spotCarusel');
				// assure that init is only performed once, even if called multiple times
				if (!data) {
					// change left and right invisible to numbers in styles array
					var stylesArray = [];
					$.each(options.styles, function (key, value) {
						if (key === "leftinvisible") { key = "0"; }
						if (key === "rightinvisible") { key = stylesArray.length.toString(); }
						stylesArray[key] = value;
					});

					// only proceed if styles are defined
					if (stylesArray.length) {
						// create carusel data
						$this.data('spotCarusel', {
							'onInitialized' : (options.onInitialized ? options.onInitialized : function () {}),
							'animationsInProgress' : 0,
							'itemsAnimationStarted' : 0,
							'target' : $this,
							'itemsCount' : $this.children('li').length,
							'startPos' : (options.startPos ? options.startPos * -1 + 1 : 1),
							'styles' : stylesArray,
							'duration' : (options.duration ? options.duration : 500),
							'durationForStartAnimation' : (options.durationForStartAnimation !== null ? options.durationForStartAnimation : 500)
						});

						// assign click listeners to left and right button
						$(options.leftButton).click(function () { methods.slide.apply($this, ["left"]); });
						$(options.rightButton).click(function () { methods.slide.apply($this, ["right"]); });

						// initially apply styles to all list items
						methods.updateStyle.apply(this);
					}
				}
				delete $this;
				delete data;
			});
		},
		// update styles of list items according to the current data.startPos
		updateStyle : function () {
			// preload/calculate(alocate stuff to increase performance
			var $this = $(this),
				data = $this.data('spotCarusel'),
				animationConfig = null,
				lis = data.target.children('li'),
				lisCount = lis.size(),
				duration = (data.itemsAnimationStarted < lisCount ? data.durationForStartAnimation : data.duration),
				thisDuration = 0;

			// iterate over all list items
			lis.each(function (index, element) {
				element = $(element);
				// elements is a subset, representing all children and self
				var elements = element.find("*").andSelf();
				// calculate index of first item
				index = (data.startPos + index + data.itemsCount * 100) % data.itemsCount;

				// iterate over all selectors for current list item
				if (index < data.styles.length || data.itemsAnimationStarted <= lisCount) {
					// counter to check when initialization is done
					data.itemsAnimationStarted++;

					// assure that no index is greater then dataStyles length (important on init);
					index = Math.min(data.styles.length - 1, index);

					// dirty little helper to prevent elements flying through the screen
					thisDuration = (element.attr("index") == data.styles.length - 1 && index == 0 ||
									data.itemsAnimationStarted < lisCount && index == 0 ? 0 : duration);

					$.each(data.styles[index], function (selector, style) {
						// count active animations - to be ably to stop further events until animation is finished
						data.animationsInProgress++;
						animationConfig = {'duration' : thisDuration, 'complete' : function () {
							data.animationsInProgress--;

							// after all animations are done
							if (data.animationsInProgress === 0 && data.itemsAnimationStarted === lisCount) {
								// check if a callback was defined
								if (typeof data.onInitialized === "function") {
									var save = data.onInitialized;
									data.onInitialized = null;
									save.apply($this);
								}
							}
						}};
						// start animation to new css styles
						elements.filter(selector).animate(style, animationConfig);
					});

					element.attr("index", index);
				}

				delete elements;
			});
			// stupid try to help saving memory
			delete $this;
			delete data;
			delete animationConfig;
			delete lis;
			delete lisCount;
			delete duration;
			delete thisDuration;
		},
		// handler for left and right buttons
		slide : function (direction) {
			var $this = $(this), data = $this.data('spotCarusel');

			// only allow movment if current animation is finished
			if (!data.animationsInProgress) {
				data.startPos += (direction === "left" ? -1 : 1);
				methods.updateStyle.apply(this);
			}
			delete $this;
			delete data;
		}
	};

	// register spotCarusel in jquery namespace - make $(..).spotCarusel() possible
	$.fn.spotCarusel = function (methodName) {
		if (methodName === "slideLeft") {
			methods.slide.apply(this, ["left"]);
		} else if (methodName === "slideRight") {
			methods.slide.apply(this, ["right"]);
		} else if (typeof methodName === 'object' || !methodName) {
			return methods.init.apply(this, arguments);
		}
		// for method chaining return this
		return this;
	};
})(jQuery);

