sense.ui.overlay = {};
sense.ui.overlay.Base = Class.create(sense.ui.Base, {

	// Properties
	defaults: { useShim: false, useMask: false, animate: false },

	// Methods
	initialize: function($super, content, options) {
		this.element = new Element('div').setStyle({ position:'absolute' });
		$super(this.element, options, this.defaults);
		
		if (Prototype.Browser.IE6) this.options.useShim = true;

		this.isOverlay = true; // Differentiate this from the Shim & Mask pseudo-overlay types
		this.create(content);
	},

	create: function(content) {
		// Insert the overlay into the document
		$(document.body).insert(this.element);

		// Create the underlying iframe as an IE6 fix
		if (this.options.useShim) {
			this.shim = new sense.ui.overlay.Shim();
		}
		if (this.options.useMask) {
			this.mask = new sense.ui.overlay.Mask();
		}

		// Populate, size & position the overlay
		this.setContent(content);

		if (this.options.positionFunc) {
			this.setPositionHandler = this.setPosition.bind(this);
			Event.observe(window, 'scroll', this.setPositionHandler);
			Event.observe(window, 'resize', this.setPositionHandler);
		}
	},

	destroy: function() {
		this.element.remove();

		if (this.setPositionHandler) {
			Event.stopObserving(window, 'scroll', this.setPositionHandler);
			Event.stopObserving(window, 'resize', this.setPositionHandler);
		}

		if (this.shim) this.shim.destroy();
		if (this.mask) this.mask.destroy();
	},

	refresh: function() {
		// Set the overlay's size & position, based on the last values 
		// provided, the size of its current content, and/or the values 
		// returned by a positioning function passed in as an option.
		this.setDimensions();
		this.setPosition();
	},

	setContent: function(content) {
		this.element.update(content);
		this.refresh();
		this.bringToFront();
	},

	setDimensions: function(w,h) {
		if (typeof w == 'undefined' && typeof this.options.w != 'undefined') w = this.options.w;
		if (typeof h == 'undefined' && typeof this.options.h != 'undefined') h = this.options.h;

		var contentElement = this.getContentElement()
		if (typeof w == 'undefined' && contentElement) {
			var wh = contentElement.getDimensions();
			w = wh.width;
		}

		if (typeof w != 'undefined') this.element.setStyle({ width: this.px(w) });
		if (typeof h != 'undefined') this.element.setStyle({ height:this.px(h) });

		if (this.mask) {

			// Set the mask & shim to fill the viewport so that they don't impact measurements.
			// Measure the scroll dimensions, then set the mask & shim to those dimensions.
			this.mask.setDimensions('100%', '100%');
			if (this.shim) this.shim.setDimensions('100%', '100%');

			var h = Math.max(
				document.body.scrollHeight, $$('html').first().getHeight(),
				document.documentElement.clientHeight || document.body.clientHeight
			);

			this.mask.setDimensions('100%', h);
			if (this.shim) this.shim.setDimensions('100%', h);

		} else {

			// The element might legitimately be set to a width or height of "auto",
			// but the iframe should use its computed dimensions instead, since it 
			// has no content, so "auto" will just set it to a default size.
			if (this.shim) {
				var wh = this.element.getDimensions();
				this.shim.setDimensions(wh.width, wh.height);
			}

		}
	},

	setPosition: function(x,y) {
		if (this.options.positionFunc) {
			var xy = this.options.positionFunc();
			x = xy.x;
			y = xy.y;
		}

		if (typeof x == 'undefined' && typeof this.options.x != 'undefined') x = this.options.x;
		if (typeof y == 'undefined' && typeof this.options.y != 'undefined') y = this.options.y;

		if (typeof x != 'undefined') this.element.setStyle({ left:this.px(x) });
		if (typeof y != 'undefined') this.element.setStyle({ top: this.px(y) });

		if (this.mask) {
			// If we're using a mask, these both want to fill the viewport...
			this.mask.setPosition(0,0);
			if (this.shim) this.shim.setPosition(0,0);
		} else {
			// Otherwise the shim wants to match the position of the overlay.
			if (this.shim) {
				var xy = this.element.cumulativeOffset();
				this.shim.setPosition(xy[0],xy[1]);
			}
		}
	},

	setPositionMethod: function(method) {
		this.element.setStyle({ position:method });
		if (this.shim && !this.mask) {
			this.shim.setPositionMethod(method);
		}
	},

	bringToFront: function() {
		if (this.shim) this.shim.bringToFront();
		if (this.mask) this.mask.bringToFront();

		var oldZ = parseInt(this.element.getStyle('zIndex') || 0, 10);
		var newZ = oldZ;

		// Find all the other positioned layers in the document
		var layers = $$('*').select(function(el){
			var pos = el.getStyle('position');
			return (el != this.element && pos && pos != 'static');
		}.bind(this));

		// For every layer higher than this one, decrement its 
		// z-index, and find the highest z-index used so far.
		layers.each(function(el){
			var z = parseInt(el.getStyle('zIndex') || 0, 10);
			if (z >= oldZ) {
				// if (z > 1) el.setStyle({ 'zIndex': z - 1 });
				newZ = Math.max(newZ, z);
			}
		});

		// newZ = Math.max(newZ, layers.length) + 1;
		newZ += 1;
		this.element.setStyle({ 'zIndex': newZ });
	},

	show: function() {
		this.element.show();

		if (this.isOverlay) {
			this.bringToFront();
			this.refresh();

			if (this.options.animate) {
				this.animatedShow();
			}

			if (this.shim) this.shim.show();
			if (this.mask) this.mask.show();
		}
	},

	hide: function() {
		var callback = function(){
			this.element.hide();
			if (this.isOverlay) {
				if (this.shim) this.shim.hide();
				if (this.mask) this.mask.hide();
			}
		}.bind(this);

		if (this.options.animate) {
			this.animatedHide(callback);
		} else {
			callback();
		}
	},

	animatedShow: function() {
		this.element.tween().fadeIn({ seconds:0.3 });
		if (this.mask) this.mask.element.tween().fadeIn({ seconds:0.3 });
	},
	
	animatedHide: function(callback) {
		this.element.tween().fadeOut({ seconds:0.3, onEnd:callback });
		if (this.mask) this.mask.element.tween().fadeOut({ seconds:0.3 });
	},

	getElement: function() {
		return this.element;
	},

	getContentElement: function() {
		if (this.element.childElements().length == 1) {
			return this.element.down();
		}
	}

});

// Don't call $super for either of these because we don't want to do the full 
// overlay init, otherwise we'll start an infinite chain of shims & masks.

sense.ui.overlay.Shim = Class.create(sense.ui.overlay.Base, {

	// Methods
	initialize: function($super) {
		this.options = {};
		this.element = new Element('iframe', { 'src':"javascript:'<html></html>';", 'scroll':'no', 'frameborder':'no' });
		this.element.setStyle({ position:'absolute', top:0, left:0, border:'none', opacity:0 });
		$(document.body).insert(this.element);
	}

});

sense.ui.overlay.Mask = Class.create(sense.ui.overlay.Base, {

	// Methods
	initialize: function($super) {
		this.options = {};
		this.element = new Element('div').addClassName('uiOverlayBackground');
		this.element.setStyle({ position:'absolute', top:0, left:0, backgroundColor:'#565656', opacity:0.8 });
		$(document.body).insert(this.element);
	}
	
});
