/*
	Copyright (c) 2007-2008 JB Interactive Pty. Ltd.
	All Rights Reserved
	http://www.jbinteractive.com.au/
*/

(function ($) {

// Protected Overlay variables.
var instances = [],

	margin = 18,
	
	overlay = $('<div id="overlay" />')
		.css({
			display: 'none',
			position: 'fixed',
			top: 0,
			left: 0,
			width: '100%',
			height: '100%',
			zIndex: 10
		}),
	
	backdrop = $('<div id="overlay_backdrop" />')
		.appendTo(overlay)
		.css({
			position: 'fixed',
			top: 0,
			left: 0,
			width: '100%',
			height: '100%',
			zIndex: 11
		}),
	
	container = $('<div id="dialog_container" />')
		.appendTo(overlay)
		.css({
			position: 'fixed',
			left: '50%',
			top: '50%',
			zIndex: 12
		})
		.extend(function () {
			var css = function (width, height) {
				return {
					width: width,
					height: height,
					marginLeft: Math.ceil(width / -2),
					marginTop: Math.ceil(height / -2)
				};
			};
			
			return {
				resize: function (width, height) {
					return this.css(css(width, height));
				},
				grink: function (width, height, callback) {
					if (typeof width === 'object') {
						height = width.height;
						width  = width.width;
					}
					return this.animate(css(width, height), callback)
						// Set overflow to visible to undo jQuery's smartness.
						.css('overflow', 'visible');
				}
			};
			
		}()),
	
	active = function () {
		
		var self = null;
		
		return {
			
			get: function () {
				return self;
			},
			
			is: function (dialog) {
				if (dialog) {
					return dialog == self;
				}
				return Boolean(self !== null);
			},
			
			set: function (dialog) {
				if (this.is()) {
					this.unset();
				}
				dialog.element()
					.appendTo(container)
					.trigger('dialogshow');
				self = dialog;
			},
			
			unset: function (dialog) {
				self.element()
					.trigger('dialoghide')
					.store();
				self = null;
			}
			
		};
	}();

JbCms.Dialog = function (content, dimensions, id) {
	
	if (typeof content == 'string') {
		content = $(content);
	}
	
	if (content.hasClass('hidden')) {
		content.css({
			display: 'block',
			visibility: 'visible'
		});
		
	}
	
	var width, height,
		
		element = $('<div class="dialog" />')
			.append(content)
			.store(),
		
		dialog = {
			
			show: function (trans) {
				JbCms.Dialog.show(this, trans);
			},
			
			hide: function () {
				if (!this.visible()) {
					return;
				}
				JbCms.Dialog.hide();
			},
			
			visible: function () {
				return active.is(this);
			},
		
			element: function () {
				return element;
			},
			
			dimensions: function (new_width, new_height) {
				
				// If a single dialog object is passed in, this becomes a 
				// comparison function.
				if (typeof new_width == 'object' && $.isFunction(new_width.dimensions)) {
					var other = new_width.dimensions();
					return (width == other[0]) && (height == other[1]);
				}
				
				// If no argument are passed, then it acts as an accessor.
				if (!arguments.length) {
					return [width, height];
				}
				
				// If only 1 argument is passed it then the value is used for
				// both width and height.
				if (!new_height) {
					new_height = new_width;
				}
				
				width  = window.parseInt(new_width);
				height = new_height == 'auto' ? 'auto' : window.parseInt(new_height);
				
				if (active.is(this)) {
					container.grink(width, height);
				}
				
				return this;
			},
			
			width: function (new_width) {
				if (!new_width) {
					return width;
				}
				
				width = window.parseInt(new_width);
				
				if (active.is(this)) {
					container.grink(width, height);
				}
				
				return this;
			},
			
			height: function (new_height) {
				if (!new_height) {
					if (height == 'auto') {
						content.store().width(this.width() - (margin*2));
						var calculated_height = content.height();
						content.appendTo(element);
						return calculated_height + (margin*2);
					}
					
					return height;
				}
			
				height = new_height == 'auto' ? 'auto' : window.parseInt(new_height);
				
				if (active.is(this)) {
					container.grink(width, height);
				}
				
				return this;
			}
		};
	
	if (dimensions) {
		if (!(dimensions instanceof Array)) {
			dimensions = [dimensions];
		}
		dialog.dimensions.apply(dialog, dimensions);
	}
	
	if (typeof id == 'string' && id.length) {
		element.attr('id', id);
	}
	
	instances.push(dialog);
	
	return dialog;
};

// This is also defined as a jQuery plugin.
$.fn.dialog = function (dimensions, id) {
	return JbCms.Dialog($(this), dimensions, id);
};

$.extend(JbCms.Dialog, {
	
	init: function () {
		overlay.prependTo('body');
	},
		
	overlay: function () {
		return overlay;
	},
	
	container: function () {
		return container;
	},
	
	show: function (dialog, transition, event) {
		
		if (dialog && active.is(dialog)) {
			return;
		}
		
		var after = function () {
			if (dialog) {
				dialog.element().trigger(event || 'dialogshow');
			}
		};
		
		if (!transition || !this.transitions[transition]) {
			transition = this.transitions[this.default_transition];
		} else {
			transition = this.transitions[transition];
		}
		
		return transition(dialog, after, overlay, container, active);
	},
	
	hide: function (transition) {
		return this.show(null, transition, 'dialoghide');
	},
	
	active: function () {
		return active.get();
	},
	
	default_transition: 'instant',
	
	transitions: {
		
		instant: function (dialog, after) {
			if (!dialog) {
				overlay.hide();
				// Make sure overlay is hidden first.
				setTimeout(function () {
					active.unset();
				}, 5);
			} else {
				var isActive = active.is();
				
				container.resize(dialog.width(), dialog.height());
				active.set(dialog);
				
				dialog.element().show();
				
				if (!isActive) {
					overlay.show();
				}
			}
			
			after();
		},
		
		fade: function (dialog, after) {
			if (!dialog) {
				overlay.fadeOut(function () {
					active.unset();
				});
				return;
			}
			
			var isActive = active.is(),
				element  = dialog.element(),
				showNew  = function () {
					active.set(dialog);
					element.hide().fadeIn(after);
				};
			
			if (!isActive) {
				container.resize(dialog.width(), dialog.height());
				overlay.fadeIn();
				return showNew();
			}
			
			active.get().element().fadeOut(function () {
				if (!active.get().dimensions(dialog)) {
					container.grink(dialog.width(), dialog.height(), showNew);
				} else {
					showNew();
				}
			});
		}
		
	}
});

$(JbCms.Dialog.init);

})(jQuery);

