if(!$chk(window['wb'])) {
	var wb = {};
}

/**
 * wm.Carrousel
 *
 * @classDescription wm.Carrousel
 */
wb.Carrousel = new Class({

	/**
	 * Options
	 * 
	 * @type {Object}
	 */
	options: {
		
		elements: {
				navigationConatainer: '.carrouselNavigation',
				content: '.carrouselContent',
				contentContainer: '.carrouselContent',
				itemsContainer: '.carrouselItemContainer',
				item: '.carrouselItem',
				nextButton: '.carrouselNavigation .next',
				previousButton: '.carrouselNavigation .previous',
				indicatorDots: '.carrouselPagingItems a',
				playControll: '.carrouselControl'
			},
			
		currentDotClass: 'current',
		
		playClass: 'play',
		
		playLabel: 'play',
		
		stopClass: 'stop',

		stopLabel: 'stop',
		
		slideSpeed: 0.6,
		
		maxSpeed: 15,
		
		playOnStart: true,
		
		playInterval: 10000
			
	},
	
	/**
	 * Carrousel container
	 *
	 * @type {Elememt}
	 */
	carousselTarget: null,
	
	/**
	 * Carrousel content container
	 *
	 * @type {Elememt}
	 */
	contentContainer: null,
	
	/**
	 * Width of slide view
	 *
	 * @type {Integer}
	 */
	slideWidth: 0,
	
	/**
	 * Carrousel items container
	 *
	 * @type {Elememt}
	 */
	itemsContainer: null,
	
	/**
	 * The number of items that make up a single slide
	 *
	 * @type {Integer}
	 */
	itemPerSlide: 3,
	
	/**
	 * Carrousel itemContainer width
	 *
	 * @type {Integer}
	 */
	containerWidth: 0,
	
	/**
	 * The slide offset of the carrousel
	 *
	 * @type {Integer}
	 */
	currentSlide: 0,
	
	/**
	 * The number of slides in the carrousel
	 *
	 * @type {Integer}
	 */
	numberOfSlides: 0,
	
	/**
	 * Carrousel next button controller
	 *
	 * @type {Elememt}
	 */
	nextButton: null,
	
	/**
	 * Carrousel previous button controller
	 *
	 * @type {Elememt}
	 */
	previousButton: null,
	
	/**
	 * Array of the indicator dots
	 *
	 * @type {Array}
	 */	
	indicatorDots: null,
	
	/**
	 * The current slide index
	 * 
	 * @type {Number}
	 */
	selectedSlideIndex: 0,
	
	/**
	 * Animation fx's
	 *
	 * @type {Object}
	 */
	animations: {
		slide: null
	},
	
	isPlaying: false,
	
	playButton: null,
	
	playTimer: null,
	
	/**
	 *  Needed to extend container size for
	 *  contineus carrousel.
	 */
	correction: 50,
	
	/**
	 * wm.Carrousel Constructor
	 * 
	 * @param {Object} target
	 * @param {Object} options
	 */
	initialize: function(target, options) {
		this.setOptions(options);
		this.carousselTarget = $(target);
		
		this._setupcontainer();
		this._setupNavigation();
		
		this.setSelectedIndex(0)
	},
	
	_setupcontainer: function() {
		
		// Get the content container
		this.contentContainer = this.carousselTarget.getElement(this.options.elements.contentContainer);
		this.slideWidth = this.contentContainer.getSize().x; // appears to be stage size
			
		// Get the items container
		this.itemsContainer = this.carousselTarget.getElement(this.options.elements.itemsContainer);
		
		// Get the actual width of the container
		var firstSlide = this.itemsContainer.getElement(this.options.elements.item);
		var actualItemsWidth = this.itemsContainer.getElements(this.options.elements.item).length * firstSlide.getSize().x
		
		// Calulate the number of slides
		this.numberOfSlides =  Math.ceil(actualItemsWidth / this.slideWidth)
		
		// Correct the item width
		this.containerWidth = this.numberOfSlides * this.slideWidth;
		
		this.itemPerSlide = Math.round(this.containerWidth / this.slideWidth);
		
		// Fillout slides with empty slides if needed
		var numberOfItems = this.itemsContainer.getChildren().length;
		var itemWidth     = (numberOfItems > 0) ? this.itemsContainer.getChildren()[0].getSize().x : 0;
		var itemsPerSlide = Math.floor(this.slideWidth / itemWidth);
		
		var missingSlides = itemsPerSlide - (numberOfItems % itemsPerSlide);
		
		if(missingSlides > 0) {
	
			// Add container for missing slides
			var missingSlidesWidth = itemWidth * missingSlides;
			var missingElement = new Element('div');

			missingElement.setStyles({
										'float': 	'left',
										'height': 	'100%',
										'position': 'relative',
										'width': 	 missingSlidesWidth
									 });
									
			missingElement.inject(this.itemsContainer, 'bottom');

		}
		
		if(numberOfItems > itemsPerSlide) {
			// copy first items to end of slides for continuous carrousel 
			var currentItems = this.itemsContainer.getChildren();
			
			for(var i=0; i<itemsPerSlide; i++) {
				var dubItem = currentItems[i].clone();
				dubItem.inject(this.itemsContainer, 'bottom');
			}
			
			// Add extra items to container width
			this.containerWidth += (itemsPerSlide * itemWidth);
			if(Browser.Engine.trident) {
				this.containerWidth += 6;
			}
		}
		
		// Set items container width to fill out
		this.itemsContainer.setStyle('width', this.containerWidth + this.correction);
	},
	
	_setupNavigation: function() {

		// Get the buttons
		this.nextButton = this.carousselTarget.getElement(this.options.elements.nextButton);		
		this.previousButton = this.carousselTarget.getElement(this.options.elements.previousButton);
		
		// Set button functionality
		if(this.nextButton) {
			this.nextButton.addEvent('click', this.next.bindWithEvent(this));
		}
		if(this.previousButton) {
			this.previousButton.addEvent('click', this.previous.bindWithEvent(this));
		}
		
		// Get the indicator dots
		this.indicatorDots = this.carousselTarget.getElements(this.options.elements.indicatorDots);
		
		for(var i=0;i<this.indicatorDots.length;i++) {
			
			this.indicatorDots[i].addEvent('click', this.dotActions.bindWithEvent(this, i));
		}
		
		// Get the play/pause controlls
		var playPauseControl = this.carousselTarget.getElement(this.options.elements.playControll)
		if(playPauseControl) {
			this.playButton = playPauseControl;
			if(!this.options.playOnStart) {
				this.stop();
			} else {
				this.play()
			}
		}
		
	},
	
	_getLeftPositionForIndex: function(index) {
		return (index * this.slideWidth);
	},
	
	/**
	 * Called to slide to next view
	 */
	next: function(e) {
		if(e) {
			var evt = new Event(e);
			evt.preventDefault();
			this.stop();
		}

		this.slideToIndex(this.currentSlide + 1);
	},
	
	/**
	 * Called to slide to previous view
	 */
	previous: function(e) {
		if(e) {
			var evt = new Event(e);
			evt.preventDefault();
			this.stop();
		}
		
		this.slideToIndex(this.currentSlide - 1);
	},
	
	dotActions: function(e, index) {
		var evt = new Event(e);
		evt.preventDefault();
		
		this.slideToIndex(index);
	},
	
	slideToIndex: function(index) {

		if (index <= -1) {
			index = (this.numberOfSlides - 1);
			// Correct back for continuous scrolling
			this.contentContainer.scrollTo(this.containerWidth,0);
		}

		var targetIndex = (index < this.numberOfSlides + 1) ? index : (this.numberOfSlides);
		this.currentSlide = targetIndex;
		
		if(this.animations.slide !== null) {
			$clear(this.animations.slide);
			this.animations.slide = null;
		}		
		this.animations.slide = this._scrollLoop.periodical(10, this, [this._getLeftPositionForIndex(targetIndex)]);
		
		
		var targetSelectedIndex = (targetIndex < this.numberOfSlides) ? targetIndex : 0;
		this.setSelectedIndex(targetSelectedIndex)
	},
	
	setSelectedIndex: function(index) {
		
		this.selectedSlideIndex = index;
		
		for(var i=0;i<this.indicatorDots.length;i++) {
			
			if(this.indicatorDots[i].hasClass(this.options.currentDotClass) && i !== index) {
				this.indicatorDots[i].removeClass(this.options.currentDotClass);
			}
			if(i == index) {
				this.indicatorDots[i].addClass(this.options.currentDotClass);
			}
		}
		
	},
	
	_scrollLoop: function(targetPosition) {
		
		var currentOffset = this.contentContainer.getScroll().x;
		var negative = (targetPosition < currentOffset);
		
		var offset = Math.abs((targetPosition - currentOffset) * this.options.slideSpeed);
		var newOffset = Math.min(offset, this.options.maxSpeed) == offset ? offset : this.options.maxSpeed;
		
		if(negative) {
			newOffset = -newOffset;
		}
		
		var newScrollX = currentOffset + Math.round(newOffset);

		if( Math.abs(newScrollX - currentOffset) < 1 ) {
			newScrollX = targetPosition;
			$clear(this.animations.slide);
			this.animations.slide = null;
			
			// Correct scroll for continuous scroll
			if(this.selectedSlideIndex == 0 && this.contentContainer.getScroll().x > 0) {
				newScrollX = 0;
				this.currentSlide = 0;
			}
		}
		
		this.contentContainer.scrollTo(newScrollX, 0);
	},
	
	play: function(e) {
		if($chk(e)) {
			var evt = new Event(e);
			evt.preventDefault();
		}
		
		if(this.playButton) {
			this.playButton.removeClass(this.options.playClass);
			this.playButton.addClass(this.options.stopClass);
			this.playButton.set('text', this.options.stopLabel);
			this.playButton.removeEvents('click');
			this.playButton.addEvent('click', this.stop.bindWithEvent(this));
		}
		
		if(this.playTimer !== null) {
			$clear(this.playTimer);
			this.playTimer = null;
		}
		this.playTimer = this.next.periodical(this.options.playInterval, this);
		
		if($chk(e)) {
			this.next();
		}
	},
	
	stop: function(e) {
		
		if(e) {
			var evt = new Event(e);
			evt.preventDefault();
		}
		
		if(this.playButton) {
			this.playButton.removeClass(this.options.stopClass);
			this.playButton.addClass(this.options.playClass);
			this.playButton.set('text', this.options.playLabel);
			this.playButton.removeEvents('click');
			this.playButton.addEvent('click', this.play.bindWithEvent(this));
		}
		
		if(this.playTimer !== null) {
			$clear(this.playTimer);
			this.playTimer = null;
		}

	}

});
wb.Carrousel.implement(new Options);
wb.Carrousel.implement(new Events);
