/*
UvumiTools Gallery v1.0.2 http://tools.uvumi.com/gallery.html

Copyright (c) 2008 Uvumi LLC

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
 */

var UvumiGallery = new Class(
		{
			Implements : Options,
			options : {
				caption : true,
				thumbSize : 120,
				spacing : 40,
				loadingImg : 'images/loading.gif',
				missingThumbClass : 'missing-thumbnail',
				progressClass : 'progress-bar',
				errorMessageClass : 'error-message',
				captionClass : 'caption'
			},
			initialize : function(a) {
				this.setOptions(a);
				window.addEvent('domready', this.domReady.bind(this))
			},
			domReady : function() {
				this.container = $(this.options.container) || $$('body')[0];
				this.container
						.setStyles( {
							'position' : (this.container.getStyle('position') == 'absolute' ? 'absolute'
									: 'relative'),
							'width' : (this.container.getStyle('width') == 'auto' ? this.container
									.getSize().x
									: this.container.getStyle('width')),
							'height' : (this.container.getStyle('height') == 'auto' ? this.container
									.getSize().y
									: this.container.getStyle('height'))
						});
				this.anchors = this.container.getElements('a').dispose();
				this.nbrImages = this.anchors.length;
				this.images = new Hash();
				if (this.options.caption) {
					this.captions = new Hash()
				}
				this.anchors.each(this.getImageInfo, this);
				this.loaded = false;
				var a = new Asset.image(this.options.loadingImg);
				this.build();
				this.load()
			},
			getImageInfo : function(a) {
				var b = a.get('href');
				if (Browser.Engine.trident) {
					b = b.replace('about:', '')
				}
				var c = a.getFirst('img');
				var d = c.get('src');
				this.images.set(d, b);
				if (this.options.caption) {
					var e = c.get('alt');
					if ($defined(e)) {
						this.captions.set(b, e)
					}
				}
			},
			build : function() {
				this.pusher = new Element('div', {
					'styles' : {
						'position' : 'absolute',
						'width' : 1,
						'left' : 0
					}
				});
				this.container.setStyles( {
					'background-repeat' : 'no-repeat',
					'background-position' : 'center center'
				});
				this.error = new Element('div', {
					'html' : 'the image cannot be loaded.',
					'class' : this.options.errorMessageClass,
					'styles' : {
						'top' : 0,
						'left' : 0,
						'padding-left' : this.options.thumbSize
					}
				});
				this.resize();
				this.originalHeight = this.windowSize.y;
				if (this.options.caption) {
					this.caption = new Element('div', {
						'class' : this.options.captionClass,
						'styles' : {
							'position' : 'absolute',
							'top' : 0,
							'left' : 0,
							'padding' : 0,
							'height' : 0,
							'opacity' : 0.75,
							'z-index' : 99,
							'overflow' : 'hidden',
							'white-space' : 'nowrap'
						},
						'morph' : {
							'link' : 'cancel'
						},
						'events' : {
							'mouseenter' : function() {
								$clear(this.captionDelay)
							}.bind(this),
							'mouseleave' : function() {
								this.full.fireEvent('mouseleave')
							}.bind(this)
						}
					});
				}
				this.progressContainer = new Element(
						'div',
						{
							'class' : this.options.progressClass,
							'styles' : {
								'position' : 'absolute',
								'top' : (this.extraSpace + this.options.spacing) / 4,
								'height' : (this.extraSpace + this.options.spacing) / 2,
								'width' : this.windowSize.x / 2,
								'left' : this.windowSize.x / 4
							}
						}).inject(this.container);
				this.progresser = new Element(
						'div',
						{
							'styles' : {
								'height' : (this.extraSpace + this.options.spacing) / 2 - 2,
								'position' : 'absolute',
								'top' : 0,
								'left' : 0,
								'width' : 0,
								'margin' : '1px',
								'background-color' : this.progressContainer
										.getStyle('border-top-color')
							},
							'tween' : {
								'link' : 'cancel',
								'duration' : 'short'
							}
						}).inject(this.progressContainer);
				this.scrollArea = new Element('div', {
					styles : {
						position : 'absolute',
						top : 0,
						left : 0,
						width : this.options.thumbSize + this.extraSpace / 2,
						height : '100%'
					}
				}).inject(this.container);
				this.containerDefaultEvents();
				this.mode = "gallery"
			},
			resize : function() {
				this.windowSize = this.container.getSize();
				this.perLine = (this.windowSize.x / (this.options.thumbSize + this.options.spacing))
						.toInt();
				this.extraSpace = ((this.windowSize.x - this.options.spacing - (this.options.thumbSize + this.options.spacing)
						* this.perLine) / 2).toInt();
				this.mainImage = {
					x : this.windowSize.x - (this.options.thumbSize + 10) - 2
							* this.options.spacing,
					y : this.windowSize.y - 2 * this.options.spacing
				}
			},
			containerDefaultEvents : function() {
				this.repositionImages2 = function() {
					$clear(this.resizeDelay);
					$clear(this.resizeDelay2);
					this.resizeDelay = this.repositionImages.delay(300, this);
					if (this.full && this.loaded) {
						this.resizeDelay2 = this.positionFullSize.delay(400,
								this)
					}
				}.bind(this);
				window.addEvent('resize', this.repositionImages2);
				this.scroll = new Fx.Scroll(this.container, {
					duration : 'short'
				});
				this.grow = new Fx.Tween(this.container, {
					onStart : function() {
						window.removeEvent('resize', this.repositionImages2)
					}.bind(this),
					onComplete : function() {
						window.addEvent('resize', this.repositionImages2)
					}.delay(100, this)
				})
			},
			load : function() {
				this.ready = false;
				this.loadedThumbs = new Asset.images(this.images.getKeys(), {
					onProgress : this.displayThumb.bind(this),
					onComplete : this.imagesLoaded.bind(this),
					onError : this.thumbMissing.bind(this)
				})
			},
			displayThumb : function(a, b) {
				var c = this.loadedThumbs[b];
				this.progresser.tween('width',
						((this.windowSize.x * a) / (2 * this.nbrImages))
								.toInt() + 'px');
				var d = c.width / c.height;
				if (d < 1) {
					var e = true;
					var f = this.options.thumbSize;
					var g = this.options.thumbSize * d;
					var h = ((this.options.thumbSize - g) / 2).toInt();
					var i = 0
				} else {
					var e = false;
					var g = this.options.thumbSize;
					var f = (this.options.thumbSize / d).toInt();
					var i = ((this.options.thumbSize - f) / 2).toInt();
					var h = 0
				}
				c.store('width', c.width);
				c.store('height', c.height);
				var j = this.extraSpace + this.options.spacing
						+ Math.floor(b / this.perLine)
						* (this.options.thumbSize + this.options.spacing) + i;
				var k = this.extraSpace + this.options.spacing
						+ (b - this.perLine * Math.floor(b / this.perLine))
						* (this.options.thumbSize + this.options.spacing) + h;
				c.setStyles( {
					'opacity' : 0,
					'width' : g,
					'height' : f,
					'position' : 'absolute',
					'top' : j,
					'left' : k,
					'zIndex' : 0,
					'cursor' : 'pointer'
				}).inject(this.container);
				c.store('tag_width', g);
				c.store('tag_height', f);
				c.store('top', j);
				c.store('left', k);
				c.store('turned', e);
				c.store('add2top', i);
				c.store('add2left', h);
				c.store('path', this.images.getKeys()[b]);
				c.set('morph', {
					link : 'cancel'
				});
				c.get('morph').start( {
					opacity : 1
				}).chain(function() {
					this.attachDefaultEvents(c)
				}.bind(this))
			},
			thumbMissing : function(a, b) {
				this.progresser.tween('width',
						((this.windowSize.x * a) / (2 * this.nbrImages))
								.toInt() + 'px');
				var c = this.extraSpace + this.options.spacing
						+ Math.floor(b / this.perLine)
						* (this.options.thumbSize + this.options.spacing)
						+ this.options.thumbSize / 4;
				var d = this.extraSpace + this.options.spacing
						+ (b - this.perLine * Math.floor(b / this.perLine))
						* (this.options.thumbSize + this.options.spacing)
						+ this.options.thumbSize / 4;
				var e = this.images.getKeys()[b];
				var f = new Element('div', {
					'class' : this.options.missingThumbClass,
					'styles' : {
						'position' : 'absolute',
						'opacity' : 0,
						'width' : this.options.thumbSize / 2 - 2,
						'height' : this.options.thumbSize / 2 - 2,
						'top' : c,
						'left' : d,
						'zIndex' : 0
					}
				}).inject(this.container);
				this.loadedThumbs[b] = f;
				f.store('width', this.options.thumbSize - 2);
				f.store('height', this.options.thumbSize - 2);
				f.store('tag_width', this.options.thumbSize / 2 - 2);
				f.store('tag_height', this.options.thumbSize / 2 - 2);
				f.store('top', c);
				f.store('left', d);
				f.store('turned', true);
				f.store('add2top', this.options.thumbSize / 4);
				f.store('add2left', this.options.thumbSize / 4);
				f.store('path', e);
				f.set('morph', {
					link : 'cancel'
				});
				f.get('morph').start( {
					opacity : 1
				}).chain(function() {
					this.attachDefaultEvents(f)
				}.bind(this))
			},
			imagesLoaded : function() {
				this.loaded = true;
				this.ready = true;
				this.progressContainer.get('tween').start('opacity', 0).chain(
						function() {
							this.progressContainer.destroy()
						}.bind(this));
				this.imageFx = new Fx.Elements(this.loadedThumbs, {
					link : 'cancel'
				});
				this.animations = {};
				this.repositionImages()
			},
			attachDefaultEvents : function(a) {
				a.removeEvents();
				a.addEvents( {
					'mouseenter' : this.zoom.bindWithEvent(this),
					'mouseleave' : this.dezoom.bindWithEvent(this),
					'click' : this.toMenu.bindWithEvent(this)
				})
			},
			zoom : function(e) {
				var a = $(e.target);
				if (this.mouseDown) {
					return
				}
				a.store('zoomed', true);
				a.setStyle('zIndex', 2);
				var b = a.get('morph');
				b.clearChain();
				b.start( {
					'width' : a.retrieve('width'),
					'height' : a.retrieve('height'),
					'top' : (a.retrieve('top') - (a.retrieve('height') - a
							.retrieve('tag_height')) / 2).toInt(),
					'left' : (a.retrieve('left') - (a.retrieve('width') - a
							.retrieve('tag_width')) / 2).toInt()
				})
			},
			dezoom : function(e) {
				var a = $(e.target);
				a.store('zoomed', false);
				a.setStyle('zIndex', 1);
				var b = a.get('morph');
				b.clearChain();
				b.chain(function() {
					if (!this.retrieve('zoomed')) {
						this.setStyle('zIndex', 0)
					}
				}.bind(a));
				b.start( {
					'width' : a.retrieve('tag_width'),
					'height' : a.retrieve('tag_height'),
					'top' : a.retrieve('top'),
					'left' : a.retrieve('left')
				})
			},
			toMenu : function(e) {
				if (!this.ready) {
					return false
				}
				this.mode = 'menu';
				this.index = -1;
				this.mouseScroll = function(a) {
					this.scrolling = true;
					$clear(this.scrollDelay);
					this.scrollDelay = function() {
						this.scrolling = false;
						this.loadHiRez()
					}.delay(500, this);
					this.scrollSideBar(a)
				}.bindWithEvent(this);
				this.scrollArea.addEvent('mousewheel', this.mouseScroll);
				this.loadedThumbs.each(this.attachScrollEvents, this);
				this.scrollSideBar(e)
			},
			attachScrollEvents : function(a) {
				a.removeEvents();
				var b = a.get('morph');
				b.cancel().clearChain();
				a.addEvents( {
					'mouseenter' : function() {
						b.start( {
							opacity : 1
						});
						this.thumbOpacChain(a);
						a.store('timer', this.thumbOpacChain.periodical(1000,
								this, a))
					}.bind(this),
					'mouseleave' : function() {
						$clear(a.retrieve('timer'));
						b.start( {
							opacity : this.retrieve('opa')
						})
					},
					'click' : this.scrollSideBar.bindWithEvent(this)
				})
			},
			thumbOpacChain : function(a) {
				var b = a.get('morph');
				b.start( {
					opacity : 1
				}).chain(function() {
					b.start( {
						opacity : a.retrieve('opa')
					})
				})
			},
			scrollSideBar : function(e) {
				this.mouseDown = false;
				e.stop();
				var a = this.images.getKeys();
				var b = this.getImgForScroll(e, a);
				if (b == this.index) {
					return
				}
				this.index = b;
				this.start = this.max(this.index - 3, 0);
				this.stop = this.min(this.index + 3, a.length - 1);
				if (this.scrolling) {
					this.repositionImages()
				} else {
					this.grow.start('height', this.originalHeight).chain(
							function() {
								this.repositionImages();
								this.loadHiRez()
							}.bind(this))
				}
			},
			getImgForScroll : function(a, b) {
				if (a.wheel < 0) {
					return this.min(b.length - 1, this.index + 1)
				} else if (a.wheel > 0) {
					return this.max(0, this.index - 1)
				} else {
					return b.indexOf($(a.target).retrieve('path'))
				}
			},
			loadHiRez : function() {
				this.mouseDown = false;
				var a = this.images.getValues()[this.index];
				var b = this.loadedThumbs[this.index];
				this.loaded = false;
				if (this.full) {
					this.full.fireEvent('mouseleave').destroy();
					this.full = false
				}
				this.container.setStyle('background-image',
						'url(' + this.options.loadingImg + ')');
				this.error.dispose();
				this.full = new Asset.image(a, {
					onload : this.displayHiRez.bind(this, b),
					onerror : this.displayError.bind(this, a)
				});
				this.full.store('turned', b.retrieve('turned'));
				this.full.store('path', a)
			},
			displayError : function(a) {
				if (this.loaded) {
					return
				}
				this.full = false;
				this.error.set('html', 'The image ' + a + ' could not load.');
				this.error.setStyles( {
					'top' : this.windowSize.y / 2
				}).inject(this.container);
				this.container.setStyle('background-image', '')
			},
			displayHiRez : function(a) {
				this.container.setStyle('background-image', '');
				var b = a.getCoordinates(this.container);
				this.full.setStyles( {
					'position' : 'absolute',
					'width' : b.width,
					'height' : b.height,
					'top' : b.top,
					'left' : b.left,
					'opacity' : 0,
					'cursor' : 'pointer',
					'z-index' : 90
				}).inject(this.container);
				if (this.caption) {
					var c = "";
					if (this.captions.has(this.full.retrieve('path'))) {
						c = this.captions.get(this.full.retrieve('path'))
					}
					this.caption.set('html', c);
				}
				this.loaded = true;
				this.full.set('morph', {
					link : 'ignore'
				});
				this.positionFullSize()
			},
			toGallery : function(e) {
				$clear(this.scrollDelay);
				this.scrolling = false;
				this.mode = 'gallery';
				var a = new Event(e).stop();
				var b = $(a.target);
				b.fireEvent('mouseleave');
				this.loadedThumbs.removeEvents();
				this.loadedThumbs.each(this.attachDefaultEvents, this);
				this.scrollArea.removeEvent('mousewheel', this.mouseScroll);
				this.container.setStyle('background-image', '');
				this.repositionImages();
				if (this.full) {
					this.full.fireEvent('mouseleave');
					this.full.get('morph').start( {
						opacity : 0
					}).chain(function() {
						if (this.caption) {
							this.caption.dispose();
							this.full.destroy();
							this.full = false
						}
					}.bind(this))
				}
			},
			repositionImages : function() {
				this.resize();
				this.ready = false;
				this.scroll.toTop();
				if (this.mode == "gallery") {
					if (!this.loaded) {
						return
					}
					this.loadedThumbs
							.each(
									function(a, b) {
										var c = (this.extraSpace
												+ this.options.spacing
												+ Math.floor(b / this.perLine)
												* (this.options.thumbSize + this.options.spacing) + a
												.retrieve('add2top')).toInt();
										var d = (this.extraSpace
												+ this.options.spacing
												+ (b - this.perLine
														* Math.floor(b
																/ this.perLine))
												* (this.options.thumbSize + this.options.spacing) + a
												.retrieve('add2left')).toInt();
										a.store('top', c);
										a.store('left', d);
										this.animations[b] = {
											'opacity' : 1,
											'width' : a.retrieve('tag_width'),
											'height' : a.retrieve('tag_height'),
											'top' : c,
											'left' : d,
											'zIndex' : 0
										}
									}, this);
					var e = true
				} else {
					this.loadedThumbs
							.each(
									function(a, i) {
										var z = i - this.index;
										var b = 1 / (1 + 1.2 * (Math.abs(z)));
										var c = this.windowSize.y
												* (1 + 1.1 * z
														/ (2 + (Math.abs(z))))
												/ 2
												- (this.options.thumbSize + this.options.spacing)
												/ 2;
										a
												.setStyles( {
													'display' : 'block',
													'visibility' : 'visible',
													'z-index' : this.loadedThumbs.length
															- Math.abs(z)
												});
										if ((i < this.start) || (i > this.stop)) {
											var d = 0
										} else {
											var d = b
										}
										a.store('opa', d);
										this.animations[i] = {
											'top' : (c + (this.options.thumbSize - a
													.retrieve('tag_height')
													* b) / 2).toInt(),
											'left' : (10 + (this.options.thumbSize - a
													.retrieve('tag_width')
													* b) / 2).toInt(),
											'width' : (a.retrieve('tag_width') * b)
													.toInt(),
											'height' : (a
													.retrieve('tag_height') * b)
													.toInt(),
											'opacity' : d
										}
									}, this);
					var e = false
				}
				this.imageFx.start(this.animations).chain(function() {
					this.ready = true;
					this.updatePusher(e)
				}.bind(this))
			},
			positionFullSize : function() {
				var c = this.full.getSize();
				var d = this.full.clone();
				d.setStyles( {
					visibility : 'hidden',
					width : 'auto',
					height : 'auto'
				}).inject(this.container);
				var e = d.getSize();
				d.destroy();
				if (this.full.retrieve('turned')) {
					var f = this.min(this.mainImage.y, e.y);
					var g = (e.x * f / e.y).toInt();
					if (g > this.mainImage.x) {
						var g = this.mainImage.x;
						var f = (e.y * g / e.x).toInt()
					}
				} else {
					var g = this.min(this.mainImage.x, e.x);
					var f = (e.y * g / e.x).toInt();
					if (f > this.mainImage.y) {
						var f = this.mainImage.y;
						var g = (e.x * f / e.y).toInt()
					}
				}
				var h = (this.options.spacing + (this.mainImage.y - f) / 2)
						.toInt();
				var i = (this.options.thumbSize + 10 + this.options.spacing + (this.mainImage.x - g) / 2)
						.toInt();
				this.full
						.get('morph')
						.start( {
							'opacity' : 1,
							'left' : i,
							'top' : h,
							'width' : g,
							'height' : f
						})
						.chain(
								function() {
									this.ready = true;
									this.updatePusher();
									if (this.caption) {
										var b = this.full
												.getCoordinates(this.container);
										this.caption.setStyles( {
											'top' : b.bottom + 'px',
											'height' : 0,
											'left' : b.left - 1,
											'width' : b.width + 2
										}).inject(this.container);
										this.full.removeEvents();
										this.full
												.addEvents( {
													'mouseenter' : function() {
														if (!this.ready) {
															return
														}
														$clear(this.captionDelay);
														var a = this.full
																.getCoordinates(this.container);
														this.caption
																.get('morph')
																.start(
																		{
																			'top' : a.bottom - 18,
																			'height' : 19,
																			'text-align' : 'center'
																		})
													}.bind(this),
													'mouseleave' : function() {
														var a = this.full
																.getCoordinates(this.container);
														this.captionDelay = (function() {
															this.caption
																	.get(
																			'morph')
																	.start(
																			{
																				'top' : a.bottom,
																				'height' : 0
																			})
														}).delay(100, this)
													}.bind(this),
													'mousemove' : function() {
														this
																.removeEvents('mousemove');
														this
																.fireEvent('mouseenter')
													},
													'click' : this.toGallery
															.bind(this)
												})
									} else {
										this.full.removeEvents();
										this.full.addEvent('click',
												this.toGallery.bind(this))
									}
								}.bind(this))
			},
			updatePusher : function(a) {
				this.container.setStyle('overflow', 'hidden');
				this.pusher.dispose();
				if (a) {
					this.pusher
							.setStyles(
									{
										'top' : this.loadedThumbs[this.loadedThumbs.length - 1]
												.getCoordinates(this.container).bottom,
										'height' : this.extraSpace
												+ this.options.spacing
									}).inject(this.container);
					this.grow.start('height', this.pusher
							.getCoordinates(this.container).bottom);
					this.resize()
				}
			},
			destroy : function() {
				this.container.empty();
				window.removeEvent('resize', this.repositionImages2);
				this.scrollArea.removeEvent('mousewheel', this.mouseScroll)
			},
			min : function(a, b) {
				return ((a < b) ? a : b)
			},
			max : function(a, b) {
				return ((a > b) ? a : b)
			}
		});
Asset.set('images', function(c, d) {
	d = $merge( {
		onComplete : $empty,
		onProgress : $empty,
		onError : $empty
	}, d);
	if (!c.push)
		c = [ c ];
	var e = [];
	var f = 0;
	c.each(function(a) {
		var b = new Asset.image(a, {
			'onload' : function() {
				d.onProgress.call(this, f, c.indexOf(a));
				f++;
				if (f == c.length)
					d.onComplete()
			},
			'onerror' : function() {
				d.onError.call(this, f, c.indexOf(a));
				f++;
				if (f == c.length)
					d.onComplete()
			}
		});
		e.push(b)
	});
	return new Elements(e)
});
