/*
	Class:			Slideshow
	Author:			Tom Kentell
	Version:		0.4.2 Fixed issue with transitions when clicking on current item
	Date:			02/11/2010
	Note:			This should be called in an on load event not dom ready to allow webkit to work out heights of images, otherwise you need to set this manually and remove JS for working the heights out.
	Dependencies:	http://www.aryweb.nl/projects/mooDeps/#Core;Browser;Array;Function;Number;String;Hash;Event;Class;Class.Extras;Element;Element.Event;Element.Style;Element.Dimensions;Selectors;Fx;Fx.CSS;Fx.Tween
*/

var Slideshow = new Class({
	Implements: [Options],

	options: {
		/* Basic SettingallerySlider */
		slideTarget: $$('.slideshow')[0],
		slideItems: '.slideshow_items',
		slideDuration: 3000, 			/* miliseconds 1000 = 1 second ** MUST BE LONGER THAN TRANSITION ** */
		slideTransitionDuration: 1000,	/* miliseconds 1000 = 1 second */
		slideshowHeight: 0,

		/* Whether to change active/current slide on hover or focus */
		changeOnHover: false,
		changeOnFocus: false,

		/* Autoplay and Pause Control */
		autoplay: true,
		pauseOnHover: true,
		btnPlayPause: '.slideshow_control',
		playText: 'Play',
		pauseText: 'Pause',

		/* Control buttons for each slide */
		hasButtons: false,
		buttonsTarget: '.slideshow_buttons',

		/* Controls if thumbs/number buttons are in a slider setup */
		hasSliderControls: false,
		sliderPrevious: '.previous',
		sliderNext: '.next',
		sliderItemsShown: 6,
		sliderScrollBy: 1
	},

	initialize: function(options) {
		this.setOptions(options);

		this.currentIndex = 0;
		this.slideImages = this.options.slideTarget.getElements(this.options.slideItems + ' img');
		slideShowState = null;

		/* Opacity and Height SettingallerySlider */
		slideshowSetHeight = (this.options.slideshowHeight == 0) ? true : false; // do we need to set the height programatically by working out the tallest slide or has someone set this for us
		slideshowHeight = this.options.slideshowHeight;

		this.slideImages.each(function(img, i) {
			/* Skip over first item, we want this visible */
			if(i > 0) img.getParent('li').set('opacity',0);

			/* If slideshow height needs to be set then do so */
			if(slideshowSetHeight) {
				currentImageHeight = img.getSize().y;
				if(slideshowHeight < currentImageHeight) slideshowHeight = currentImageHeight;
			}
		});

		/* Set height of container as images are positioned absolute */
		this.options.slideTarget.getElement(this.options.slideItems).setStyle('height', slideshowHeight);

		/* If autoplay = true then start slideshow */
		if(this.options.autoplay) this.start();
			else this.options.paused = true;

		if(this.options.pauseOnHover) {
			/* If slideshow already paused then we don't want to restart it on mouseleave */
			this.wasPaused = false;

			this.options.slideTarget.getElements(this.options.slideItems + ' li').addEvents({
				'mouseenter': function() {
					if(this.options.paused) this.wasPaused = true;
						else this.wasPaused = false;
					this.stop();
				}.bind(this),
				'mouseleave': function() {
					if(!this.wasPaused) this.start();
				}.bind(this)
			});
		}

		/* If slideshow has buttons eg: 1, 2, 3 or thumbnails then do this */
		if(this.options.hasButtons) {
			/* add class of current to first button */
			theButtons = this.options.slideTarget.getElements(this.options.buttonsTarget + ' li');
			theButtons[0].addClass('current');

			/* bind click events to buttons */
			theButtons.each(function(elem, i) {
				elem.addEvent('click', function(e) {
					e.stop();
					if(!elem.hasClass('current')) this.slideTo(i);
				}.bind(this));

				// If change on hover then do so here, stops the slideshow when entered
				if(this.options.changeOnHover) {
					elem.addEvent('mouseenter', function() {
						this.slideTo(i);
					}.bind(this));
				}

				// If change on focus then do so here, stops the slideshow when entered. NOTE: The focus event will fire on click as well, Button must contain anchor for focus event to work.
				if(this.options.changeOnFocus) {
					elem.getElement('a').addEvent('focus', function() {
						this.slideTo(i);
					}.bind(this));
				}
			}, this);
		}

		/* If slideshow has play/pause button then set this up */
		if(this.options.slideTarget.getElement(this.options.btnPlayPause) != undefined) {
			var playPause = this.options.slideTarget.getElement(this.options.btnPlayPause);

			playPause.addEvent('click', function(e) {
				e.stop();
				if(playPause.hasClass('paused')) this.start();
					else this.stop();
			}.bind(this));
		}

		/* If slideshow has a slider style thumb/number set */
		if(this.options.hasSliderControls) {
			/* Work out the size of the first button for calculations */
			this.itemSize = theButtons[0].getComputedSize({styles:['margin','padding','border']}).totalWidth;

			/* If there isn't enough buttons to use for scrolling add a class of noscroll for styling */
			if(theButtons.length <= this.options.sliderItemsShown) {
				this.options.slideTarget.addClass('noscroll');
			}

			/* Work out the width of the container based on all children */
			sliderContainerTotalWidth = 0;
			theButtons.each(function(e) {
				sliderContainerTotalWidth += e.getComputedSize({styles:['margin','padding','border']}).totalWidth;
			});

			/* Set ul to size of all items combined to give smooth scrolling effect, needs overflow hidden to work on container */
			this.options.slideTarget.getElement(this.options.buttonsTarget + ' ul').setStyle('width', sliderContainerTotalWidth);

			/* bind scrollLeft function to left handle and add a class of disabled to left button */
			this.options.slideTarget.getElement(this.options.sliderPrevious).addClass('disabled').addEvent('click', function(e) {
				e.stop();
				this.scrollLeft();
			}.bind(this));

			/* bind scrollRight function to right handle */
			this.options.slideTarget.getElement(this.options.sliderNext).addEvent('click', function(e) {
				e.stop();
				this.scrollRight();
			}.bind(this));

			this.currentItem = 0;
			this.myMorphLeft = new Fx.Morph(this.options.slideTarget.getElement(this.options.buttonsTarget + ' ul').get('id'),{onComplete:function() {this.currentItem = this.currentItem - this.options.sliderScrollBy;}.bind(this)});
			this.myMorphRight = new Fx.Morph(this.options.slideTarget.getElement(this.options.buttonsTarget + ' ul').get('id'),{onComplete:function() {this.currentItem = this.currentItem + this.options.sliderScrollBy;}.bind(this)});
		}
	},

	slideTo: function(here) { /* here [optional] = position to slide/transition to in the collection of pictures, if supplied then slideshow is stopped */
		/* Sort out the indexes and maintain a reference to previous index for fading */
		this.previousIndex = this.currentIndex;
		if($defined(here)) this.currentIndex = here;

		/* Fade out previous image and fade in new one, if here is set then number has been clicked so pause */
		var imageToSlideOut = new Fx.Tween(this.slideImages[this.previousIndex].getParent('li'), {duration:this.options.slideTransitionDuration});
		imageToSlideOut.start('opacity', '1', '0');

		this.slideImages[this.previousIndex].getParent('li').removeClass('current');

		if(!$defined(here)) this.currentIndex++;
			else this.stop();

		var imageToSlideIn = new Fx.Tween(this.slideImages[this.currentIndex %= this.slideImages.length].getParent('li'), {duration:this.options.slideTransitionDuration});
		imageToSlideIn.start('opacity', '0', '1');

		this.slideImages[this.currentIndex %= this.slideImages.length].getParent('li').addClass('current');

		/* If slideshow has buttons eg: 1, 2, 3, 4, 5 then do this */
		if(this.options.hasButtons) {
			theButtons.removeClass('current');
			theButtons[this.currentIndex].addClass('current');
		}
	},

	start: function() {
		this.slideShowState = this.slideTo.periodical(this.options.slideDuration, this);
		this.options.paused = false;

		/* Update Play/Pause button if one exists */
		if($defined(this.options.slideTarget.getElement(this.options.btnPlayPause))) {
			this.options.slideTarget.getElement(this.options.btnPlayPause)
				.removeClass('paused')
				.set('html', this.options.pauseText);
		}
	},

	stop: function() {
		clearInterval(this.slideShowState);
		this.options.paused = true;

		/* Update Play/Pause button if one exists */
		if(this.options.slideTarget.getElement(this.options.btnPlayPause) != undefined) {
			this.options.slideTarget.getElement(this.options.btnPlayPause)
				.addClass('paused')
				.set('html', this.options.playText);
		}
	},

	scrollLeft: function() {
		var gallerySlider = this.options.slideTarget.getElement(this.options.buttonsTarget);

		if(this.currentItem != 0) {
			/* Move items right by morphing to margin-left, current position + this.itemSize */
			this.myMorphLeft.start({'margin-left':parseInt(gallerySlider.getElement('ul').getStyle('margin-left')) + (this.itemSize * this.options.sliderScrollBy)});

			/* Button states */
			this.options.slideTarget.getElement(this.options.sliderNext).removeClass('disabled'); // remove it incase it's disabled and we go left
			if(this.currentItem == 1) { // if on the last item then disable button
				this.options.slideTarget.getElement(this.options.sliderPrevious).addClass('disabled');
			}
		}
	},

	scrollRight: function() {
		var gallerySlider = this.options.slideTarget.getElement(this.options.buttonsTarget);

		if((this.currentItem + this.options.sliderItemsShown) != gallerySlider.getElements('li').length) {
			/* Move items left by morphing to margin-left, current position + this.itemSize */
			this.myMorphRight.start({'margin-left':parseInt(gallerySlider.getElement('ul').getStyle('margin-left')) - (this.itemSize * this.options.sliderScrollBy)});

			/* Button states */
			this.options.slideTarget.getElement(this.options.sliderPrevious).removeClass('disabled'); // remove it incase it's disabled and we go right

			if(((this.currentItem + this.options.sliderItemsShown) + 1) == gallerySlider.getElements('li').length) { // if on the last item then disable button
				this.options.slideTarget.getElement(this.options.sliderNext).addClass('disabled');
			}
		}
	}
});
