var Carousel = Class.create();

Carousel.prototype = {
	
	// ----- OPTIONS -----
	
	options: {},
	
	// ----- PROPERTIES -----
	
	currentItem: 0,
	carouselElement: null,
	previousBtnElement: null,
	nextBtnElement: null,
	ulElement: null,
	ilElementList: null,
	
	transitionEffect: null,
	transitionInterval: null,
	
	// ----- CONSTRUCTOR -----
	
	initialize: function(options)
	{
		this.trace('CONSTRUCTOR()');
		
		// -- OPTIONS --
		
		this.options = {
			// id of the carousel element
			carouselElementId: 'carousel',
			
			// id of the previous button element
			prevBtnElementId: '',
			// id of the next button element
			nextBtnElementId: '',
			
			// number of visible items
			nbVisibleItem: 1,
			// number of items to scroll
			nbScrollItem: 1,
			// duration of the transition
			transitionDuration: 500,
			// type of the transition
			transitionEasing: Effect.Transitions.sinoidal,
			// if the carousel scroll vertically
			isVertical: false,
			// is auto
			isAuto: false,
			// duration of the element's display
			displayDurationDuration: 4000,
			// if is infinite
			isInfinite: false
		};
		
		if(options != undefined)
		{
			this.options = Object.extend(this.options, options);
		}
		
		//this.trace(this.options);
		
		// -- PROPERTIES --
		
		this.currentItem = 0;
		
		this.carouselElement 	= $(this.options.carouselElementId);
		this.prevBtnElement 	= $(this.options.prevBtnElementId);
		this.nextBtnElement 	= $(this.options.nextBtnElementId);
		
		if((this.carouselElement != null))
		{
			this.ulElement 		= this.carouselElement.select('ul')[0];
			this.ilElementList 	= this.ulElement.select('li');
		}
		else
		{
			this.trace('ERROR - undefined carousel element.');
			return(false);
		}
		
		if((this.ulElement != null) && (this.ilElementList != null))
		{
			// errors
			if(this.options.nbScrollItem > this.ilElementList.size())
			{
				this.trace('ERROR - the number of items to scroll is greater than the number of items.');
				return(false);
			}
			
			if((this.options.isAuto == true) && (this.options.transitionDuration > this.options.displayDurationDuration))
			{
				this.trace('ERROR - the duration of the transition is greater than the duration of the element\'s display.');
				return(false);
			}
			
			if(this.options.nbScrollItem > this.options.nbVisibleItem)
			{
				this.trace('ERROR - the number of items to scroll is greater than the number of visible items.');
				return(false);
			}
			
			if(this.options.nbVisibleItem > this.ilElementList.size())
			{
				this.options.isAuto = false;
				this.options.isInfinite = false;
			}
			
			// set the CSS
			this.setCSS();
			
			// start the carousel
			if(this.ilElementList.size() > 1)
			{
				this.start();
			}
		}
		else
		{
			this.trace('ERROR - undefined list.');
			return(false);
		}
	},
	
	// ----- METHODS -----
	
	setCSS: function()
	{
		this.trace('setCSS()');
		
		// -- CSS --
		
		if(this.options.isVertical == false)
		{
			var carouselElementStyle = {
				display: 'block',
				width: this.ilElementList[0].getWidth() * this.options.nbVisibleItem +'px',
				height: this.ilElementList[0].getHeight() +'px',
				margin: '0',
				padding: '0',
				overflow: 'hidden'
			}
		}
		else
		{
			var carouselElementStyle = {
				display: 'block',
				width: this.ilElementList[0].getWidth() +'px',
				height: this.ilElementList[0].getHeight() * this.options.nbVisibleItem +'px',
				margin: '0',
				padding: '0',
				overflow: 'hidden'
			}
		}
		this.carouselElement.setStyle(carouselElementStyle);
		
		if(this.options.isVertical == false)
		{
			var ulElementStyle = {
				display: 'block',
				width: this.ilElementList[0].getWidth() * this.ilElementList.size() +'px',
				height: this.ilElementList[0].getHeight() +'px',
				margin: '0',
				padding: '0'
			}
		}
		else 
		{
			var ulElementStyle = {
				display: 'block',
				width: this.ilElementList[0].getWidth() +'px',
				height: this.ilElementList[0].getHeight() * this.options.nbVisibleItem +'px',
				margin: '0',
				padding: '0'
			}
		}
		this.ulElement.setStyle(ulElementStyle);
		
		var ilElementListStyle = {
			float: 'left',
			listStyle: 'none'
		}
		this.ilElementList.invoke('setStyle', ilElementListStyle);
	},
	
	start: function()
	{
		this.trace('start()');
		
		this.checkButtonState();
		
		this.enableButtons();
		
		// -- AUTO --
		
		if(this.options.isAuto == true)
		{
			this.transitionInterval = setInterval(this.onIntervalComplete.bind(this), this.options.displayDurationDuration);
		}
		
		// -- INFINITE --
		
		if(this.options.isInfinite == true)
		{
			this.ilElementList.each(
				function(element, index)
				{
					this.ulElement.insert(element.clone(true));
				},
				this
			);
			
			this.ilElementList.each(
				function(element, index)
				{
					this.ulElement.insert(element.clone(true));
				},
				this
			);
			
			if(this.options.isVertical == false)
			{
				this.ulElement.setStyle(
					{
						'marginLeft': -1 * this.ilElementList.size() * this.ilElementList[0].getWidth() +'px',
						'width': this.ilElementList[0].getWidth() * this.ilElementList.size() * 3 +'px'
					}
				);
			}
			else
			{
				this.ulElement.setStyle(
					{
						'marginTop': -1 * this.ilElementList.size() * this.ilElementList[0].getHeight() +'px',
						'height': this.ilElementList[0].getHeight() * this.ilElementList.size() * 3 +'px'
					}
				);
			}
			
			this.currentItem = this.ilElementList.size();
		}
	},
	
	moveTo: function(targetItem)
	{
		this.trace('moveTo()');
		
		if(this.ilElementList.size() <= this.nbVisibleItem)
		{
			// if the number of the carousel's items is equal or lower than the number of the visible items
			
			return(false);
		}
		
		if(this.options.isInfinite == false)
		{
			// if the carousel is not infinite
			
			if(targetItem <= 0)
			{
				// if the target index is lower than 0
				
				targetItem = 0;
			}
			else if(targetItem >= (this.ilElementList.size() - this.options.nbVisibleItem))
			{
				// if the target index is equal ou upper than the first item index of the last position
				
				targetItem = (this.ilElementList.size() - this.options.nbVisibleItem);
				
				if(this.options.isAuto == true)
				{
					// if the carousel is in auto mode, the interval is cleared
					
					clearInterval(this.transitionInterval);
				}
			}
		}
		else
		{
			// if the carousel is infinite
			
			if(targetItem < this.ilElementList.size())
			{
				// if ...
				
				targetItem = targetItem + this.ilElementList.size();
				
				if(this.options.isVertical == false)
				{
					this.ulElement.setStyle({'marginLeft': -1 * (targetItem + this.options.nbScrollItem) * this.ilElementList[0].getWidth() +'px'});
				}
				else
				{
					this.ulElement.setStyle({'marginTop': -1 * (targetItem + this.options.nbScrollItem) * this.ilElementList[0].getHeight() +'px'});
				}
			}
			else if(targetItem >= ((this.ilElementList.size() * 2) - this.options.nbScrollItem))
			{
				// if ...
				targetItem = targetItem - this.ilElementList.size();
				
				if(this.options.isVertical == false)
				{
					this.ulElement.setStyle({'marginLeft': -1 * (targetItem - this.options.nbScrollItem) * this.ilElementList[0].getWidth() +'px'});
				}
				else
				{
					this.ulElement.setStyle({'marginTop': -1 * (targetItem - this.options.nbScrollItem) * this.ilElementList[0].getHeight() +'px'});
				}
			}
		}
		
		if(targetItem != this.currentItem)
		{
			this.disableButtons();
			
			if(this.options.isVertical == false)
			{
				// horizontal transition
				
				if(this.transitionEffect != null)
				{
					this.transitionEffect.cancel();
				}
				
				this.transitionEffect = new Effect.Morph(
					this.ulElement,
					{
						duration: this.options.transitionDuration / 1000,
						style: 'margin-left: '+ -1 * targetItem * this.ilElementList[0].getWidth() +'px;',
						transition: this.options.transitionEasing,
						afterFinish: this.enableButtons.bind(this)
					}
				);
			}
			else
			{
				// vertical transition
				
				if(this.transitionEffect != null)
				{
					this.transitionEffect.cancel();
				}
				
				this.transitionEffect = new Effect.Morph(
					this.ulElement,
					{
						duration: this.options.transitionDuration / 1000,
						style: 'margin-top: '+ -1 * targetItem * this.ilElementList[0].getHeight() +'px;',
						transition: this.options.transitionEasing,
						afterFinish: this.enableButtons.bind(this)
					}
				);
			}
			
			this.currentItem = targetItem;
			
			this.checkButtonState();
		}
	},
	
	enableButtons: function()
	{
		this.trace('enableButtons()');
		
		// -- EVENTS --
		
		if((this.prevBtnElement != null))
		{
			this.prevBtnElement.observe('click', this.onPrevBtnElementClick.bind(this));
		}
		
		if((this.nextBtnElement != null))
		{
			this.nextBtnElement.observe('click', this.onNextBtnElementClick.bind(this));
		}
	},
	
	disableButtons: function()
	{
		this.trace('disableButtons()');
		
		// -- EVENTS --
		
		if((this.prevBtnElement != null))
		{
			this.prevBtnElement.stopObserving('click');
		}
		
		if((this.nextBtnElement != null))
		{
			this.nextBtnElement.stopObserving('click');
		}
	},
	
	checkButtonState: function()
	{
		this.trace('checkButtonState()');
		
		// -- BUTTONS STATE --
		
		if(this.options.isInfinite == false)
		{
			if((this.prevBtnElement != null))
			{
				this.prevBtnElement.removeClassName('disabled');
				if(this.currentItem == 0)
				{
					this.prevBtnElement.addClassName('disabled');
				}
				if((this.ilElementList.size() <= this.options.nbVisibleItem) || (this.ilElementList.size() == 0))
				{
					this.prevBtnElement.addClassName('disabled');
				}
			}
			
			if((this.nextBtnElement != null))
			{
				this.nextBtnElement.removeClassName('disabled');
				if(this.currentItem >= this.ilElementList.size() - this.options.nbVisibleItem)
				{
					this.nextBtnElement.addClassName('disabled');
				}
				if((this.ilElementList.size() <= this.options.nbVisibleItem) || (this.ilElementList.size() == 0))
				{
					this.nextBtnElement.addClassName('disabled');
				}
			}
		}
	},
	
	// ----- EVENTS -----
	
	onPrevBtnElementClick: function(event)
	{
		this.trace('onPrevBtnElementClick()');
		
		this.moveTo(this.currentItem - this.options.nbScrollItem);
		
		if(this.options.isAuto == true)
		{
			clearInterval(this.transitionInterval);
		}
	},
	
	onNextBtnElementClick: function(event)
	{
		this.trace('onNextBtnElementClick()');
		
		this.moveTo(this.currentItem + this.options.nbScrollItem);
		
		if(this.options.isAuto == true)
		{
			clearInterval(this.transitionInterval);
		}
	},
	
	onIntervalComplete: function()
	{
		this.trace('onIntervalComplete()');
		
		this.moveTo(this.currentItem + this.options.nbScrollItem);
	},
	
	// ----- MISC -----
	
	trace: function(objToTrace)
	{
		if(typeof(console) != 'undefined')
		{
			console.log(objToTrace);
		}
	}
};
