/*
Class: Gallery
	The last gallery we'll ever use...

TODO v0.8
	- automatic resizing
  - crossfading of images (can this be used with reflections?)
	- multiple line comments and titles

TODO v1.0 RC1
	- initialize images so new images can be loaded on the fly
	- cleeeean and optimize (more)
	- get rid of all unnecessary ID's... elements should be generic
	- eliminate external styles... woo this is gonna be rough
	
	- enhancements
		- 'view' option should start the gallery in that view (doesnt work for view : 2)
		- thumbnail sizing integrated right into view 3?
		- implement color options... (themes?)
	
	- bugs
		- going from view 1 to 0, if moving, it jumps to stop

*/
var Gallery = new Class({
	version:'0.88',
	
	options: {
		url               : false,
		
		view              : 1,
		crossfade         : false, //see TODO in getImage()
		autoScroll        : false,
		
		reflection        : false,
		reflectionHeight  : 100,
		reflectionOpacity : 0.25,
		
		//imageDir          : 'image/',
		imageDir          : 'remotecontrol/Images/',
		//thumbDir          : 'thumb/',
		thumbDir          : 'remotecontrol/Images/thumb/',
		thumbSize         : 40,
		thumbBorder       : 1,
		thumbMargin       : 4,
		thumbClass        : 'thumb',
		thumbClassActive  : 'active',
		
		showTitle         : true,
		showCaption       : true,
		
		galleryColor      : '#555',
		gallerySize       : 500,
		
		onImageSetLoad    : Class.empty,
		
		disableRightClick : false
	},
	
	initialize: function(gallery, sources, titles, captions, options){
		this.setOptions(options);
		
		if(!window.Reflection || window.khtml) this.options.reflection = false; //need to include the reflection class in order to use...
		if(this.options.reflection == false) this.options.reflectionHeight = this.options.reflectionOpacity = 0;
		
		this.view     = -1;
		this.lastView = -1;
		this.imageSet = -1;
		this.idle     = true;
		this.id       = gallery; //if its a string, use that.  if its an element, use the elements id. otherwise use 'gallery'
		this.gallery  = $(gallery).setStyle('visibility', 'hidden');
		
		this.initializeComponents();
		this.initializeEffects();

		if(sources) this.loadImageSet(1, sources, titles, captions, false);
		document.addEvent('keydown', this.keyPressed.bind(this));
		
		if(this.options.disableRightClick) this.gallery.addEvent('contextmenu', function(ev){ new Event(ev).stop(); return false;});
	},
	
	galleryLoaded: function() {
		//console.log(this.image.width == 0 ,  this.image.complete == false ,  !this.imageReady ,  !this.ready);
		if(this.image.width == 0 || this.image.complete == false || !this.imageReady || !this.ready) return;
		
		$clear(this.check);
		this.buffer.setStyles({'margin-left' : this.options.gallerySize * 0.5 - this.buffer.getSize().size.x * 0.5});
		this.updateText(this.image.getSize().size);
		this.image.removeEvents('load').addEvent('load', this.fixImage.bind(this));
		
		this.fireEvent('onLoad');
		
		this.view = -1;
		this.show.delay(500, this, this.options.view);
	},
	
	loadImageSet: function(id, sources, titles, captions) {
		/*
		if(this.imageSet == id) {
			this.fireEvent('onImageSetLoad');
			this.galleryLoaded();
			return;
		}
		*/
		
		this.check = this.galleryLoaded.periodical(100, this);
		
		if(!this.options.url) this.sources = sources;
		else this.sources = sources.map(function(item, index){ return this.options.url + item; }.bind(this));
		
		if(!this.imageLoader) {
			this.imageLoader = new ImageLoader(this.sources, {
				loadingDiv : this.loadingDiv,
				onComplete : function(){
					this.initializeImages($A(arguments), titles, captions);
				}.bind(this)
			});
		}
		else {
			this.view = -1;
			this.imageLoader.reset();
			new Fx.Elements([this.gallery, this.loadingDiv], {
				onComplete:function(){
					this.imageLoader.loadImages(this.sources);
				}.bind(this)
			}).start({
				'0' : { 'opacity' : 0 },
				'1' : { 'opacity' : 1 }
			});
		}
		
		this.imageSet = id;
	},
	
	initializeImages: function(images, titles, captions) {
		this.thumbTray.innerHTML = '';
		this.images = {
			index    : 0,
			thumbs   : images,
			titles   : titles,
			captions : captions,
			total    : images.length
		};
		
		this.images.thumbs.each(function(e,i){
			e.addEvents({
				'mouseout'  : function(){ this.hidePreview(); }.bind(this),
				'mouseover' : function(){ this.showPreview(i); }.bind(this),
				'mousedown' : function(){ this.getImage(i); }.bind(this) }).
			setProperty('class', this.options.thumbClass).
			setStyles({'width' : this.options.thumbSize, 'height' : this.options.thumbSize, 'margin' : this.options.thumbMargin }).
			injectInside(this.thumbTray);
		}, this);
		
		this.controlDiv.getLast().setHTML('1 / ' + this.images.total);
		this.buffer.src = this.image.src = this.images.thumbs[0].src.replace(this.options.thumbDir, this.options.imageDir);
		
		this.images.thumbs[0].addClass(this.options.thumbClassActive);
		this.setThumbSize(this.options.thumbSize);
		
		var ready = function(){ this.ready = true; }.delay(500, this);
		this.fireEvent('onImageSetLoad');
	},
	
	initializeComponents: function() {
		this.gallery.setStyles({
			'width'   : this.options.gallerySize
		});

		this.thumbDiv  = new Element('div', { 'id' : this.id + '-thumb-div' }).injectInside(this.gallery);	
		this.imageDiv  = new Element('div', { 'id' : this.id + '-image-div' }).injectAfter(this.thumbDiv);
		this.thumbTray = new Element('div', { 'id' : this.id + '-thumb-tray' }).injectInside(this.thumbDiv);		
		
		
		/* CONTROL DIV */
		this.controlDiv = new Element('div', {'id' : this.id + '-control'}).
			adopt(new Element('span', {'events' : {'click' : function(){this.getPrev()}.bind(this) }, 'styles' : {'float' : 'left'} }).setHTML('&laquo; prev')).
			adopt(new Element('span', {'events' : {'click' : function(){this.getNext()}.bind(this) }, 'styles' : {'float' : 'right'} }).setHTML('next &raquo;')).
			adopt(new Element('div')).
			injectInside(this.imageDiv);
		
		
		/* TITLE DIV */
		if(this.options.showTitle){
			this.titleDiv  = new Element('div', {
				'id' : this.id + '-title-div',
				'styles' : { 'width' : this.options.gallerySize }
			}).injectInside(this.imageDiv).setOpacity(0.4);
			this.titleTray = new Element('div', {
				'id' : this.id + '-title-tray',
				'styles' : { 'width' : this.options.gallerySize }
			}).injectInside(this.imageDiv);
		}
		
		
		/* CAPTION DIV */
		if(this.options.showCaption){
			this.captionDiv  = new Element('div', {
				'id' : this.id + '-caption-div',
				'styles' : { 'width' : this.options.gallerySize }
			}).injectInside(this.imageDiv).setOpacity(0.4);
			this.captionTray = new Element('div', {
				'id' : this.id + '-caption-tray',
				'styles' : { 'width' : this.options.gallerySize }
			}).injectInside(this.imageDiv);
		}
		
		
		/* BUFFER TRAY*/
		this.buffer = new Element('img', {
			'alt' : '',
			'id'  : this.id + '-buffer'
		});
		this.bufferReflectionDiv = new Element('div', {
			'id' : this.id + '-buffer-reflection',
			'styles' : { 'height' : this.options.reflectionHeight }
		});
		this.bufferTray = new Element('div', {
			'id' : this.id + '-buffer-tray'
		}).
			injectInside(this.imageDiv).
			adopt(this.buffer).
			adopt(this.bufferReflectionDiv);
			
		/* IMAGE TRAY */
		this.image = new Element('img', {
			'alt' : '',
			'id' : this.id + '-image'
		});
		this.imageReflectionDiv = new Element('div', {
			'id' : this.id + '-image-reflection',
			'styles' : { 'height' : this.options.reflectionHeight }
		});
		this.imageTray = new Element('div', {
			'id' : this.id + '-image-tray',
			'styles' : { 'top' : this.controlDiv.getSize().size.y }
		}).
			injectInside(this.imageDiv).
			adopt(this.image).
			adopt(this.imageReflectionDiv);
		
		/* LOADING DIV */
		//need to actually create and style this...
		this.loadingDiv = $('loading');
		
		/* REFLECTIONS */
		if(this.options.reflection){
			this.imageReflection  = new Reflection(this.image,  this.imageReflectionDiv,  { height:this.options.reflectionHeight, opacity:this.options.reflectionOpacity });
			this.bufferReflection = new Reflection(this.buffer, this.bufferReflectionDiv, { height:this.options.reflectionHeight, opacity:this.options.reflectionOpacity });
		}
		
		this.buffer.addEvent('load', function(){
			var dims = this.resetImage(this.buffer);
			if (this.options.reflection) {
				this.bufferReflection.reflect(this.buffer);
				this.bufferReflectionDiv.getFirst().setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});				
			}
		}.bind(this));
		
		this.image.addEvent('load', function(){
			var dims = this.resetImage(this.image);
			if (this.options.reflection) {
				this.imageReflection.reflect(this.image);
				this.imageReflectionDiv.getFirst().setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});
			}
			this.imageReady = true;
		}.bind(this));
		
		
		/* PREVIEW DIV */
		this.previewDiv = new Element('div', {'id' : this.id + '-preview'}).
			adopt(new Element('span')).
			adopt(new Element('h1')).
			adopt(new Element('img')).
			adopt(new Element('div')).
			injectInside(document.body).
			setOpacity(0);
		
		this.gallery.addEvent('mousemove', function(ev){ var e = new Event(ev); this.previewDiv.setStyles({'left' : 10 + e.page.x, 'top': 10 + e.page.y})}.bind(this));
	},

	initializeEffects: function() {
		this.fadePreview   = this.previewDiv.effect('opacity', { duration:250, wait:false});
		
		this.scrollClick   = new Fx.Scroll(this.thumbDiv);
		this.scrollMotion  = new Scroller(this.thumbDiv, { area: .1 * this.options.gallerySize, velocity: .2 });
		
		this.viewChanger   = new Fx.Elements([this.thumbDiv, this.imageDiv, this.imageTray, this.bufferTray], { duration:800, onComplete:function(){
			if(this.view < 2) {
				this.thumbTray.setStyle('width', this.thumbTrayWidth);
				this.focusImage(this.images.index, false);
			}
			if(this.view == 1) this.thumbDiv.effect('opacity', { duration:400 }).start(1);
			this.idle = true;
			
			if(this.gallery.getStyle('opacity') == 0) {
				new Fx.Elements([this.gallery, this.loadingDiv]).start({
					'0' : { 'opacity' : 1 },
					'1' : { 'opacity' : 0 }
				});
			}
		}.bind(this) });
	},
	
	getImage: function(i) {
		if(this.images.index != i && this.idle) {
			this.controlDiv.getLast().setHTML('loading');
			this.idle = false;
			this.images.thumbs[this.images.index].removeClass(this.options.thumbClassActive);
			this.images.thumbs[i].addClass(this.options.thumbClassActive);
			this.images.index = i;
			
			this.bufferImage();
			this.hidePreview();
			if(this.options.autoScroll) this.scrollMotion.reset();
			
			if(this.view < 2) {
				this.focusImage(this.images.index, true);			
				new Fx.Elements([this.titleDiv, this.titleTray, this.captionDiv, this.captionTray], { 
					onComplete:function(){ this.image.src = this.images.thumbs[this.images.index].src.replace(this.options.thumbDir, this.options.imageDir); }.bind(this)
				 }).start({
					'0' : { 'opacity' : 0 },
					'1' : { 'opacity' : 0 },
					'2' : { 'opacity' : 0 },
					'3' : { 'opacity' : 0 }
				});
			}
			else this.image.src = this.images.thumbs[this.images.index].src.replace(this.options.thumbDir, this.options.imageDir);
		}
	},
	
	resetImage: function(image){
		image.setStyles({ 'width'  : 'auto', 'height' : 'auto' });
		var dims = image.getSize().size;
		if (dims.y > dims.x) image.setStyles({ 'width'  : 'auto', 'height' : this.options.gallerySize });
		else image.setStyles({ 'width'  : this.options.gallerySize, 'height' : 'auto' });
		return image.getSize().size;
	},
	
	bufferImage: function() {
		this.buffer.src = this.image.src.replace(this.options.thumbDir, this.options.imageDir);
		
		var dims = this.resetImage(this.buffer);
		this.buffer.setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});
		
		if(this.options.reflection) {
			this.bufferReflection.reflect(this.buffer);
			this.bufferReflectionDiv.getFirst().setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});
		}
		
		this.bufferTray.setStyles({'opacity' : 1, 'height' : (this.view == 0 ? this.options.reflectionHeight : 0) + dims.y});
	},
	
	fixImage: function() {
		var dims = this.resetImage(this.image);
		
		this.updateText(dims);
		this.image.setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});
		
		if(this.options.reflection) {
			this.imageReflection.reflect(this.image);
			this.imageReflectionDiv.getFirst().setStyles({'margin-left' : this.options.gallerySize * 0.5 - dims.x * 0.5});
		}
		
		var height = (this.view == 0 ? this.options.reflectionHeight : 0) + this.controlDiv.getSize().size.y + dims.y;
		
		if(this.view < 2) {
			new Fx.Elements([this.titleDiv, this.captionDiv, this.titleTray, this.captionTray, this.imageDiv, this.imageTray, this.bufferTray], { 
				onComplete:function(){ this.idle = true; }.bind(this)
			 }).start({
				'0' : { 'opacity' : 0.5 },
				'1' : { 'opacity' : 0.5 },
				'2' : { 'opacity' : 1 },
				'3' : { 'opacity' : 1 },
				'4' : { 'height'  : height },
				'5' : { 'height'  : height },
				'6' : { 'height'  : height, 'opacity' : 0 }
			});
		}
		else {
			this.bufferTray.setOpacity(0);
			$$(this.titleDiv, this.captionDiv).setOpacity(0.5);
			$$(this.titleTray, this.captionTray).setOpacity(1);
			this.idle = true;
			this.show(this.lastView);
		}
	},
	
	updateText: function(idims) {
		this.controlDiv.getLast().setHTML(this.images.index + 1 + ' / ' + this.images.total);
		
		if(this.options.showTitle) {
			var title = unescape(this.images.titles[this.images.index]).trim();
			this.titleTray.setHTML(title);
			var tH = this.titleTray.getSize().size.y;
			
			this.titleDiv.setStyles({
				'height'  : tH,
				'display' : title == '' ? 'none' : ''
			});
		}
		
		if(this.options.showCaption) {
			var caption = unescape(this.images.captions[this.images.index]).trim();
			this.captionTray.setHTML(caption);
			var cH = this.captionTray.getSize().size.y;
			var cT = idims.y + this.controlDiv.getSize().size.y - cH;
			
			this.captionTray.setStyle('top', cT);
			this.captionDiv.setStyles({
				'top'     : cT,
				'height'  : cH,
				'display' : caption == '' ? 'none' : ''
			});
		}
	},
	
	show: function(view) {
		if(view == this.view || view < 0 || view >  2 || !this.idle) return;
		this.gallery.setStyle('visibility', 'visible');
		this.idle = false;
		this.lastView = this.view;
		if(this.options.autoScroll) this.scrollMotion.reset();
		
		switch(view) {
			case 0: var
				tH = 0,
				tO = 0,
				iH = this.image.getSize().size.y + this.controlDiv.getSize().size.y + this.options.reflectionHeight;
				break;
						
			case 1: var
				tH = this.thumbSize,
				tO = this.view == 0 ? 1 : this.images.index < Math.round(0.5 * this.options.gallerySize / this.thumbSize) ? 1 : 0,
				iH = this.image.getSize().size.y + this.controlDiv.getSize().size.y;
				break;
				
			case 2: var
				tH = this.thumbTrayHeight,
				tO = 1,
				iH = 0;
				break;
		}
		
		if(this.view == 1 && view == 2 && this.thumbDiv.scrollLeft > 0) {
			this.thumbDiv.effect('opacity', {duration:400, onComplete:function(){
				this.focusImage(0, false);
				this.thumbTray.setStyle('width', this.options.gallerySize);
				this.viewChanger.start({ '0' : { 'height' : tH, 'opacity' : tO }, '1' : { 'height' : iH }, '2' : { 'height' : iH }, '3' : { 'height' : iH } });
			}.bind(this) }).start(0);
		}
		else {
			this.focusImage(view == 2 ? 0 : this.images.index, false);
			if(view == 2) this.thumbTray.setStyle('width', this.options.gallerySize);
			this.viewChanger.start({ '0' : { 'height' : tH, 'opacity' : tO }, '1' : { 'height' : iH }, '2' : { 'height' : iH }, '3' : { 'height' : iH } });
		}
		
		this.view = view;
	},
	
	
	setThumbSize: function(thumbSize) {
		this.thumbSize = thumbSize + 2 * this.options.thumbMargin + 2 * this.options.thumbBorder;
		this.thumbTrayWidth = this.thumbSize * this.images.total;
		this.thumbTrayHeight = Math.ceil(this.thumbTrayWidth / this.options.gallerySize) * this.thumbSize;
		this.thumbTrayOffset = 0;
		this.thumbTrayMaxOffset = this.thumbTrayWidth - this.options.gallerySize;
		
		if(this.view == 1) {
			this.thumbDiv.setStyle('height', this.thumbSize);
			this.thumbTray.setStyle('height', this.thumbSize);
		}
		if(this.view < 2) {
			this.thumbDiv.setStyle('width', this.options.gallerySize);
			this.thumbTray.setStyle('width', this.thumbTrayWidth);
		}
		this.images.thumbs.each(function(thumb){ thumb.setStyles({'width':thumbSize, 'height':thumbSize}) });
	},
	
	focusImage: function(i, smooth) {
		this.thumbTrayOffset = Math.max(0, Math.min(this.thumbTrayMaxOffset, (i + 0.5) * this.thumbSize - 0.5 * this.options.gallerySize));
		(smooth ? this.scrollClick : this.thumbDiv).scrollTo(this.thumbTrayOffset, 0);
	},
	
	getPrev: function() {
		this.getImage(this.images.index - 1 < 0 ? this.images.total - 1 : this.images.index - 1);
	},
	
	getNext: function() {
		this.getImage(this.images.index + 1 > this.images.total - 1 ? 0 : this.images.index + 1);
	},

	showPreview: function(i) {
		if(this.view != 2) return;
		
		var els = this.previewDiv.getChildren();
		els[0].setHTML(i+1 + ' / ' + this.images.total);
		//els[1].setHTML(this.images.titles[i]);
		//els[3].setHTML(this.images.captions[i]);
		els[3].setHTML(unescape(this.images.titles[i]));
		els[2].src = this.images.thumbs[i].src;
		
		this.images.captions[i] == '' ? els[3].hide() : els[3].show();
		
		var dims = els[2].getSize().size;
		if (dims.y > dims.x) els[2].setStyles({ 'width'  : 'auto', 'height' : '120px' });
		else els[2].setStyles({ 'width'  : '120px', 'height' : 'auto' });
		
		this.fadePreview.start(0.9);
	},
	
	hidePreview: function() {
		this.fadePreview.start(0);
	},
	
	keyPressed: function(ev) {
		var e = new Event(ev);
		switch(e.key) {
			case '1' : this.show(0); break;
			case '2' : this.show(1); break;
			case '3' : this.show(2); break;
			case 'left'  : this.getPrev(); break;
			case 'right' : this.getNext(); break;
		}
	}

});

Gallery.implement(new Events);
Gallery.implement(new Options);


Scroller.implement({
	reset: function(){
		this.stop();
		this.start.delay(500, this);
	}																		
});