var SimpleSlideShow = new Class
({
    Implements: [Events, Options],
    options: {
        selector     : '*',
        cycle        : true,
		delay		 : 5000,
		tweenDuration: 'long',
		mouseExitNext: false,
        pageControls : [], // array with an element reference [right,left]
		mode		 : 'left' // fade, left, right, top and bottom are supported
    },
    
    initialize: function( element, options )
    {
        this.setOptions( options );
        this.element = $( element );
		this.isAnimating = false;
        
        this.slides = this.element.getChildren( this.options.selector );

        // Bail out if we have 1 or less slides
        if( this.slides.length <= 1 )
            return;

		// Bind our animation complete handler so that it can access this
		var boundAnimationComplete = this.animationDidFinish.bind( this );
		
        // Hide all but the first slide
        $each( this.slides, function( item, index )
        {
            // Set the fade transition defaults
            item.set( 'tween',
			{
				duration: this.options.tweenDuration,
				onComplete: boundAnimationComplete
			});
            
            if( index )
                item.setStyle( 'opacity', 0 );
        }, this );

		// Setup event handlers for the buttons if we have them
		if( this.options.pageControls.length == 2 )
		{
			// Setup the left button
			$( this.options.pageControls[0] ).addEvent( 'click', function()
			{
				// Stop the cycler and go to the previous slide
				this.stopCycle();
				this.previous();
				this.startCycle( false );
			}.bind( this ));
			
			// Setup the right button
			$( this.options.pageControls[1] ).addEvent( 'click', function()
			{
				// Stop the cycler and go to the next slide
				this.stopCycle();
				this.next();
				this.startCycle( false );
			}.bind( this ));
		}
        
        // Set the current index
        this.currentIndex = 0;

		if( this.options.cycle )
		{
			this.startCycle();
			
			// Setup mouseenter/exit handlers if necessary
			if( this.options.mouseExitNext )
			{
				// Setup event handlers for mouseenter/exit to pause the slideshow
				this.element.addEvent( 'mouseenter', this.stopCycle.bind( this ) );
				this.element.addEvent( 'mouseleave', this.startCycle.bind( this, true ) );
			}
		}
    },

	animationDidFinish: function( ele )
	{
		// Set the flag so we don't animate while we are animating.
		this.isAnimating = false;
	},

	startCycle: function( startImmediately )
	{
		if( !this.cycler )
		{
			if( startImmediately )
				this.next();
			
			// Bind up a function for the cycle
			var boundNext = this.next.bind( this );
			this.cycler = boundNext.periodical( this.options.delay );
		}
	},
	
	stopCycle: function()
	{
		$clear( this.cycler );
		this.cycler = null;
	},
    
    next: function()
    {
		if( this.isAnimating )
			return;

        var nextIndex = this.currentIndex + 1;

        if( this.slides.length == nextIndex )
            nextIndex = 0;
        
        this.showSlide( nextIndex );
    },
    
    previous: function()
    {
		if( this.isAnimating )
			return;

        var prevIndex = this.currentIndex - 1;
        
        if( prevIndex < 0 )
            prevIndex = this.slides.length - 1;
        
        this.showSlide( prevIndex );
    },
    
    showSlide: function( index )
    {
		// Set the previous slides zIndex back to 0 so that it doesn't become visible during transitions
		var previousIndex = ( this.currentIndex == 0 ) ? this.slides.length - 1 : this.currentIndex - 1;
		var prevSlide = this.slides[previousIndex];
		prevSlide.setStyle( 'zIndex', 0 );
	
        // We need to transition one slide out and the other in
        var currentSlide = this.slides[this.currentIndex];
        var nextSlide = this.slides[index];

		// Set our animating flag so we dont start more than one animation at a time
		this.isAnimating = true;
        
		// Setup our animation based on the setting type
		switch( this.options.mode )
		{
			case 'fade':
			{
		        // Put the next slide under the current
		        currentSlide.setStyle( 'zIndex', 3 );
		        nextSlide.setStyle( 'zIndex', 2 );

		        nextSlide.setStyle( 'opacity', 1 );
		        currentSlide.tween( 'opacity', 0 );
	
				break;
			}
			case 'left':
			case 'right':
			{
		        // Put the next slide on top of the current
		        currentSlide.setStyle( 'zIndex', 2 );
		        nextSlide.setStyle( 'zIndex', 3 );
		
				// Move the next slide off to the left or right so it can be slid in
				var slideWidth = nextSlide.getStyle( 'width' ).toInt();
		
				if( this.options.mode == 'left' )
					nextSlide.setStyle( 'left', -slideWidth );
				else
					nextSlide.setStyle( 'left', slideWidth );
				
				// Make sure the next slide is visible
		        nextSlide.setStyle( 'opacity', 1 );

				// Animate the next slide in
				nextSlide.tween( 'left', 0 );
				
				break;
			}
			case 'top':
			case 'bottom':
			{
		        // Put the next slide on top of the current
		        currentSlide.setStyle( 'zIndex', 2 );
		        nextSlide.setStyle( 'zIndex', 3 );
		
				// Move the next slide off to the left so it can be slid in
				var slideHeight = nextSlide.getStyle( 'height' ).toInt();
				
				if( this.options.mode == 'top' )
					nextSlide.setStyle( 'top', -slideHeight );
				else
					nextSlide.setStyle( 'bottom', slideHeight );
				
				// Make sure the next slide is visible
		        nextSlide.setStyle( 'opacity', 1 );

				// Animate the next slide in
				nextSlide.tween( 'top', 0 );
				
				break;
			}
		}
        
        this.currentIndex = index;
    }
});
