﻿/* 

    jQuery Carousel plug-in
      
    Turns a block-level element with a list into a navigable carousel.
    
    Usage:
    
        Call the plug-in constructor on the block-level element containing 
        the list. The plug-in MUST be loaded ONLY after the document finished
        loading.
    
        $(window).load(function() {
            $("#carousel").WikioCarousel();
        });
        
        #carousel is the ID of the block-level element containing:
            - an unordered list (<ul>)
            - two navigation DIVs, as follows:
                <div class="carousel-nav" id="left">
                    <a href="#left" title="Scroll left" class="left"></a>
                </div>
                <div class="carousel-nav" id="right">
                    <a href="#right" title="Scroll right" class="right"></a>
                </div>

    Options:
    
        Options are passed as an argument to the plug-in constructor.
        
        - fps (default: 25): frames per second count of the animation
        - duration (default: 500): duration of the animation
        - amount (default: 100): amount of one scroll step (in pixels)
        - step (default: 1): the number of steps at a time we should move, 
            e.g. if amount=130 and step=4, then we'll move 520px each click
        - eventposition (default: 4): how long before the end of the carousel 
            should the endLoad event be fired
        - loadfunction (default: none): the function to be called when the 
            carousel reaches the end ("end" being determined by the eventposition
            option)
    
*/

(function($) {
    
	$.fn.WikioCarousel = function(opt) {
		if (this.length > 1) {

			this.each(function() {

				$(this).WikioCarousel(opt);

			});
	
			return this;

		}

		// setup the default options
		opt = $.extend({ 
		fps: 25, duration: 500, amount: 100, step: 1, eventposition: 4, loadfunction: false
		}, opt);

		var carousel = new Carousel(this[0], opt);
		this[0].Carousel = carousel;
		return this[0];
	};

	function Carousel(domContainer, opt) {
		this.domContainer = domContainer;
		this.opt = opt;
		this.moves = new Array(Math.floor(opt.duration / opt.fps));
		this.cList = $(this.domContainer).find("ul");  // fetch the first UL in the layer
		this.length = $(this.cList).find("li").length;
		this.history = new Array(); // stores the numbers of the frames on which the event was triggered
		var T = this;

		// bind the event to the UL element if the function was defined
		if (typeof T.opt.loadfunction == "function") {
			$(T.domContainer).bind("endLoad", T.opt.loadfunction);
		}

		// cache easing values

		var i;
		
		for(i = 0; i < this.moves.length; ++i) {

			this.moves[i] = Math.sin(Math.PI / 2 * i / (this.moves.length - 1));

		}

		this.moves[this.moves.length - 1] = 1;
		$(this.domContainer).find("ul.carousel > li").each(function(i) { // carousel container
			
			$(this).css("position", "absolute");
			var padding = parseInt($(this).css("padding-left")) + parseInt($(this).css("padding-right"));
			var width = parseInt($(this).css("width"));
			$(this).css("left", i*(width + padding));
			$(this).find("a").attr("title", i+1);
		});

		$(this.domContainer).find("#carouselright > a").click(function(e) {
			e.preventDefault();
			T.stepAni(opt.amount);
			var p = $(T.domContainer).find("ul.carousel > li").size();
			if ((p - T.position) <= T.opt.eventposition && typeof T.opt.loadfunction == "function") {
				$(T.domContainer).trigger("endLoad");
			}
		});

		$(this.domContainer).find("#carouselleft > a").click(function(e) {
			e.preventDefault();
			T.stepAni((-1)*opt.amount);
		});

		this.stepAni = stepAni;
		this.setPositioning = setPositioning;
		this.stopLoading = stopLoading;
		$(T.domContainer).bind("stopLoad", {"o":this},this.stopLoading);
		$(T.domContainer).bind("loadLi", this.setPositioning); // bind the positioning event for the loading of list items

		return this;
	}

	function stepAni(amount) {  // Carousel
		if (this.ani) {
			clearInterval(this.ani.timer);
		}
		var T = this;
		function setAniStep() {
			T.ani.i++;
			if (T.ani.i == T.moves.length) {

				clearInterval(T.ani.timer);

				T.ani = null;

				return this;

			}
			var x = T.ani.start + (T.opt.step * amount * T.moves[T.ani.i]);
			$(T.cList).scrollLeft(x);
		}

		this.ani = { i: 0, start: $(T.cList).scrollLeft() };
		this.ani.timer = setInterval(setAniStep, Math.floor(this.opt.duration / this.opt.fps));
        
		// switch the class on the arrows, depending on the direction of scrolling
		if (amount <= 0) {
			$(T.domContainer).find("ul > li.arrow").addClass("rtl");
		} else {
			$(T.domContainer).find("ul > li.rtl").removeClass("rtl");
		}

		var carouselw = $(T.cList).attr("clientWidth") + $(T.cList).scrollLeft() + T.opt.amount;
		var imgw = $(T.cList).find("li").attr("clientWidth");
		T.position = Math.ceil(carouselw / imgw);
		return this;
	}
    
	function setPositioning(e) {
		var len = parseInt(this.length-1);
		if (isNaN(len)) var len = 0;
		$(this.domContainer).find("ul.carousel > li:gt("+(len)+")").each(function(i) { // carousel container
			i++;
			$(this).css("position", "absolute");
			var padding = parseInt($(this).css("padding-left")) + parseInt($(this).css("padding-right"));
			var width = parseInt($(this).css("width"));
			$(this).css("left", (len+i)*(width + padding));
			//$(this).find("a").attr("title", (len+i)+1);
		});
		this.length = $(this.domContainer).find("ul.carousel > li").size();
	}
	
	function stopLoading(event) {
		event.data.o.opt.loadfunction=false;
		return false;
	}

})(jQuery);