﻿/** 
 * @author Pop JS-ID [cn]
 * @version: 0.1.
 * @description: infinitely looping carousel class
 * @dependencies: jQuery 1.5+
 */
/*** start InfiniteCarousel ***/
POP.InfiniteCarousel = function (container, options) {
	var self = this;

	// defaults
	this.elContainer = container;
	this.options = {
		initialIndex: 0,
		itemsPerGroup: 5,
		visibleItems: 5,
		prevLinkSelector: 'a.carousel-prev-lnk',
		nextLinkSelector: 'a.carousel-next-lnk',
		innerTrackSelector: 'div.carousel-inner-track',
		itemSelector: 'div.carousel-item',
		activeItemClass: 'active',
		disabledLinkClass: 'disabled',
		autoRotate: false,
		autoRotateInterval: 2000,
		itemOffsetLeft: 0,
		infiniteScroll: true,
		speed: 400
	};
	if (typeof options === 'object') {
		$.extend(this.options, options);
	}

	// element references
	this.elPrevLink = this.elContainer.find(this.options.prevLinkSelector);
	this.elNextLink = this.elContainer.find(this.options.nextLinkSelector);
	this.elInnerTrack = this.elContainer.find(this.options.innerTrackSelector);
	this.elItems = this.elInnerTrack.find(this.options.itemSelector);

	// setup & properties
	this._isAnimating = false;
	this._isInitialized = false;
	this._len = this.elItems.size();
	if (this.options.initialIndex >= this._len) {this.options.initialIndex = 0;}			// reset initial index if too high
	if (this._len <= this.options.visibleItems) {											// if not enough items...
		this.options.autoRotate = false;													// ... short-circuit autoRotate option
		this.elPrevLink.addClass(this.options.disabledLinkClass);							// ... disable prev link
		this.elNextLink.addClass(this.options.disabledLinkClass);							// ... disable next link
	}
	this.currentIndex = this.options.initialIndex;											// current index = first item
	this.previousIndex = this.currentIndex;													// declare previous index
	this.scrollAmt = (
						this.elItems.outerWidth() * 
						this.options.itemsPerGroup + 
						this.options.itemOffsetLeft
					) * -1;																	// amt to scroll by = items width

	// add accessibility attributes
	this.elInnerTrack.attr('role', 'listbox');												// add role 'listbox' to track
	this.elItems.attr({'role': 'option', 'tabindex': '-1'});								// add role 'option' to items

	// clone items for looping
	if (this._len > this.options.visibleItems && this.options.infiniteScroll) {
		this.elItems.clone().appendTo(this.elInnerTrack);
		this.elItems.clone().appendTo(this.elInnerTrack);
		this.elItems = this.elContainer.find(this.options.itemSelector);
		this.currentIndex += this._len;
		this.previousIndex = this.currentIndex;
	}

	// init track position
	this.firstPos = 0;
	this.lastPos = 0;
	this._setInitialPos();

	// auto-rotate items
	this.setAutoRotation = false;
	if (this.options.autoRotate) {
		this.setAutoRotation = setInterval(function(){
			self.currentIndex += self.options.itemsPerGroup;
			self.slideCarousel();
		}, self.options.autoRotateInterval);
	}

	// event handlers
	this.elPrevLink.bind('click', function (event) {
		event.preventDefault();
		if (!self._isAnimating && !self.elPrevLink.hasClass(self.options.disabledLinkClass)) {
			self.__clickPrevLink(event);
		}
	});
	this.elNextLink.bind('click', function (event) {
		event.preventDefault();
		if (!self._isAnimating && !self.elNextLink.hasClass(self.options.disabledLinkClass)) {
			self.__clickNextLink(event);
		}
	});

	//Make sure arrows are updated
	if (!this.options.infiniteScroll) {
		this.updateItems();
	}

};

POP.InfiniteCarousel.prototype = {
	_setInitialPos: function () {
		var self = this;

		this.firstPos = this.currentIndex - this.options.visibleItems;			// set firstPos to first item - num visible items
		this.lastPos = this.currentIndex * 2;									// set lastPos to first item of duplicate group

		this.elInnerTrack.css({left: this.scrollAmt * this.currentIndex});
		$(this.elItems[this.currentIndex]).attr({'tabindex': '0'});
		this._isInitialized = true;

    },
	__clickPrevLink: function (event) {
		var self = this;
		if (this.options.autoRotate) {
			this.options.autoRotate = false;
			clearInterval(this.setAutoRotation);
		}
		this.currentIndex -= this.options.itemsPerGroup;
		this.slideCarousel();

	},
	__clickNextLink: function (event) {
		var self = this;
		if (this.options.autoRotate) {
			this.options.autoRotate = false;
			clearInterval(this.setAutoRotation);
		}
		this.currentIndex += this.options.itemsPerGroup;
		this.slideCarousel();

    },
    slideCarousel: function () {
		var self = this;

		this._isAnimating = true;
		this.elInnerTrack.animate({
			left: (self.scrollAmt * self.currentIndex)
		}, self.options.speed, 'swing', function(){
			self._isAnimating = false;
			self.adjustPosition();
		});

    },
    adjustPosition: function () {

		if (this.currentIndex <= this.firstPos) {
			if(this.options.infiniteScroll) {
				this.currentIndex += this._len;
				this.elInnerTrack.css({left: this.scrollAmt * this.currentIndex});
			}
		}
		if (this.currentIndex >= this.lastPos) {
			if(this.options.infiniteScroll) {
				this.currentIndex -= this._len;
				this.elInnerTrack.css({left: this.scrollAmt * this.currentIndex});
			}
		}
		this.updateItems();
    },
    updateItems: function () {
		$(this.elItems[this.previousIndex]).attr({'tabindex': '-1'});
		$(this.elItems[this.currentIndex]).attr({'tabindex': '0'});

		this.previousIndex = this.currentIndex;
		if (!this.options.infiniteScroll) {
			if (this.currentIndex <= 0) {
				this.elPrevLink.addClass(this.options.disabledLinkClass);
			} else {
				this.elPrevLink.removeClass(this.options.disabledLinkClass);
			}
			if (this.currentIndex >= (this._len - this.options.visibleItems)) {
				this.elNextLink.addClass(this.options.disabledLinkClass);
			} else {
				this.elNextLink.removeClass(this.options.disabledLinkClass);
			}
		}
		$.event.trigger('POP.InfiniteCarousel:carouselUpdated');

    }
};
/*** end InfiniteCarousel ***/

