jQuery.fn.Overlay = function(overlayContent, options) {
	options = jQuery.extend({
		fixedSize: true,
		onClose: null,
		clickToClose: false
	}, options || {});

	return this.each(function() {
		this.overlay = new jQuery.Overlay(this, overlayContent, options);
		var el = this;
		jQuery('#' + this.overlay.overlayId).add('#' + this.overlay.contentId).click(function() { jQuery(el).OverlayDestroy() });
	});
};

jQuery.fn.OverlayDestroy = function() {
	return this.each(function() {
		if(this.overlay.options.clickToClose) {
			jQuery('#' + this.overlay.overlayId).add('#' + this.overlay.contentId).unbind('click', function() { jQuery(el).OverlayDestroy() });
		}
		this.overlay.close();
		this.overlay = null;
		return this;
	});
};

jQuery.Overlay = function(wrapElement, overlayContent, options) {
	var id = jQuery.overlayUtility.getUniqueId();
	this.id = id;
	this.options = options;

	this.overlayId = 'overlay_' + id;
	this.contentId = 'overlay_content_' + id;
	this.containerId = 'overlay_container_' + id;

	this.buildDefaultHtml(wrapElement, overlayContent);
	this.size(wrapElement);

	// Attempt to have the overlay match the wrapped element's position.
	jQuery('#' + this.containerId).css({
		float: jQuery(wrapElement).css('float'),
		margin: '0 auto'
	});

	this.oldZ = jQuery(wrapElement).css('z-index');
	jQuery(wrapElement).css('z-index', 98);
	
	this.fadeIn();
};

jQuery.Overlay.prototype.buildDefaultHtml = function(wrapElement, overlayContent) {
	jQuery(wrapElement).wrap('<div id="'+this.containerId+'"></div>');
	jQuery(wrapElement).before('<div id="'+this.overlayId+'"></div><div id="'+this.contentId+'"></div>');

	// Insert the content and measure it. Note, floating the content causes the element to shrink to
	// fit its contents - allows an accurate automatic measurement of the content.
	jQuery('#' + this.contentId).css({float: 'left'}).append(overlayContent);
	this.contentSz = jQuery.iUtil.getSize(document.getElementById(this.contentId));

	jQuery('#' + this.containerId).css('position', 'relative');
	jQuery('#' + this.overlayId).css({
		position: 'absolute',
		left: 0,
		top: 0,
		height: '100%',
		width: '100%',
		backgroundColor: 'black',
		opacity: 0,
		zIndex: 99
	});
	jQuery('#' + this.contentId).css({
		position: 'absolute',
		top: '50%',
		left: '50%',
		margin: '-' + (this.contentSz.hb / 2) + 'px 0 0 -' + (this.contentSz.wb / 2) + 'px',
		float: 'none',	// Remove the float set when inserting the content.
		zIndex: 100
	});
};

jQuery.Overlay.prototype.size = function(wrapElement) {
	if(this.options.fixedSize) {
		// Measure the size of the element being overlayed.
		this.size = jQuery.iUtil.getSize(wrapElement);

		jQuery('#' + this.overlayId).add('#' + this.containerId).css({
			width: this.size.wb,
			height: this.size.hb
		});
	} else {
		// Seperate code path for handling dynamic sized overlays in IE6 (it can't cope with the
		// standards based solution).
		if(jQuery.browser.msie && jQuery.overlayUtility.getIEVersion(navigator.userAgent) <= 6) {
			document.getElementById(this.containerId).style.setExpression('height', "jQuery.overlayUtility.ieFixHeights(" + this.id + ")");
		}
	}
};

jQuery.Overlay.prototype.fadeIn = function() {
	jQuery('#' + this.overlayId).fadeTo(300, 0.6);
};

jQuery.Overlay.prototype.close = function() {
	var overlay = this;

	jQuery('#' + overlay.contentId).remove();
	jQuery('#' + this.overlayId).unbind('click').fadeTo(300, 0, function() {
		jQuery('#' + overlay.overlayId).remove();

		// Unwrap the overlayed element and remove the container.
		if(overlay.oldZ) {
			jQuery('#' + overlay.containerId).children().css('z-index', overlay.oldZ).remove().insertBefore('#' + overlay.containerId).end().remove();
		} else {
			jQuery('#' + overlay.containerId).children().remove().insertBefore('#' + overlay.containerId).end().remove();
		}

		if(overlay.options.onClose != null) {
			overlay.options.onClose();
		}
	});
};

jQuery.overlayUtility = {
	nextUniqueId : 0,

	getUniqueId : function() {
		var i = jQuery.overlayUtility.nextUniqueId;
		jQuery.overlayUtility.nextUniqueId++;
		return i;
	},

	getIEVersion	: function(ua) {
		return ua.match(/MSIE (\d+(?:\.\d+)+(?:b\d*)?)/)[1];
	},

	ieFixHeights : function(id) {
		// This is called when evaluating the height of the overlay container in IE6 - but actually
		// we're going to use it to size the overlay and overlay content.

		// Measure the current size of the overlayed content.
		var sz = jQuery.iUtil.getSizeLite(document.getElementById('overlay_container_' + id));

		var lastSize = { wb: -1, hb: -1 };

		if(jQuery.overlayUtility.ieOverlaySizes[id] != null) {
			lastSize = jQuery.overlayUtility.ieOverlaySizes[id];
		}

		if(lastSize.wb != sz.wb || lastSize.hb != sz.hb) {
			// Find the overlay and content.
			jQuery('#overlay_' + id).css('height', sz.hb + 'px');
			jQuery('#overlay_content_' + id).css({
				height: sz.hb + 'px',
				left: sz.wb / 2,
				top: sz.hb / 2
			});

			jQuery.overlayUtility.ieOverlaySizes[id] = sz;
		}

		return 'auto'
	},

	ieOverlaySizes : {}
};
