﻿Ext.ns('Ext.ux');

Ext.ux.Lightbox = (function(){
	var els = {},
		images = [],
		urls = [],
		activeImage,
		activeUrl,
		initialized = false,
		selectors = [],
		width = 640,
		height = 410,
		template = new Ext.Template([
			'<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>'
		]).compile();

	return {
		overlayOpacity: 0.65,
		animate: false,
		resizeSpeed: 8,
		borderSize: 10,
		labelImage: "Imagem",
		labelOf: "de",

		init: function(reboot) {
			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;
			}
			else if (reboot) {
				this.initMarkup();
				this.initEvents();
			}
		},

		initMarkup: function() {

			var ids = [
				'outerImageContainer', 'imageContainer', 'image',
				'hoverNav', 'navPrev', 'navNext', 'loading', 'loadingLink',
				'outerDataContainer', 'dataContainer', 'data',
				'details', 'caption', 'imageNumber', 'bottomNav', 'navClose'
			];

			els.overlay = Ext.DomHelper.append(document.body, {
				id: 'ux-lightbox-overlay'
			}, true);

			//var lightboxTpl = template;//new Ext.Template(this.getTemplate());
			els.lightbox = template.append(document.body, {}, true);

			els.shim = Ext.DomHelper.append(Ext.fly('ux-lightbox-imageContainer'), {
				tag: 'iframe',
				id: 'ux-lightbox-shim'
			}, true);

			els.msg = Ext.DomHelper.insertAfter(Ext.fly('ux-lightbox-outerImageContainer'), {
				tag: 'div',
				id: 'ux-lightbox-msg'
			}, true);

			els.msg.setVisibilityMode(Ext.Element.DISPLAY);

			Ext.each(ids, function(id){
				els[id] = Ext.get('ux-lightbox-' + id);
				els[id].setVisibilityMode(Ext.Element.DISPLAY);
			});

			Ext.each([els.overlay, els.lightbox, els.shim], function(el){
				el.setVisibilityMode(Ext.Element.DISPLAY);
				el.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();
			};

			this.on('close',
				function (victim) {
					if ('lightbox' == victim) {
						Ext.get('ux-lightbox').remove();
						Ext.get('ux-lightbox-overlay').remove();

						/* Triste, mas necessário */
						{
							/*
							var date = new Date();
							var curDate = null;
							do {curDate = new Date();} while (curDate-date < 500);
							*/
							initialized = false;
							this.init();
						}
					}
				},
				this
			);


			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){
					var target = ev.getTarget(sel);

					if (target) {
						ev.preventDefault();
						this.open(target, sel, group);
					}
				}, this);
			}
		},

		registerUrl: function(sel, width, height) {
			if(selectors.indexOf(sel) === -1) {
				selectors.push(sel);

				Ext.fly(document).on('click', function(ev){
					var target = ev.getTarget(sel);

					if (target) {
						ev.preventDefault();
						this.openUrl(target, width, height);
					}
				}, this);
			}
		},

		open: function(image, sel, group) {
			group = group || false;
			this.setViewSize();
			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++;
						}
					}

					// calculate top and left offset for the lightbox
					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();

					var fWidth = this.setImage(index);

					this.fireEvent('open', images[index]);

					els.outerImageContainer.show();

					els.outerImageContainer.setStyle({
						backgroundColor: "#eeeeee",
						width: fWidth
					});
					els.outerDataContainer.setStyle({
						backgroundColor: "#eeeeee",
						width: fWidth
					});

				},
				scope: this
			});
		},

		openUrl: function(url, fWidth, fHeight) {
			els.msg.update('');
			els.shim.dom.src = '';
			this.setViewSize();
			els.overlay.fadeIn({
				duration: this.overlayDuration,
				endOpacity: this.overlayOpacity,
				callback: function() {
					urls = [];

					var index = 0;
					urls.push([url.href, url.title]);


					// calculate top and left offset for the lightbox
					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();
					els.shim.setStyle({
						width: fWidth + 'px',
						height: fHeight + 'px',
						alpha:	'(opacity=0)'
					});
					this.setUrl(index, fWidth, fHeight);

					this.fireEvent('open', urls[index]);
				},
				scope: this
			});
		},

		openMessage: function(mText, fWidth, fHeight, url) {
			fWidth = fWidth || width;
			fHeight = fHeight || height;

			this.setViewSize();
			els.overlay.fadeIn({
				duration: this.overlayDuration,
				endOpacity: this.overlayOpacity,
				callback: function() {

				// calculate top and left offset for the lightbox
					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.setMessage(mText, fWidth, fHeight, url);

					this.fireEvent('open', mText);
				},
				scope: this
			});
		},

		openLoader: function(fWidth, fHeight) {
			fWidth = fWidth || width;
			fHeight = fHeight || height;

			this.setViewSize();
			els.overlay.fadeIn({
				duration: this.overlayDuration,
				endOpacity: this.overlayOpacity,
				callback: function() {


					// calculate top and left offset for the lightbox
					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();
					els.msg.setStyle({
						width: fWidth + 'px',
						height: fHeight + 'px'
					});
					this.setLoader(fWidth, fHeight);

					this.fireEvent('open', '#Loader#');
				},
				scope: this
			});
		},

		setViewSize: function(){
			var viewSize = this.getViewSize();
			/*viewSize[0] = Ext.getBody().getWidth();*/
			viewSize[0] = Ext.select('html').item(0).getWidth();

			els.overlay.setStyle({
				width: viewSize[0] + 'px',
				height: viewSize[1] + 'px'
			});
			els.lightbox.setStyle({
				width: viewSize[0] + 'px'
			});
			els.shim.setStyle({
				width: viewSize[0] + 'px',
				height: viewSize[1] + 'px'
			}).show();
		},

		setImage: function(index){
			els.msg.update('');
			activeImage = index;

			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}

			els.msg.hide();
			els.image.hide();
			els.shim.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.outerImageContainer.show();
			els.dataContainer.setOpacity(0.0001);
			els.dataContainer.show();
			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];
			els.navClose.show();

			return preload.width;
		},

		setMessage: function(mText, fWidth, fHeight, a){
			els.msg.update('');
			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}

			els.msg.hide();
			els.navClose.hide();
			els.imageNumber.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.image.hide();
			els.shim.hide();
			els.dataContainer.hide();
			els.outerImageContainer.hide();
			//els.dataContainer.setOpacity(0.0001);

			var fHtml = Ext.get(a).first();
			//			els.msg.update(mText);

			els.msg.setStyle({
				width: '0px',
				height: '0px'
			}).show();

			fHtml.appendTo(els.msg);

			if (typeof(window['Cufon']) != "undefined")
				Cufon.replace('#ux-lightbox .g', '#ux-lightbox .g *');

			els.msg.setVisibilityMode(Ext.Element.VISIBILITY);

			els.msg.hide().show(true).shift(
				{
					width:els.msg.first().getWidth(true)+els.msg.getPadding('lr'),
					height: els.msg.first().getHeight(true)+els.msg.getPadding('tb')
				}
			);

			els.msg.setVisibilityMode(Ext.Element.DISPLAY);

			Ext.get(a).remove();

			els.loading.hide();
		},

		setLoader: function(fWidth, fHeight){
			fWidth = fWidth || width;
			fHeight = fHeight || height;

			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}

			els.image.hide();
			els.shim.hide();
			els.msg.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.dataContainer.setOpacity(0.0001);
			els.imageNumber.hide();
			els.navClose.hide();

			this.resizeBox(fWidth+30, fHeight+5);

		},

		setUrl: function(index, fWidth, fHeight){
			activeUrl = index;

			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}

			els.shim.hide();
			els.msg.hide();
			els.image.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.dataContainer.setOpacity(0.0001);
			els.imageNumber.hide();

			els.shim.dom.src = urls[activeUrl][0];
			els.shim.show();
			els.navClose.show();

			this.resizeBox(fWidth, fHeight);
			els.shim.setStyle({
				alpha:	'(opacity=100)'
			});
			els.loading.hide();
		},

		resizeBox: function(w,h) {
			var wCur = els.outerImageContainer.getWidth();
			var hCur = els.outerImageContainer.getHeight();

			var wNew = w;
			var hNew = h;

			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(els.imageContainer.getWidth() + 'px');

				els.navPrev.setHeight(h + 'px');
				els.navNext.setHeight(h + 'px');

				els.outerDataContainer.setWidth(wNew + 'px');
				els.dataContainer.setOpacity(100);

			}).createDelegate(this).defer((this.resizeDuration*1000) + timeout);
		},

		resizeImage: function(w, h, urlmode){
			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(els.imageContainer.getWidth() + 'px');
				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');
						var width = els.imageContainer.getWidth();
						els.hoverNav.setWidth(width + 'px');
						els.navPrev.setWidth(Math.floor(width*0.49) + 'px');
						els.navNext.setWidth(Math.floor(width*0.49) + 'px');
						this.updateNav();
					}
				})
		},

		updateNav: function(){
			this.enableKeyNav();

			els.hoverNav.show();

			// if not first image in set, display prev image button
			if (activeImage > 0)
				els.navPrev.show();

			// if not last image in set, display next image button
			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 || // x
				keyCode == 70 || // f
				keyCode == 27
			) {
				this.close();
			}
			else if (keyCode == 65 || keyCode == 37){ // display previous image
				if (activeImage != 0){
					this.setImage(activeImage - 1);
				}
			}
			else if (keyCode == 80 || keyCode == 39){ // display next image
				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 (p) {var a = p; return function(){a.fireEvent('close', 'lightbox');}})(this)
			});
			els.shim.hide();

			this.fireEvent('close', activeImage);
		},

		getViewSize: function() {
			return [Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)];
		}
	}
})();

Ext.onReady(Ext.ux.Lightbox.init, Ext.ux.Lightbox);

