dojo.provide("UI.Dialog.Generic");
dojo.require("UI.Dialog.Modal");
dojo.require("dojo.window");


(function() {
	var handles        = [],
		id             = 0,
		topZIndex      = 1,
		openModalCount = 0;
	
	var EVT_BEFORE_OPEN  = 'beforeopen',
		EVT_OPEN         = 'open',
		EVT_BEFORE_CLOSE = 'beforeclose',
		EVT_CLOSE        = 'close',
		
		ANIMATION_DURATION_IN  = 150,
		ANIMATION_DURATION_OUT = 150;
	
	dojo.declare("UI.Dialog.Generic", UI.Base, {
		constructor: function(container) {
			if ( !container ) {
				throw "Dialog container does not exist";
			}
			
			this.container          = container;
			this.id                 = id++;
			this.modal              = null;
			this.baseZIndex         = this.getStyle(container, "z-index") || 10;
			this.autoCentering      = true;
			this.autoCenteringFixed = true;

			this.aniShow = dojo.fadeIn({node: this.container, duration: ANIMATION_DURATION_IN});
			this.aniHide = dojo.fadeOut({node: this.container, duration: ANIMATION_DURATION_OUT});
			
			dojo.connect(this.aniShow, "onBegin", this, function() {
				this.container.style.display = "block";
				this.isShown = true;
			});
			dojo.connect(this.aniHide, "onBegin", this, function() { this.isShown = false; });
			dojo.connect(this.aniHide, "onEnd", this, function() {
				this.container.style.display = "none";
			});
			
			// Initialize to hidden
			dojo.fadeOut({node: this.container, duration: 1}).play();
			
			this._init();
			
			handles[this.id] = this;
			return this;
		},
	
		open: function(event) {
			try { dojo.stopEvent(event); } catch(e) {}
			
			if ( this.triggerEvent(EVT_BEFORE_OPEN) === false ) {
				return this;
			}
			
			if ( this.isClosed() ) {
				this.bringToFront();
				
				if ( this.isModal() ) {
					++openModalCount;
					this.modal.open();
				}
				
				if ( !this.isShown ) {
					this.aniHide.stop();
					this.aniShow.play();
				}
				
				if ( this.autoCentering ) {
					this.center(this.autoCenteringFixed);
				}
			}
			
			this.triggerEvent(EVT_OPEN);
			
			return this;
		},
		
		close: function() {
			try { dojo.stopEvent(event); } catch(e) {}
			
			if ( this.triggerEvent(EVT_BEFORE_CLOSE) === false ) {
				return this;
			}
			
			if ( this.isOpen() ) {
				this.sendBack();
				this.aniShow.stop();
				
				if ( this.isModal() && !--openModalCount ) {
					this.modal.close();
				}
				
				this.aniHide.play();
			}
			
			this.triggerEvent(EVT_CLOSE);
			
			return this;
		},
		
		isOpen: function() {
			return this.isShown;
		},
		
		isClosed: function() {
			return !this.isOpen();
		},
		
		bringToFront: function() {
			topZIndex = Math.max(parseInt(this.baseZIndex, 10) || 0, topZIndex) + 2;
			
			this.container.style.zIndex = topZIndex;
			
			if ( this.isModal() ) {
				this.modal.setZIndex(topZIndex - 1); 
			}
		},
		
		sendBack: function() {
			topZIndex -= 2;
			
			if ( this.isModal() ) {
				this.modal.setZIndex(topZIndex - 3); 
			}
		},
		
		addOpenTriggers: function(triggers, stopEvent) {
			if ( !dojo.isArray(triggers) && !triggers.length ) {
				triggers = [triggers];
			}
			
			// If stop event is not specified, default to true; otherwise, it should be a boolean value
			stopEvent = typeof stopEvent == "undefined" || !!stopEvent;
			
			for ( var i=0, l=triggers.length; i<l; ++i ) {
				this.setNodeAttribute(
					triggers[i], "openTrigger",
					dojo.connect(triggers[i], "click", this, function(event) {
						if ( stopEvent ) {
							dojo.stopEvent(event);
						}
						
						event.target.blur();
						this.open();
					})
				);
			}
			
			return this;
		},
		
		removeOpenTriggers: function(triggers) {
			if ( !dojo.isArray(triggers) && !triggers.length ) {
				triggers = [triggers];
			}
			
			for ( var i=0, l=triggers.length; i<l; ++i ) {
				dojo.disconnect( this.getNodeAttribute(triggers[i], "openTrigger") );
			}
			
			return true;
		},
		
		useModal: function() {
			this.modal = UI.Dialog.Modal;
			
			// This is for IE7.  The `position:relative` on parent nodes is preventing modal 
			// dialogs from being displayed about the modal background making it unclickable.
			// The easy fix is to move it from its current location, to the bottom of the page
			// to put it at the same level in the DOM tree and take it out of the other
			// `position:relative` nodes that don't have a z-index set higher than the modal
			// background.
			if ( dojo.isIE < 8 && !this._reorganizedInDom ) {
				this._reorganizedInDom = true;
				document.body.appendChild(this.container);
				this.useAutoCenter(true);
			}
			
			return this;
		},
		
		useAutoCenter: function(fixed) {
			this.autoCentering      = true;
			this.autoCenteringFixed = !!fixed;
			return this;
		},
		
		removeModal: function() {
			this.modal = null;
			return this;
		},
		
		removeAutoCenter: function() {
			this.autoCentering = true;
			return this;
		},
		
		isModal: function() {
			return this.modal !== null;
		},
		
		getContainer: function() {
			return this.container;
		},
		
		center: function(fixed) {
			var pos = dojo.position(this.container),
				box = dojo.window.getBox();
			
			var dlgHeight    = Math.ceil(pos.h),
				dlgWidth     = Math.ceil(pos.w),
				wndHeight    = box.h,
				wndWidth     = box.w,
				scrollOffset = box.t,
				top          = Math.max(50, (wndHeight - dlgHeight) / 4);
			
			if ( typeof fixed == "undefined" ) {
				fixed = this.autoCenteringFixed;
			}
			
			if ( fixed ) {
				this.container.style.position = "fixed";
				this.container.style.left     = ((wndWidth - dlgWidth) / 2) + "px";
			} else {
				top += scrollOffset;
			}
			
			this.container.style.top = top + "px";
			
			return this;
		},
		
		getContent: function() {
			return dojo.query(".container .content", this.container)[0];
		},
		
		_init: function() {
			dojo.connect(dojo.query(".controls .close", this.container)[0], "click", this, function(event) {
				event.target.blur();
				this.close();
			});
		}
	});
	
	UI.Dialog.Generic.loadTemplate = (function() {
		var cachedTemplates = {};
		
		return function(templateParams, container, callback) {
			var key = dojo.toJson(templateParams);
			
			var onComplete = function(template) {
				var node       = document.createElement("div");
				node.innerHTML = template;
				template       = node.children[0];
				
				if ( container ) {
					container.innerHTML = template.innerHTML;
					container.id        = template.id;
					container.className = template.className;
				}
				
				if ( callback ) {
					callback(template);
				}
			};
			
			if ( cachedTemplates[key] ) {
				setTimeout(function() {
					onComplete(cachedTemplates[key]);
				}, 1);
			} else {
				dojo.xhrGet({
					url:      "/data/template/dialog",
					content:  templateParams,
					handleAs: "text",
					load:     function(template) {
						onComplete(template);
						cachedTemplates[key] = template;
					}
				});
			}
		};
	}());
	
	
	UI.Dialog.Generic.create = (function() {
		var dialogs = {};
		
		var create = function(config, callback) {
			config = dojo.mixin({
				template: {}
			}, config || {});
			
			var container = dojo.create("div");
			var dialog    = new UI.Dialog.Generic(container);
			
			UI.Dialog.Generic.loadTemplate(config.template, container, function() {
				dialog._init();
				dialog.center();
				
				if ( callback ) {
					callback(dialog);
				}
			});
			
			document.body.appendChild(container);
			
			return dialog;
		};
		
		return function(config, createCallback, runtimeCallback) {
			var template = config.template.template;
			
			// Do not cache unique (non-signleton) 
			if ( config.unique ) {
				return create(config, function(dialog) {
					typeof createCallback  == "function" && createCallback(dialog);
					typeof runtimeCallback == "function" && runtimeCallback(dialog);
				});
			}
			
			if ( !dialogs[template] ) {
				dialogs[template] = create(config, function(dialog) {
					typeof createCallback  == "function" && createCallback(dialog);
					typeof runtimeCallback == "function" && runtimeCallback(dialog);
				});
			} else {
				typeof runtimeCallback == "function" && runtimeCallback(dialogs[template]);
			}
			
			return dialogs[template];
		}
	}());
	
	getNoCookieDialog: (function() {
		var dlg = false,
			recheckOnClose = false;
		
		return function(recheck) {
			recheckOnClose = !!recheck;
			
			if ( !dlg ) {
				dlg = UI.Dialog.Generic.create({template:{template: "no-cookies"}}, function(d) {
					dojo.query(".btn-okay", d.getContent()).connect("click", function(event) {
						dojo.stopEvent(event);
						this.blur();
						d.close();
					});
				}).useModal();
				
				dlg.addEventListener("beforeclose", function() {
					return !recheckOnClose || UI.Util.Cookie.test();
				}, true);
			}
			
			return dlg;
		};
	}())
	
	UI.Dialog.Generic.getAll = function() {
		return handles;
	};
})();

