/*
Example usage:

<script src="js/scriptaculous/lib/prototype.js"></script>
<script src=js/scriptaculous/src/scriptaculous.js?load=effects"></script>
<script src="js/PhotoGallery.js"></script>
<script>
new PhotoGallery(['images/1.jpg','images/2.jpg','images/3.jpg'],
									['images/thumbs/1.jpg','images/thumbs/2.jpg','images/thumbs/3.jpg'],
									{});
</script>
<div id="galleryImageContainer" style="width: 600px; height: 400px; border: 1px solid #eee;margin: 0px auto"></div>
<div id="galleryControlsContainer" style="width: 150px; margin: 5px auto; bacground-color: #eee; position: relative;"></div>
<div id="galleryVerticalControlsContaner" style="float: right; border: 1px solid #eee;"></div>
<div id="galleryThumbContainer" style="width: 350px; height: 66px; float: right;"></div>

*/


var PhotoGallery = Class.create({
	initialize: function(imageArr, thumbArr, options) {
		if((typeof imageArr) != 'object') throw new Error('PhotoGallery.initialize: The first argument must be an array.');
		if((typeof thumbArr) != 'object') throw new Error('PhotoGallery.initialize: The second argument must be an array.');
		if(imageArr.length != thumbArr.length) throw new Error('PhotoGallery.initialize: The first and second arguments must be arrays of the same length.');

		this.options = {
			slideShowSpeed: 5,
			imageContainer: 'galleryImageContainer',
			thumbContainer: 'galleryThumbContainer',
			controlsContainer: 'galleryControlsContainer',
			verticalControlsContainer: 'galleryVerticalControlsContaner',
			prevButton: 'galleryControlPrev',
			prevButtonImage: '',
			nextButton: 'galleryControlNext',
			nextButtonImage: '',
			slideShowButton: 'galleryControlSlideShow',
			upButton: 'galleryControlUp',
			upButtonImage: '',
			downButton: 'galleryControlDown',
			downButtonImage: ''
		}
		Object.extend(this.options, options);

		this.imageContainer;
		this.thumbContainer;
		this.controlsContainer;
		this.verticalControlsContainer;
		this.prevButoon;
		this.nextButton;
		this.slideShowButton;
		this.upButton;
		this.downButton;

		this.slideShowSpeed = this.options.slideShowSpeed;
		this.slideShowTimerPointer = null;

		this.imageArr = [];
		this.thumbArr = [];
		this.imageIndex = -1;
		this.thumbRowIndex = -1;
		this.thumbRows = 0;
		this.thumbCols = 0;
		this.thumbContainerWidth = 0;
		this.thumbContainerHeight = 0;
		this.thumbsUl = null;

		for(var i=0; i < imageArr.length; i++) {
			var tmp = new Image();// an attempt to preload
			tmp.src = imageArr[i];
			tmp = null
			this.imageArr.push(imageArr[i]);
			this.thumbArr.push(thumbArr[i]);
		}

		Event.observe(window, 'load', this.onLoad.bindAsEventListener(this));
	},
	onLoad: function() {
		if(!$(this.options.imageContainer) || !$(this.options.thumbContainer)) throw new Error('PhotoGallery.onLoad: The imageContainer and the thumbContainer are required objects.');
		this.imageContainer = $(this.options.imageContainer);
		this.thumbContainer = $(this.options.thumbContainer);

		// create the main images
		var imageUl = new Element('ul', {style: 'position: relative; margin: 0px; padding: 0px; text-align: center;'});

		for(var i=0; i < this.imageArr.length; i++) {
			var imageLi = new Element('li', {style:'position: absolute; top: 0px; left: 0px; list-style: none; width: 100%;'});

			this.imageArr[i] = new Element('img', {id: 'galleryImage_' + i, src: this.imageArr[i], style: 'opacity: 0; filter: alpha(opacity=0);'})
			imageLi.insert(this.imageArr[i]);
			imageUl.insert(imageLi);

			imageLi = imageObj = null;
		}
		this.imageContainer.insert(imageUl);
		imageUl = null;

		// create the thumb images
		this.thumbContainer.style.position = 'relative';
		this.thumbContainer.style.overflow = 'hidden';
		this.thumbsUl = new Element('ul', {style: 'width: ' + this.thumbContainer.getWidth() + '; margin: 0px; padding: 0px; position: absolute; top: 0px; left: 0px; opacity: 0; filter: alpha(opacity=0);'});

		for(var i=0; i < this.thumbArr.length; i++) {
			var imageLi = new Element('li', {style:'margin: 0px; padding: 0px; border: 0px; float: left; list-style: none;'});

			this.thumbArr[i] = new Element('img', {id: 'galleryThumb_' + i, src: this.thumbArr[i], style: 'border: 1px solid #333; margin: 5px; cursor: pointer; opacity: 0.5; filter: alpha(opacity=50);'})

			this.thumbArr[i].observe('click',this.select.bindAsEventListener(this));
			this.thumbArr[i].observe('mouseover',this.highlightThumb.bindAsEventListener(this));
			this.thumbArr[i].observe('mouseout',this.unhighlightThumb.bindAsEventListener(this));

			imageLi.insert(this.thumbArr[i]);
			this.thumbsUl.insert(imageLi);

			imageLi = imageObj = null;
		}
		this.thumbContainer.insert(this.thumbsUl);
		new Effect.Opacity(this.thumbsUl, {from: 0.0, to: 1.0});

		// create the controls
		if($(this.options.controlsContainer)) {
			this.controlsContainer = $(this.options.controlsContainer);
			this.controlsContainer.style.textAlign = 'center';

			if(this.options.prevButtonImage.length > 0) {
				this.prevButton = new Element('img', {id:  this.options.prevButton, style: 'position: absolute; left: 0px; cursor: pointer;', src: this.options.prevButtonImage});
			} else {
				this.prevButton = new Element('span', {id: this.options.prevButton, style: 'position: absolute; left: 0px; cursor: pointer;'}).update('&larr;');
			}
			this.prevButton.observe('click',this.prev.bindAsEventListener(this));
			this.controlsContainer.insert(this.prevButton);

			//this.slideShowButton = new Element('span', {id: this.options.slideShowButton, style: 'cursor: pointer;'}).update('SLIDESHOW');
			this.slideShowButton = new Element('img', {id: this.options.slideShowButton, style: 'cursor: pointer;', src: '/images/slideshow.gif'});
			this.slideShowButton.observe('click',this.toggleSlideShow.bindAsEventListener(this));
			this.controlsContainer.insert(this.slideShowButton);

			if(this.options.nextButtonImage.length > 0) {
				this.nextButton = new Element('img', {id:  this.options.nextButton, style: 'position: absolute; right: 0px; cursor: pointer;', src: this.options.nextButtonImage});
			} else {
				this.nextButton = new Element('span', {id: this.options.nextButton, style: 'position: absolute; right: 0px; cursor: pointer;'}).update('&rarr;');
			}
			this.nextButton.observe('click',this.next.bindAsEventListener(this));
			this.controlsContainer.insert(this.nextButton);
		}

		// create the vertical controls
		if($(this.options.verticalControlsContainer)) {
			this.verticalControlsContainer = $(this.options.verticalControlsContainer);

			if(this.options.upButtonImage.length > 0) {
				this.upButton = new Element('img', {id:  this.options.upButton, style: 'position: relative; cursor: pointer;', src: this.options.upButtonImage});
			} else {
				this.upButton = new Element('div', {id: this.options.upButton, style: 'position: relative; cursor: pointer;'}).update('&uarr;');
			}
			this.upButton.observe('click',this.thumbsUp.bindAsEventListener(this));
			this.verticalControlsContainer.insert(this.upButton);

			if(this.options.downButtonImage.length > 0) {
				this.downButton = new Element('img', {id:  this.options.downButton, style: 'position: relative; cursor: pointer;', src: this.options.downButtonImage});
			} else {
				this.downButton = new Element('div', {id: this.options.downButton, style: 'position: relative; cursor: pointer;'}).update('&darr;');
			}
			this.downButton.observe('click',this.thumbsDown.bindAsEventListener(this));
			this.verticalControlsContainer.insert(this.downButton);
		}

		// TODO add speed controls

		// get thumb container statistics
		var liObjs = this.thumbsUl.getElementsByTagName('li');
		
		this.thumbCols = 7;
		this.thumbRows = Math.ceil(liObjs.length / 7);
		
		this.thumbContainerWidth;
		this.thumbContainerHeight;
		
		liObjs[0].getElementsByTagName('img')[0].observe('load', function (event) {
			this.thumbContainerWidth = $('gallery_thumb_container').getElementsByTagName('li')[0].getWidth() * 7;
			this.thumbContainerHeight = $('gallery_thumb_container').getElementsByTagName('li')[0].getHeight();
		}.bindAsEventListener(this));
		
				
		// let's start this show
		this.next();
	},
	prev: function() {
		this._goto((this.imageIndex == 0? this.imageArr.length: this.imageIndex) - 1);
	},
	next: function() {
		this._goto((this.imageIndex + 1) % this.imageArr.length);
	},
	select: function(event) {
		this._goto(parseInt(Event.element(event).id.toString().split('_').pop()));
	},
	toggleSlideShow: function() {
		if(this.slideShowTimerPointer == null) {
			this._slideShowNext();
			this.slideShowButton.src = '/images/stopSlideshow.gif';
		} else if(this.slideShowTimerPointer) {
			clearInterval(this.slideShowTimerPointer);
			this.slideShowTimerPointer = null;
			this.slideShowButton.src = '/images/slideshow.gif';
		}
	},
	thumbsUp: function() {
		return this._moveThumbs(this.thumbRowIndex - 1);
	},
	thumbsDown: function() {
		return this._moveThumbs(this.thumbRowIndex + 1);
	},
	thumbsSelect: function() {
		return this._moveThumbs(this.thumbRowIndex); // kind of lame but I have no gui to choose which row
	},
	highlightThumb: function(event) {
		var index = parseInt(Event.element(event).id.toString().split('_').pop());
		if(index != this.imageIndex) new Effect.Opacity(this.thumbArr[index], {duration: 0.5, from: 0.5, to: 1.0});
	},
	unhighlightThumb: function(event) {
		var index = parseInt(Event.element(event).id.toString().split('_').pop());
		if(index != this.imageIndex) new Effect.Opacity(this.thumbArr[index], {duration: 0.5, from: 1.0, to: 0.5});
	},
	speedUp: function() {
		if(this.slideShowSpeed<10) this.slideShowSpeed++;
		return this.slideShowSpeed;
	},
	speedDown: function() {
		if(this.slideShowSpeed>1) this.slideShowSpeed--;
		return this.slideShowSpeed;
	},
	speedSelect: function(newSpeed) {
		if(newSpeed > 0 && newSpeed <= 10) this.slideShowSpeed = newSpeed;
		return this.slideShowSpeed;
	},
	_slideShowNext: function() {
		this.next();
		this.slideShowTimerPointer = setTimeout(this._slideShowNext.bind(this), this.slideShowSpeed * 800);
		// used setTimeout instead of setInterval so you can change the speed while it is playing
	},
	_moveThumbs: function(newThumbRowIndex) {
		if(newThumbRowIndex < 0) newThumbRowIndex = (this.thumbRows - 1);
		if(newThumbRowIndex >= this.thumbRows) newThumbRowIndex = 0;

		new Effect.Move (this.thumbsUl, {y: 0 - (newThumbRowIndex * this.thumbContainerHeight), mode: 'absolute'});

		this.thumbRowIndex = newThumbRowIndex;

		return true;
	},
	_goto: function(newIndex) {
		if(this.imageIndex == newIndex) return true;

		this._moveThumbs(Math.floor(newIndex / this.thumbCols));

		var effectsArr = new Array();

		if(this.imageIndex >= 0 && this.imageIndex < this.imageArr.length) {
			effectsArr.push(new Effect.Opacity(this.imageArr[this.imageIndex], {sync: true, from: 1.0, to: 0.0}));
			effectsArr.push(new Effect.Opacity(this.thumbArr[this.imageIndex], {sync: true, from: 1.0, to: 0.5}));
		}
		if(newIndex >= 0 && newIndex < this.imageArr.length) {
			effectsArr.push(new Effect.Opacity(this.imageArr[newIndex], {sync: true, from: 0.0, to: 1.0}));
			effectsArr.push(new Effect.Opacity(this.thumbArr[newIndex], {sync: true, from: 0.5, to: 1.0}));
		}

		if(effectsArr.length > 0) new Effect.Parallel(effectsArr, { duration: 1 });

		return this.imageIndex = newIndex;
	}
});
