/*
 * Slideshow - Creates a slideshow
 *
 * Syntax:
 *
 * var slideshow = new Slideshow([options]);
 *
 * Arguments:
 *
 * options - (object: optional) An object with options for the slideshow. See below.
 *
 * Options:
 *
 * container - (mixed: defaults to element id 'slideshow') The element where the slideshow must be applied to.
 * elements - (mixed: defaults to 'img') The elements that will become the slides.
 * wait - (number: defaults to 4000) The timeout before the next element is faded in.
 * transition - (function: defaults to Fx.Transitions.Sine.easeInOut) The equation to use for the effect see Fx.Transitions.
 * duration - (number: defaults to 1000) The duration of the effect in ms. Can also be one of: 'short' - 250ms, 'normal' - 500ms, 'long' - 1000ms.
 * autoStart - (boolean: defaults to true) Start the slideshow automatically or wait for the user to call start().
 * onStart - (function) Executes when the slideshow starts
 * onChange - (function) Executes when the transition to a next elements is complete
 * onStop - (function) Executes when the slideshow is stopped
 *
 * Functions:
 *
 * start() - Start the slideshow
 * stop() - Stop the slideshow
 * next() - Fade to the next element
 * previous() - Fade to the previous element
 */

var Slideshow = new Class({
	Implements: [Events, Options],
	
	options: {
		container: 'slideshow',
		elements: 'img',
		wait: 4000,
		transition: Fx.Transitions.Sine.easeInOut,
		duration: 1000,
		autoStart: true,
		onStart: $empty,
		onChange: $empty,
		onStop: $empty
	},
	
	initialize: function(options){
		// Merge options
		this.setOptions(options);
		
		// Get container and validate
		this.container = $(this.options.container);
		if (this.container == null){
			return;
		}
		
		// Set style for the container
		this.container.setStyle('position', 'relative');
		
		// Get all slides
		this.elements = $$(this.container.getElements(this.options.elements));
		
		// Set styles for all slides, except the first
		for (var i = 1; i < this.elements.length; i++){
			this.elements[i].setStyles({
				position: 'absolute',
				top: 0,
				left: 0,
				opacity: 0
			});
		}
		
		// Initialize variables
		this.index = 0;
		this.intervalId = -1;
		
		// Start slideshow if autoStart = true
		if (this.options.autoStart){
			this.start();
		}
	},
	
	start: function(){
		// Only start if there is more than 1 slide and the slideshow isn't started yet
		if (this.elements.length > 1 && this.intervalId < 0){
			this.fireEvent('start');
			this.intervalId = this.next.bind(this).periodical(this.options.wait);
		}
	},
	
	stop: function(){
	// If the slideshow is started, stop it en reset variable
		if (this.intervalId > 0){
			$clear(this.intervalId);
			this.intervalId = -1;
			this.fireEvent('stop');
		}
	},
	
	next: function(){
		// Check if there is more than 1 slide
		if (this.elements.length <= 1){
			return;
		}
		
		// Save current index
		var previousIndex = this.index;
		
		// If current index is the last slide, make first slide visible and fade out last element
		if (this.index >= (this.elements.length - 1)){
			this.elements[(this.index = 0)].setStyle('opacity', 1);
			this.elements[previousIndex].set('tween', {
				duration: this.options.duration,
				transition: this.options.transition,
				link: 'chain',
				onComplete: function(){
					this.fireEvent('change');
				}.bind(this)
			}).fade('out');
		} else {
			// Fade in the next slide and hide previous when complete
			this.elements[++this.index].set('tween', {
				duration: this.options.duration,
				transition: this.options.transition,
				link: 'chain',
				onComplete: function(){
					this.elements[previousIndex].setStyle('opacity', 0);
					this.fireEvent('change');
				}.bind(this)
			}).fade('in');
		}
	},
	
	previous: function(){
		// Check if there is more than 1 slide
		if (this.elements.length <= 1){
			return;
		}
		
		// Save current index
		var previousIndex = this.index;
		
		// If current index is the first slide, fade in last slide and hide current when complete
		if (this.index <= 0){
			this.elements[(this.index = (this.elements.length - 1))].set('tween', {
				duration: this.options.duration,
				transition: this.options.transition,
				link: 'chain',
				onComplete: function(){
					this.elements[previousIndex].setStyle('opacity', 0);
					this.fireEvent('change');
				}.bind(this)
			}).fade('in');
		} else {
			// Show the next slide and fade out previous
			this.elements[--this.index].setStyle('opacity', 1);
			this.elements[previousIndex].set('tween', {
				duration: this.options.duration,
				transition: this.options.transition,
				link: 'chain',
				onComplete: function(){
					this.fireEvent('change');
				}.bind(this)
			}).fade('out');
		}
	}
});