/*
# $Id$
#
# Requires the "GCms.css" stylesheet to be manually included
# Requires script.aculo.us
*/

/*
# @class GCms.Overlay( string overlayId, [object attr] )
# overlayId	= A unique ID for this overlay
# attr		= Object containing overlay attributes (see below)
#
# Do not use this constructor directly, instead always use the static 'create' method:
#	var myOverlay = GCms.Overlay.create(...)
#
# Creates a new GCms.Overlay object.
# Valid attributes:
#	int width			- Overlay width (pixels)
#	int height			- Overlay height (pixels)
#	int top				- Top position (pixels)
#	int left			- Left position (pixels)
#	string src			- Main body source (url)
#	string body			- Main body text (HTML). This is only used if "src" is not specified
#	Function ondestroy	- A function that will be executed just before the overlay is destroyed (passed the GCms.Overlay instance as the only parameter)
#	string title		- Title that will be displayed in the overlay's header bar
#	Object callbacks	- Object containing all custom callback functions, indexed by their function name
#
# NOTE: If a window/iframe is already open with the same source as "attr.src", then it won't load at all, so use different URLS.
*/
GCms.Overlay = function(overlayId, attr) {
	
	// Class properties
	this.id = overlayId;		// Unique ID
	this.overlay = null;		// Reference to the Overlay DIV
	this.window = null;			// Reference to the main IFRAME's window object
	this.attributes = {};		// Overlay attributes
	this.childOverlays = [];	// Stores Overlays IDs that were spawned from within this Overlay itself

	// Default attributes
	var attrDefaults = {
		width: 900,
		height: 600,
		title: '[Untitled]',
		src: '',
		noHeader: false,
		noFooter: false,
		contrast: true,
		body: 'no source defined!',
		ondestroy: null,
		callbacks: {}
	};
	if(attr==null) {
		attr = {};
	}
	for(var i in attrDefaults) {
		if(attr[i]==null) {
			attr[i] = attrDefaults[i];
		}
	}
	/*
	if(attr.top==null) {
		var scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop;
		var offsetHeight = top.innerHeight ? top.innerHeight : document.documentElement.offsetHeight;
		attr.top = offsetHeight>attr.height ? Math.round((offsetHeight-attr.height)/2)+scrollTop : 0;
	}
	if(attr.left==null) attr.left = document.documentElement.offsetWidth>attr.width ? Math.round((document.documentElement.offsetWidth-attr.width)/2) : 0;
	*/
	
	var de = document.documentElement;
	var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
	
	//alert(window.offsetHeight+' - '+self.offsetHeight+' - '+(de&&de.scrollHeight)+' - '+document.body.offsetHeight)
	
	var h = 0
	if(window.offsetHeight && window.offsetHeight > h) h = window.offsetHeight
	if(self.offsetHeight && self.offsetHeight > h) h = self.offsetHeight
	if((de&&de.offsetHeight) && (de&&de.offsetHeight) > h) h = (de&&de.offsetHeight)
	if(document.body.offsetHeight && document.body.offsetHeight > h) h = document.body.offsetHeight
	if((de&&de.scrollHeight) && (de&&de.scrollHeight) > h) h = (de&&de.scrollHeight)
	if(document.body.scrollHeight && document.body.scrollHeight > h) h = document.body.scrollHeight
	
	var scrollTop = de.scrollTop>0?de.scrollTop:document.body.scrollTop
	
	if(attr.top==null)attr.top = scrollTop+20;
	if(attr.left==null)attr.left = (w/2)-(attr.width/2);
	
	this.attributes = attr;

	var DOC = top.document;
	
	// Create background container if required
	if(attr.contrast == true){
		this.bgOverlay = DOC.createElement('div');
		this.bgOverlay.id = 'bg-'+overlayId;
		this.bgOverlay.className = 'GCmsOverlay-pre';
		this.bgOverlay.style.zIndex = top.GCms.Overlay.stackIndex+100;
		this.bgOverlay.style.top = '0px';
		this.bgOverlay.style.left = '0px';
		this.bgOverlay.style.width = w+'px';
		this.bgOverlay.style.height = h+'px';
	}
	
	// Create main container
	this.overlay = DOC.createElement('div');
	this.overlay.id = overlayId;
	this.overlay.className = 'GCmsOverlay';
	this.overlay.style.zIndex = ++top.GCms.Overlay.stackIndex+100;
	this.overlay.style.top = attr.top+'px';
	this.overlay.style.left = attr.left+'px';

	// Create lower iframe (to prevent underlying form elements being visible through the overlay)
	var lowerIframe = DOC.createElement('iframe');
	lowerIframe.frameBorder = '0';
	lowerIframe.style.width = attr.width+'px';
	lowerIframe.style.height = attr.height+'px';
	this.overlay.appendChild(lowerIframe);

	// Create overlay window and header/footer elements
	var win = DOC.createElement('div');
	win.id = overlayId+'-window';
	win.className = 'GCmsOverlay-window';
	if(attr.noHeader==false)
	win.innerHTML = '<div class="GCmsOverlay-header" id="'+overlayId+'-header"><div class="GCmsOverlay-control-buttons"><a href="/" onclick="top.GCms.Overlay.overlays[\''+overlayId+'\'].destroy();return false;">Close</a></div><h1>'+attr.title+'</h1></div>';
	if(attr.noFooter==false)
	win.innerHTML += '<div class="GCmsOverlay-footer">&nbsp;</div>';
	win.style.width = attr.width+'px';
	win.style.height = attr.height+'px';
	this.overlay.appendChild(win);

	// Create window body (main IFRAME)
	var bodyContainer = DOC.createElement('div');
	bodyContainer.className = 'GCmsOverlay-body';
	if(attr.noHeader==false || attr.noFooter==false){
		bodyContainer.style.height = (attr.height-68)+'px';
	}else{
		bodyContainer.style.height = attr.height+'px';	
	}
	
	var body = DOC.createElement('iframe');
	//body.src = attr.src;
	body.name = "nm"+(Math.random()*1000);
	body.frameBorder = '0';
	body.style.width = '100%';
	body.style.height = '100%';
	bodyContainer.appendChild(body);
	win.insertBefore(bodyContainer, win.lastChild);

	// Attach bgOverlay to the current document
	if(attr.contrast!=false)DOC.body.insertBefore(this.bgOverlay, DOC.body.firstChild);
	// Attach overlay to the current document
	DOC.body.insertBefore(this.overlay, DOC.body.firstChild);
	
	// Find a reference to the IFRAME window object
	this.window = body.contentWindow;

	// Write HTML body content if no source is specified
	if(attr.src=='') {
		
		//this.window.onload = function() {
			body.contentWindow.document.write('<html><head><title>[GCms.Overlay Message]</title>'+
			'<style type="text/css">body { font-size: 1em; font-family: Arial; } DIV#preloaderContentBlock {text-align:center;padding-top:15px;padding-left:10px;} DIV#preloaderContentBlock, [DUMMY] {padding-left:0px;} </style></head><body>'+
			attr.body+
			'</body></html>'
			);
		//}
	}

	// Set window location
	else {
		this.window.location = attr.src;
	}

	// Make the overlay draggable
	/*
	var D = new Draggable(overlayId, {handle:overlayId+'-header', starteffect:null, endeffect:null});
	if(Draggables.observers.length==0) {
		Draggables.addObserver({
			onEnd: function(eventName, draggable, event) {

				// Send to top of stack
				draggable.element.style.zIndex = top.GCms.Overlay.stackIndex+1;
				top.GCms.Overlay.stackIndex += 2;

				// Inflict boundaries
				if(parseInt(draggable.element.style.top)<0) {
					draggable.element.style.top = "0px";
				}
					
				// Reset drag state
				var win = draggable.element.getElementsByTagName('div')[0];
				win.className = win.className.toString().replace(/\sGCmsOverlay\-dragging/i, '');
			}
		});
		Draggables.addObserver({
			onStart: function(eventName, draggable, event) {

				// Set drag state
				var win = draggable.element.getElementsByTagName('div')[0];
				win.className += ' GCmsOverlay-dragging';
			}
		});
	}
	*/

	// Increment the stackIndex
	top.GCms.Overlay.stackIndex ++;

	// This little hack is a workaround for the 'forever-loading' bug in IE (the loading bar of the parent frame never stops)
	setTimeout("top.frames[0].location = 'about:blank';top.frames[1].focus();", 1)
	
}

/*
# @property object overlays
# Static property holding references to all GCms.Overlay instances.
# NOTE: Only one instance of this variable must exist, and it must exist in the top-most window of the stack, ir the main browser window.
*/
if(top.GCms.Overlay.overlays==null) {
	top.GCms.Overlay.overlays = {};
}

/*
# @property int stackIndex
# Static property holding the next z-index value that will bring an Overlay to the forefront.
*/
if(top.GCms.Overlay.stackIndex==null) {
	top.GCms.Overlay.stackIndex = 100;
}

/*
# @method GCms.Overlay create( string overlayId, object attr)
# overlayId	= A unique string identifier to assign to this new Overlay
# attr		= A list of attributes that will be applied to the Overlay
#
# Creates a new Overlay and adds it to the list stored in the static "overlays" property.
*/
GCms.Overlay.create = function(overlayId, attr) {

	// Determine if this window is in an Overlay
	var parent = GCms.Overlay.getOverlayByWindow(self);

	// Create the overlay
	if(top.GCms.Overlay.overlays[overlayId]==null) {
		top.GCms.Overlay.overlays[overlayId] = new top.GCms.Overlay(overlayId, attr);
	}
	else {
		// TODO: destroy the existing one before creating the new one?
	}

	// If this new overlay is being opened from within another overlay, add to the parent's child list
	if(parent!=null) {
		if(parent.id==overlayId) {
			alert("FATAL ERROR: Attempting to open '"+overlayId+"' overlay form within the '"+parent.id+"' overlay!\nChild-association not created.");
		}
		else {
			parent.addChild(overlayId);
		}
	}

	// Result
	return top.GCms.Overlay.overlays[overlayId];
}

/*
# @method bool isOverlay( Window win )
# win	= HTML window
#
# Determines if the specified window is being rendered in an overlay IFRAME.
*/
GCms.Overlay.isOverlay = function(win) {

	// Get the overlay
	var overlay = GCms.Overlay.getOverlayByWindow(win);

	// Result
	return overlay==null ? false : true;
}

/*
# @method GCms.Overlay getOverlayByWindow( Window win )
# win	= HTML Window object
#
# Returns the GCms.Overlay object that contains the specified Window.
*/
GCms.Overlay.getOverlayByWindow = function(win) {

	// First, check if win refers to the top window
	if(win.GCms.Overlay.overlays!=null) {
		return null;
	}

	// Find which of the frames matches win
	var overlayId = null;
	/*for(var i=0; i<top.frames.length; i++) {
		if(top.frames[i].id==win.id) {
			overlayId = top.frames[i].id.toString().replace(/IFRAME-(.*)/, '$1');
		}
	}*/
	for(var id in top.GCms.Overlay.overlays) {
		if(top.GCms.Overlay.overlays[id].window==win) {
			overlayId = id;
		}
	}

	// Result
	return overlayId==null ? null : top.GCms.Overlay.overlays[overlayId];
}

/*
# @method Function getCallback( string name )
# name	= Name of the callback function
#
# Returns the callback function identified by "name".
*/
GCms.Overlay.prototype.getCallback = function(name) {

	// Result
	return this.attributes.callbacks[name];
}

/*
# @method void show()
#
# Display/unhide the Overlay.
*/
GCms.Overlay.prototype.show = function() {

	// Hide all SWF objects in the top window
	var embeds = top.document.getElementsByTagName('embed');
	for(var i=0; i<embeds.length; i++) {
		embeds[i].style.visibility = 'hidden';
	}
	
	// Show this overlay
	this.overlay.style.visibility = 'visible';
	if(this.bgOverlay!=null)this.bgOverlay.style.visibility = 'visible';

	// Show all children
	for(var i=0; i<this.childOverlays.length; i++) {
		if(top.GCms.Overlay.overlays[this.childOverlays[i]]) {
			top.GCms.Overlay.overlays[this.childOverlays[i]].show();
		}
	}
}

/*
# @method void hide()
#
# Hide the overlay, but do not completely destroy it.
*/
GCms.Overlay.prototype.hide = function() {

	// Hide all SWF objects in the top window
	var embeds = top.document.getElementsByTagName('embed');
	for(var i=0; i<embeds.length; i++) {
		embeds[i].style.visibility = 'visible';
	}

	// Hide this overlay
	this.overlay.style.visibility = 'hidden';
	if(this.bgOverlay!=null)this.bgOverlay.style.visibility = 'hidden';
	// Hide all children
	for(var i=0; i<this.childOverlays.length; i++) {
		if(top.GCms.Overlay.overlays[this.childOverlays[i]]) {
			top.GCms.Overlay.overlays[this.childOverlays[i]].hide();
		}
	}

	

	// Give focus back to the parent window
	// TODO
}

/*
# @method void destroy()
#
# Destroy the Overlay, removing it completely from the DOM.
*/
GCms.Overlay.prototype.destroy = function() {
	
	// Trigger the 'ondestory' event
	if(this.attributes.ondestroy!=null) {
		if(this.attributes.ondestroy(this)==false){
			return false;	
		}
	}
	
	// Destory all child overlays first
	for(var i=0; i<this.childOverlays.length; i++) {
		if(top.GCms.Overlay.overlays[this.childOverlays[i]]) {
			top.GCms.Overlay.overlays[this.childOverlays[i]].destroy();
		}
	}

	// Hide the overlay
	this.hide();

	// Remvoe the overlay from the DOM
	this.overlay.parentNode.removeChild(this.overlay);
	
	// Remvoe the overlays bg overlay from the DOM
	if(this.bgOverlay!=null)this.bgOverlay.parentNode.removeChild(this.bgOverlay);
	
	// Remove the overlay's reference from top.GCms.Overlay.overlays
	delete top.GCms.Overlay.overlays[this.id];
}

/*
# @method void addChild( string overlayId )
# overlayId	= ID of the Overlay
#
# Flags the specified Overlay as being a child of this Overlay.
*/
GCms.Overlay.prototype.addChild = function(overlayId) {

	// Add Overlay to this Overlay's list of children
	/*
	# adjustment to child window position removed
	# top.GCms.Overlay.overlays[overlayId].moveTo(this.attributes.top+50, this.attributes.left+50);
	*/
	this.childOverlays.push(overlayId);
}

/*
# @method void moveTo( int top, int left )
# top	= Top (y) coordinate
# left	= Left (x) coordinate
#
# Moves the Overlay's top-left corner to the specified coordinates.
*/
GCms.Overlay.prototype.moveTo = function(top, left) {

	// Move
	this.setAttribute('top', top);
	this.setAttribute('left', left);
}

/*
# @method void setAttribute( string name, mixed value )
# name	= Attribute name
# value	= Value to set
#
# Sets the specified attribute.
*/
GCms.Overlay.prototype.setAttribute = function(name, value) {

	// Act on the specified attribute
	switch(name) {

		/* body */
		case "body":
			this.window.document.body.innerHTML = value;
			break;

		/* top */
		case "top":
			this.attributes.top = value;
			this.overlay.style.top = value+'px';
			break;

		/* left */
		case "left":
			this.attributes.left = value;
			this.overlay.style.left = value+'px';
			break;

		/* unknown attribute */
		default:
			break;
	}
}