/*
 * Ext Core Library Examples 3.0 Beta http://extjs.com/ Copyright(c) 2006-2009, Ext JS, LLC. The MIT License 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.
 */
Ext.namespace('Ext.ux');
Ext.ux.Lightbox = (function() {
	var els = {}, images = [], activeImage, initialized = false, selectors = [];
	return {
		overlayOpacity : 0.85,
		animate : false,
		resizeSpeed : 8,
		borderSize : 10,
		labelImage : "Image",
		labelOf : "of",
		init : function() {
			this.resizeDuration = this.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
			this.overlayDuration = this.animate ? 0.2 : 0;
			if (!initialized) {
				Ext.apply(this, Ext.util.Observable.prototype);
				Ext.util.Observable.constructor.call(this);
				this.addEvents('open', 'close');
				this.initMarkup();
				this.initEvents();
				initialized = true;
			}
		},
		initMarkup : function() {
			els.overlay = Ext.DomHelper.append(document.body, {
				id : 'ux-lightbox-overlay'
			}, true);
			var lightboxTpl = new Ext.Template(this.getTemplate());
			els.lightbox = lightboxTpl.append(document.body, {}, true);
			var ids = 'outerImageContainer imageContainer image hoverNav navPrev navNext loading loadingLink ' + 'outerDataContainer dataContainer data details caption imageNumber bottomNav navClose';
			Ext.each(ids.split(' '), function(id) {
				els[id] = Ext.get('ux-lightbox-' + id);
			});
			els.overlay.visibilityMode = els.lightbox.visibilityMode = /* els.shim.visibilityMode = */Ext.Element.DISPLAY;
			els.overlay.hide();
			els.lightbox.hide();
			var size = (this.animate ? 250 : 1) + 'px';
			els.outerImageContainer.setStyle({
				width : size,
				height : size
			});
		},
		getTemplate : function() {
			return [
				'<div id="ux-lightbox">', '<div id="ux-lightbox-outerImageContainer">', '<div id="ux-lightbox-imageContainer">', '<img id="ux-lightbox-image">', '<div id="ux-lightbox-hoverNav">', '<a href="#" id="ux-lightbox-navPrev"></a>', '<a href="#" id="ux-lightbox-navNext"></a>', '</div>', '<div id="ux-lightbox-loading">', '<a id="ux-lightbox-loadingLink"></a>', '</div>', '</div>', '</div>', '<div id="ux-lightbox-outerDataContainer">', '<div id="ux-lightbox-dataContainer">',
				'<div id="ux-lightbox-data">', '<div id="ux-lightbox-details">', '<span id="ux-lightbox-caption"></span>', '<span id="ux-lightbox-imageNumber"></span>', '</div>', '<div id="ux-lightbox-bottomNav">', '<a href="#" id="ux-lightbox-navClose"></a>', '</div>', '</div>', '</div>', '</div>', '</div>'
			];
		},
		initEvents : function() {
			var close = function(ev) {
				ev.preventDefault();
				this.close();
			};
			els.overlay.on('click', close, this);
			els.loadingLink.on('click', close, this);
			els.navClose.on('click', close, this);
			els.lightbox.on('click', function(ev) {
				if (ev.getTarget().id == 'ux-lightbox') {
					this.close();
				}
			}, this);
			els.navPrev.on('click', function(ev) {
				ev.preventDefault();
				this.setImage(activeImage - 1);
			}, this);
			els.navNext.on('click', function(ev) {
				ev.preventDefault();
				this.setImage(activeImage + 1);
			}, this);
		},
		register : function(sel, group) {
			if (selectors.indexOf(sel) === -1) {
				selectors.push(sel);
				Ext.fly(document).on('click', function(ev) {
					try {
						var target = ev.getTarget(sel);
						if (target) {
							ev.preventDefault();
							this.open(target, sel, group);
						}
					} catch (e) {}
				}, this);
			}
		},
		open : function(image, sel, group) {
			group = group || false;
			var viewSize = this.getViewSize();
			els.overlay.setStyle({
				width : viewSize[0] + 'px',
				height : viewSize[1] + 'px'
			});
			Ext.select('object').setStyle('visibility', 'hidden');
			Ext.select('embed').setStyle('visibility', 'hidden');
			els.overlay.fadeIn({
				duration : this.overlayDuration,
				endOpacity : this.overlayOpacity,
				callback : function() {
					images = [];
					var index = 0;
					if (!group) {
						images.push([
							image.href, image.title
						]);
					} else {
						var setItems = Ext.query(sel);
						Ext.each(setItems, function(item) {
							if (item.href) {
								images.push([
									item.href, item.title
								]);
							}
						});
						while (images[index][0] != image.href) {
							index++;
						}
					};
					var pageScroll = Ext.fly(document).getScroll();
					var lightboxTop = pageScroll.top + (Ext.lib.Dom.getViewportHeight() / 10);
					var lightboxLeft = pageScroll.left;
					els.lightbox.setStyle({
						top : lightboxTop + 'px',
						left : lightboxLeft + 'px'
					}).show();
					this.setImage(index);
					this.fireEvent('open', images[index]);
				},
				scope : this
			});
		},
		setImage : function(index) {
			activeImage = index;
			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}
			els.image.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.dataContainer.setOpacity(0.0001);
			els.imageNumber.hide();
			var preload = new Image();
			preload.onload = (function() {
				els.image.dom.src = images[activeImage][0];
				this.resizeImage(preload.width, preload.height);
			}).createDelegate(this);
			preload.src = images[activeImage][0];
		},
		resizeImage : function(w, h) {
			var wCur = els.outerImageContainer.getWidth();
			var hCur = els.outerImageContainer.getHeight();
			var wNew = (w + this.borderSize * 2);
			var hNew = (h + this.borderSize * 2);
			var wDiff = wCur - wNew;
			var hDiff = hCur - hNew;
			var queueLength = 0;
			if (hDiff != 0 || wDiff != 0) {
				els.outerImageContainer.syncFx().shift({
					height : hNew,
					duration : this.resizeDuration
				}).shift({
					width : wNew,
					duration : this.resizeDuration
				});
				queueLength++;
			}
			var timeout = 0;
			if ((hDiff == 0) && (wDiff == 0)) {
				timeout = (Ext.isIE) ? 250 : 100;
			}
			(function() {
				els.hoverNav.setWidth('100%');
				els.navPrev.setHeight(h + 'px');
				els.navNext.setHeight(h + 'px');
				els.outerDataContainer.setWidth(wNew + 'px');
				this.showImage();
			}).createDelegate(this).defer((this.resizeDuration * 1000) + timeout);
		},
		showImage : function() {
			els.loading.hide();
			els.image.fadeIn({
				duration : this.resizeDuration,
				scope : this,
				callback : function() {
					this.updateDetails();
				}
			});
			this.preloadImages();
		},
		updateDetails : function() {
			els.details.setWidth((els.data.getWidth(true) - els.navClose.getWidth() - 10) + 'px');
			els.caption.update(images[activeImage][1]);
			els.caption.show();
			if (images.length > 1) {
				els.imageNumber.update(this.labelImage + ' ' + (activeImage + 1) + ' ' + this.labelOf + '  ' + images.length);
				els.imageNumber.show();
			}
			els.dataContainer.syncFx().slideIn('t', {
				duration : this.resizeDuration / 2
			}).fadeIn({
				duration : this.resizeDuration / 2,
				scope : this,
				callback : function() {
					var viewSize = this.getViewSize();
					els.overlay.setHeight(viewSize[1] + 'px');
					this.updateNav();
				}
			});
		},
		updateNav : function() {
			this.enableKeyNav();
			els.hoverNav.show();
			if (activeImage > 0) els.navPrev.show();
			if (activeImage < (images.length - 1)) els.navNext.show();
		},
		enableKeyNav : function() {
			Ext.fly(document).on('keydown', this.keyNavAction, this);
		},
		disableKeyNav : function() {
			Ext.fly(document).un('keydown', this.keyNavAction, this);
		},
		keyNavAction : function(ev) {
			var keyCode = ev.getKey();
			if (keyCode == 88 || keyCode == 67 || keyCode == 27) {
				this.close();
			} else if (keyCode == 80 || keyCode == 37) {
				if (activeImage != 0) {
					this.setImage(activeImage - 1);
				}
			} else if (keyCode == 78 || keyCode == 39) {
				if (activeImage != (images.length - 1)) {
					this.setImage(activeImage + 1);
				}
			}
		},
		preloadImages : function() {
			var next, prev;
			if (images.length > activeImage + 1) {
				next = new Image();
				next.src = images[activeImage + 1][0];
			}
			if (activeImage > 0) {
				prev = new Image();
				prev.src = images[activeImage - 1][0];
			}
		},
		close : function() {
			this.disableKeyNav();
			els.lightbox.hide();
			els.overlay.fadeOut({
				duration : this.overlayDuration,
				callback : function() {
					Ext.select('object').setStyle('visibility', 'visible');
					Ext.select('embed').setStyle('visibility', 'visible');
				}
			});
			this.fireEvent('close', activeImage);
		},
		getViewSize : function() {
			return [
				Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)
			];
		}
	};
})();
runOnLoad(function() {
	Ext.ux.Lightbox.init.call(Ext.ux.Lightbox);
});