/*
	Class:			Gallery (Slideshow)
	Author:			Tom Kentell
	Version:		1.0
	Date:			14/03/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.
					
					* = required option, defaults are set but can be overrided as needed
	Requires		Core: Fx.Morph
*/

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

	options: {
		mode: 1,								// TO DO - Operating Mode: 1 = Gallery [default], 2 = Gallery Slideshow, 3 = Slideshow
		galleryTarget: '.gallery',				// Container for gallery/slideshow *
		galleryItems: '.gallery-items',			// Container for items *

		slideDuration: 4000,					// Miliseconds 1000 = 1 second * [required for slideshow]
		autoplay: false,						// If slideshow autoplay?

		pauseOnHover: false,					// If slideshow pause on hover?
		btnPlayPause: '.slideshow-control',		// Control element for Pause/Play
		pauseText: 'Pause',						// If play/pause present then output this text for pause
		playText: 'Play',						// If play/pause present then output this text for play

		hasButtons: true,						// Set to true for buttons/thumbs to be active
		buttonsTarget: '.gallery-thumbs',		// Buttons or Thumbnails
		isScrollable: true,						// Gallery is scrollable?
		itemsToScroll: 4,						// Amount of thumbails to scroll if scrollable
		scrollLeftHandle: '.previous',			// Class of previous scroller
		scrollRightHandle: '.next',				// Class of next scroller

		currentItem: 0,							// Don't touch
		currentIndex: 0							// Don't touch
	},

	initialize: function(options) {
		this.setOptions(options);
		this.options.images = this.options.galleryTarget.getElement(this.options.galleryItems).getElements('img');

		/* Opacity + get height of biggest image */
		this.options.images.each(function(img,i) {
			if(i > 0) img.getParent('li').set('opacity',0);

			/* Get height of biggest image */
			if(this.options.galleryHeight == null || this.options.galleryHeight < img.getSize().y) this.options.galleryHeight = img.getSize().y;
		}.bind(this));

		/* Run through again to vertically center images */
		this.options.images.each(function(img,i) {
			var imageHeight = img.getSize().y;
			if(imageHeight != this.options.galleryHeight) {
				img.setStyle('padding-top',(this.options.galleryHeight - imageHeight)/2);
			}
		}.bind(this));

		/* Set height of container as images are positioned absolute */
		this.options.galleryTarget.getElement(this.options.galleryItems).setStyle('height',this.options.galleryHeight);

		/* Autoplay? */
		if(this.options.autoplay) this.start();
			else this.options.paused = true;

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

			$$(this.options.images).getParent('li').addEvents({
				'mouseenter': function() {
					if(this.options.paused) wasPaused = true;
						else wasPaused = false;
					this.stop();
				}.bind(this),
				'mouseleave': function() {
					if(!wasPaused) this.start();
				}.bind(this)
			});
		}

		/* Buttons or thumbs? */
		if(this.options.hasButtons) {
			/* get collection + add class of current to first button */
			this.options.theButtons = this.options.galleryTarget.getElement(this.options.buttonsTarget).getElements('li');
			this.options.theButtons[0].addClass('current');

			/* bind click events using relay method to buttons */ //////////////// TODO RELAY
			this.options.theButtons.each(function(e,i) {
				e.addEvent('click', function(e) {
					this.slideTo(i);
					e.stop();
				}.bind(this));
			}, this);
		}

		/* Scrolling, gallery? */
		if(this.options.isScrollable) {
			/* Work out the thumbs container width, we always want to do this */
			this.options.buttonsTargetTotalWidth = 0; // declare /this/ option here to maintain scope
			this.options.galleryTarget.getElements(this.options.buttonsTarget+' li').each(function(e) {				
				this.options.buttonsTargetTotalWidth += e.getComputedSize({styles:['margin','padding','border']}).totalWidth;
			}.bind(this));

			this.options.galleryTarget.getElement(this.options.buttonsTarget).setStyle('width',this.options.buttonsTargetTotalWidth);

			/* Work out how many/far to scroll by */
			if(this.options.images.length <= this.options.itemsToScroll) {
				/* We don't need to scroll, add class for styling */
				this.options.galleryTarget.addClass('noscroll');
			} else {
				this.options.thumbSize = this.options.galleryTarget.getElements(this.options.buttonsTarget+' li')[0].getComputedSize({styles:['margin','padding','border']}).totalWidth;

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

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

				this.options.myMorphLeft = new Fx.Morph($(this.options.galleryTarget.getElement(this.options.buttonsTarget).getProperty('id')),{onComplete:function() {this.options.currentItem = this.options.currentItem - this.options.itemsToScroll;}.bind(this)});
				this.options.myMorphRight = new Fx.Morph($(this.options.galleryTarget.getElement(this.options.buttonsTarget).getProperty('id')),{onComplete:function() {this.options.currentItem = this.options.currentItem + this.options.itemsToScroll;}.bind(this)});
			}
		}

		/* Slideshow Play/Pause Button */
		if($defined(this.options.galleryTarget.getElements(this.options.btnPlayPause))) {
			var playPause = this.options.galleryTarget.getElements(this.options.btnPlayPause);

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

	slideTo: function(here) { /* here [optional] = position to slide/transition to in the collection */
		var images = this.options.images;

		/* Sort out the indexes and maintain a reference to previous index for fading */
		var previousIndex = this.options.currentIndex;
		if($defined(here)) this.options.currentIndex = here;

		/* Fade out previous image and fade in new one, if here is set then number has been clicked so pause */
		images[previousIndex]
			.getParent('li').fade('out')
			.removeClass('current');

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

		images[this.options.currentIndex %= images.length]
			.getParent('li').fade('in')
			.addClass('current');

		/* Buttons or thumbs */
		if(this.options.hasButtons) {
			this.options.theButtons.removeClass('current');
			this.options.theButtons[this.options.currentIndex].addClass('current');
		}
	},

	start: function() {
		/* Set Interval for timeout if slideshow, this will only be called if in slideshow mode */
		this.options.interval = this.slideTo.periodical(this.options.slideDuration, this);
		this.options.paused = false;

		/* Update Play/Pause button if one exists */
		if($defined($$(this.options.btnPlayPause)[0])) {
			this.options.galleryTarget.getElements(this.options.btnPlayPause)
				.removeClass('paused')
				.set('html', this.options.pauseText);
		}
	},

	stop: function() {
		/* Clear Interval for timeout if slideshow, this will only be called if in slideshow mode */
		clearInterval(this.options.interval);
		this.options.paused = true;

		/* Update Play/Pause button if one exists */
		if($defined($$(this.options.btnPlayPause)[0])) {
			this.options.galleryTarget.getElements(this.options.btnPlayPause)
				.addClass('paused')
				.set('html', this.options.playText);
		}
	},

	scrollLeft: function() {
		if(this.options.currentItem != 0) {
			// move items right by morphing to margin-left, current position + itemSize
			this.options.myMorphLeft.start({'margin-left':parseInt(this.options.galleryTarget.getElement(this.options.buttonsTarget).getStyle('margin-left')) + (this.options.thumbSize*this.options.itemsToScroll)});

			// button states
			this.options.galleryTarget.getElement(this.options.scrollRightHandle).removeClass('disabled'); // remove it incase it's disabled and we go left

			// if on the last item then disable button
			if(this.options.currentItem == this.options.itemsToScroll) this.options.galleryTarget.getElement(this.options.scrollLeftHandle).addClass('disabled');
		}
	},

	scrollRight: function() {
		var btnTarget = this.options.galleryTarget.getElement(this.options.buttonsTarget);

		if(this.options.currentItem < (btnTarget.getElements('li').length - this.options.itemsToScroll)) {
			// move items left by morphing to margin-left, current position - itemSize
			this.options.myMorphRight.start({'margin-left':parseInt(btnTarget.getStyle('margin-left')) - (this.options.thumbSize * this.options.itemsToScroll)});

			// button states
			this.options.galleryTarget.getElement(this.options.scrollLeftHandle).removeClass('disabled'); // remove it incase it's disabled and we go right

			// if on the last item then disable button
			if((this.options.currentItem+this.options.itemsToScroll) >= (btnTarget.getElements('li').length - this.options.itemsToScroll)) {
				this.options.galleryTarget.getElement(this.options.scrollRightHandle).addClass('disabled');
			}
		}
	}

});