/* jQuery Carousel 0.9.5
Copyright 2008-2009 Thomas Lanciaux and Pierre Bertet.
This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>
*/
 (function($) {
	$.fn.carousel = function(options) {
		var params = $.extend({
			direction: "horizontal",
			blockType: "li",
			loop: false,
			dispItems: 1,
			pagination: false,
			paginationPosition: "inside",
			nextBtn: '<a href=\"#\" role="button">Next</a>',
			prevBtn: '<a href=\"#\" role="button">Previous</a>',
			btnsPosition: "inside",
			nextBtnInsert: "appendTo",
			prevBtnInsert: "prependTo",
			nextBtnInsertFn: false,
			prevBtnInsertFn: false,
			autoSlide: false,
			autoSlideInterval: 3000,
			delayAutoSlide: false,
			combinedClasses: false,
			effect: "slide",
			slideEasing: "swing",
			animSpeed: "normal",
			equalWidths: "true",
			verticalMargin: 0,
			callback: function() {},
			useAddress: true,
			addressIdentifier: "page",
			tabLabel: function(k) {
				return k;
			},
			showEmptyItems: true
		},
		options);
		if (params.btnsPosition == "outside") {
			params.prevBtnInsert = "insertBefore";
			params.nextBtnInsert = "insertAfter";
		}
		params.delayAutoSlide = params.delayAutoSlide || params.autoSlideInterval;
		return this.each(function() {
			
			// Env object
			var env = {
				$elts: {},
				params: params,
				launchOnLoad: []
			};
			
			// Carousel main container
			env.$elts.carousel = $(this).addClass("js");
			
			// Carousel content
			env.$elts.content = $(this).children().css({
				position: "absolute",
				top: 0
			});
			
			// Content wrapper
			env.$elts.wrap = env.$elts.content.wrap('<div class="carousel-wrap"></div>').parent().css({
				overflow: "hidden",
				position: "relative"
			});
			
			// env.steps object
			env.steps = {
				first: 0,
				count: env.$elts.content.children().length
			};
			
			// Last visible step
			env.steps.last = env.steps.count - 1;
			
			// Next / Prev Buttons
			if ($.isFunction(env.params.prevBtnInsertFn)) {
				env.$elts.prevBtn = env.params.prevBtnInsertFn(env.$elts);
			} else {
				env.$elts.prevBtn = $(params.prevBtn)[params.prevBtnInsert](env.$elts.carousel);
			}
			if ($.isFunction(env.params.nextBtnInsertFn)) {
				env.$elts.nextBtn = env.params.nextBtnInsertFn(env.$elts);
			} else {
				env.$elts.nextBtn = $(params.nextBtn)[params.nextBtnInsert](env.$elts.carousel);
			}
			env.$elts.nextBtn.addClass("carousel-control next carousel-next");
			env.$elts.prevBtn.addClass("carousel-control previous carousel-previous");
			
			// Bind events on next / prev buttons
			initButtonsEvents(env);
			
			// Pagination
			if (env.params.pagination) {
				initPagination(env);
			}
			initAddressPlugin(env);
			
			// On document+css load !
			$(function() {
				var n = env.$elts.content.children();
				var m = 0;
				
				n.each(function() {
					$itemHeight = $(this).outerHeight();
					if ($itemHeight > m) {
						m = $itemHeight;
					}
				});
				if (env.params.verticalMargin > 0) {
					m = m + env.params.verticalMargin;
				}
				n.height(m);
				
				// First item
				var $firstItem = env.$elts.content.children(":first");
				
				// Width 1/1 : Get default item width
				env.itemWidth = $firstItem.outerWidth();
				
				// Width 2/3 : Define content width
				if (params.direction == "vertical") {
					env.contentWidth = env.itemWidth;
				} else {
					if (params.equalWidths) {
						env.contentWidth = env.itemWidth * env.steps.count;
					} else {
						env.contentWidth = (function() {
							var totalWidth = 0;
							env.$elts.content.children().each(function() {
								totalWidth += $(this).outerWidth();
							});
							return totalWidth;
						})();
					}
				}
				
				// Width 3/3 : Set content width to container
				env.$elts.content.width(env.contentWidth);
				
				// Height 1/2 : Get default item height
				env.itemHeight = m;
				
				// Height 2/2 : Set content height to container
				if (params.direction == "vertical") {
					env.$elts.content.css({
						height: env.itemHeight * env.steps.count + "px"
					});
					env.$elts.content.parent().css({
						height: env.itemHeight * env.params.dispItems + "px"
					});
				} else {
					env.$elts.content.parent().css({
						height: env.itemHeight + "px"
					});
				}
				
				// Update Next / Prev buttons state
				updateButtonsState(env);
				
				// Launch function added to "document ready" event
				$.each(env.launchOnLoad, function(o, p) {
					p();
				});
				
				// Launch autoslide
				if (env.params.autoSlide) {
					window.setTimeout(function() {
						env.autoSlideInterval = window.setInterval(function() {
							changePage(env, shouldEnable(env, "next"));
						},
						env.params.autoSlideInterval);
					},
					env.params.delayAutoSlide);
				}
			});
		});
	};
	
	function initButtonsEvents(env) {
		env.$elts.nextBtn.add(env.$elts.prevBtn).bind("enable", 
		function() {
			var k = $(this).unbind("click").bind("click", 
			function() {
				changePage(env, shouldEnable(env, (k.is(".next") ? "next": "prev")));
				stopAutoslide(env);
				return false;
			}).removeClass("disabled");
			if (env.params.combinedClasses) {
				k.removeClass("next-disabled previous-disabled");
			}
		}).bind("disable", 
		function() {
			var k = $(this).unbind("click").addClass("disabled");
			if (env.params.combinedClasses) {
				if (k.is(".next")) {
					k.addClass("next-disabled");
				} else {
					if (k.is(".previous")) {
						k.addClass("previous-disabled");
					}
				}
			}
		}).hover(function() {
			$(this).toggleClass("hover");
		});
	}
	
	function initPagination(env) {
		env.$elts.pagination = $('<div class="center-wrap"><ol class="carousel-pagination"></ol></div>')[((env.params.paginationPosition == "outside") ? "insertAfter": "appendTo")](env.$elts.carousel).find("ol");
		env.$elts.paginationBtns = $([]);
		env.$elts.content.find(env.params.blockType).each(function(k) {
			if (k % env.params.dispItems === 0) {
				env.$elts.paginationBtns = env.$elts.paginationBtns.add($('<li><a href="#" role="button">' + env.params.tabLabel(env.$elts.paginationBtns.length + 1) + "</a></li>").data("firstStep", k));
			}
		});
		env.$elts.paginationBtns.each(function() {
			$(this).appendTo(env.$elts.pagination);
		});
		env.$elts.paginationBtns.slice(0, 1).find('a').addClass("active");
		env.launchOnLoad.push(function() {
			env.$elts.paginationBtns.click(function(k) {
				changePage(env, $(this).data("firstStep"));
				stopAutoslide(env);
				return false;
			});
		});
	}
	
	function initAddressPlugin(env) {
		if (env.params.useAddress && $.isFunction($.fn.address)) {
			$.address.init(function(l) {
				var k = $.address.pathNames();
				if (k[0] === env.params.addressIdentifier && !!k[1]) {
					changePage(env, k[1] - 1);
				}
			}).change(function(l) {
				var k = $.address.pathNames();
				if (k[0] === env.params.addressIdentifier && !!k[1]) {
					changePage(env, k[1] - 1);
				} else {
					changePage(env, 0);
				}
			});
		} else {
			env.params.useAddress = false;
		}
	}
	
	function changePage(env, k) {
		env.params.callback(k);
		slide(env, k);
		env.steps.first = k;
		updateButtonsState(env);
		if (env.params.useAddress) {
			$.address.value("/" + env.params.addressIdentifier + "/" + (k + 1));
		}
	}
	
	function shouldEnable(env, j) {
		if (j == "prev") {
			if (!env.params.showEmptyItems) {
				if (env.steps.first === 0) {
					return ((env.params.loop) ? (env.steps.count - env.params.dispItems) : false);
				} else {
					return Math.max(0, env.steps.first - env.params.dispItems);
				}
			} else {
				if ((env.steps.first - env.params.dispItems) >= 0) {
					return env.steps.first - env.params.dispItems;
				} else {
					return ((env.params.loop) ? (env.steps.count - env.params.dispItems) : false);
				}
			}
		} else {
			if (j == "next") {
				if ((env.steps.first + env.params.dispItems) < env.steps.count) {
					if (!env.params.showEmptyItems) {
						return Math.min(env.steps.first + env.params.dispItems, env.steps.count - env.params.dispItems);
					} else {
						return env.steps.first + env.params.dispItems;
					}
				} else {
					return ((env.params.loop) ? 0: false);
				}
			}
		}
	}
	
	// Slide effect
	function slide(env, k) {
		switch (env.params.effect) {
		case "no":
			if (env.params.direction == "vertical") {
				env.$elts.content.css("top", -(env.itemHeight * k) + "px");
			} else {
				env.$elts.content.css("left", -(env.itemWidth * k) + "px");
			}
			break;
		case "fade":
			if (env.params.direction == "vertical") {
				env.$elts.content.fadeOut('fast', function(){
					$(this).css("top", -(env.itemHeight * k) + "px").fadeIn('fast');
				});
			} else {
				env.$elts.content.fadeOut('fast', function(){
					$(this).css("left", -(env.itemWidth * k) + "px").fadeIn('fast');
				});
			}
			break;
		default:
			if (env.params.direction == "vertical") {
				env.$elts.content.stop().animate({
					top: -(env.itemHeight * k) + "px"
				},
				env.params.animSpeed, env.params.slideEasing);
			} else {
				env.$elts.content.stop().animate({
					left: -(env.itemWidth * k) + "px"
				},
				env.params.animSpeed, env.params.slideEasing);
			}
			break;
		}
	}
	
	// Update all buttons state : disabled or not
	function updateButtonsState(env) {
		if (shouldEnable(env, "prev") !== false) {
			env.$elts.prevBtn.trigger("enable");
		} else {
			env.$elts.prevBtn.trigger("disable");
		}
		if (shouldEnable(env, "next") !== false) {
			env.$elts.nextBtn.trigger("enable");
		} else {
			env.$elts.nextBtn.trigger("disable");
		}
		if (env.params.pagination) {
			env.$elts.paginationBtns.find("a").removeClass("active");
			env.$elts.paginationBtns.filter(function() {
				return ($(this).data("firstStep") == env.steps.first);
			}).find("a").addClass("active");
		}
	}
	
	// Stop autoslide
	function stopAutoslide(env) {
		if ( !! env.autoSlideInterval) {
			window.clearInterval(env.autoSlideInterval);
		}
	}
})(jQuery);
