/*
Copyright 2006-2007 Wellspring Technologies, LLC
All Rights Reserved
Unauthorized Use Prohibited
*/
//This is an IE fix for recognizing the header/toolbar for drag events
var ddml_INTERNAL_validDrag = true;
function ddmlPopupDragStart(ele, dx, dy) {
	ddml_INTERNAL_validDrag = (xMoz || (ele.className && (ele.className == 'ddmlPopupHeader' || ele.className == 'ddmlPopupTitle')));
}

function ddmlPopupDrag(ele, dx, dy) {
	if (ddml_INTERNAL_validDrag) xMoveTo(ele.parentNode.parentNode, xLeft(ele.parentNode.parentNode) + dx, xTop(ele.parentNode.parentNode) + dy);
}

var ddmlActivePopups = new Array();
var ddml_INTERNAL_activePopupFormRegister = new Array();
function ddmlPopup(sName, sTitle) {
	//User-settable flags
	this.debug = arguments[2] || false;
	this.name = (sName)?sName:'';			//The name of the popup - used for debugging purposes
	this.id = '';							//The DOM id of the popup
	this.title = sTitle;					//A title that will go in the popup header if it's enabled
	this.icon = '';							//If this exists, an icon will be added to the header before any title
                                    		
	this.bShowToolbar = true;				//Enable to show a toolbar - required to drag
	this.bAllowDrag = true;					//Enable to allow dragging - requires bShowToolbar
	this.bAllowMaximize = false;			//Enable to add a maximize button to the header PARTIALLY IMPLEMENTED
	this.bAllowMinimize = false;			//Enable to add a minimize button to the header NOT IMPLEMENTED
	this.bShowClose = true;					//Enable to add a close button to the header
	this.bCloseRightClickMenus = true;		//Enable to close right click menus when the popup appears
	this.bShowMask = true;					//Enable to display a mask behind the popup that makes it modal
	this.bAllowEscape = true;				//Enable to allow the escape button to close the popup
                                    		
	this.contents = '';						//Set this to the HTML contents of the popup
	this.width = null;						//Set this to fix the popup to a particular width
	this.height = null;						//Set this to fix the popup to a particular height
	this.target = null;						//Set this to an array with the position of the popup.  Possible formats:
											//[node, (middle, left, right, #), (center, top, botttom, #)]
											//[(middle, left, right, #), (center, top, botttom, #)]
	this.padding = 30;						//Set to change the space left around the 'maximized' window
	this.bFade = true;						//Disable to make the popup instantaneous
	this.fadeSpeed = 50;					//Sets time it takes to fade the popup in
	this.fadeSize = .1;						//Sets the size of each step in the fade process
	this.bIgnoreWidthBoundaries = false;	//If true, the popup won't reposition itself around objects on the x-axis
	this.bIgnoreHeightBoundaries = false;	//If true, the popup won't reposition itself around objects on the y-axis 
	
	//INTERNAL FLAGS
	this.index = null;						//INTERNAL - used to track the popup's position in ddmlActivePopups
	this.useBacking = !xMoz;				//INTERNAL - iframe backs are added for IE
	this.body = null;						//INTERNAL - contains the main popup div
	this.inner = null;						//INTERNAL - contains the first level content container in the popup
	this.reNum = new RegExp('^[0-9\-]*$');	//INTERNAL - an RE to test if something is a number
	
	//Abstract properties & functions - looked for but only used when needed
	//this.onBeforeDisplay = null;
	//this.onAfterDisplay = null;
	//this.onBeforeClose = null;
	//this.onAfterClose = null;
	//this.onDragEnd = null
}

function ddmlPopupToString(bShowContents) {
	var contents;
	if(bShowContents) contents = '"\n Contents:"' + (typeof this.contents == 'string')?this.contents:this.contents.outerHTML;
	else contents = '';
	return 'Popup name:"' + this.name + '\n", ID:"' + this.id + contents + '"';
}
ddmlPopup.prototype.toString = ddmlPopupToString;

ddmlPopup.prototype.display = function(oParent) {
	var bContinue = true;
	if(this.onBeforeDisplay) bContinue = this.onBeforeDisplay();
	if(!bContinue) return;
	
	//Build the main div
	this.body = document.createElement('div');
	this.body.style.textAlign = 'center';
	this.body.className = 'ddmlPopupOuter';
	if(this.id) this.body.id = this.id;
	
	//And the inner div
	var innerDiv = document.createElement('div');
		innerDiv.className = 'ddmlPopupInner';

	var popupBacking;
	if(this.useBacking) {
		//IE needs an iframe behind the popup or the 
		if (this.debug) ddmlAddThread('debug_ddmlPopup.display', 'ddml', 'Adding an iframe back for IE select hiding');
		innerDiv.className += 'Backed';
		popupBacking = document.createElement('iframe');
			popupBacking.className = 'ddmlPopupIframeBack';
			popupBacking.name = 'ddmlPopupIframeBack';
			popupBacking.style.zIndex = -100;
		this.body.appendChild(popupBacking);
		popupBacking.style.dispay = '';
	}
	var header;
	if(this.bShowToolbar) {
		//Note that no toolbar functionality is even created if the toolbar is not requested.
		if (this.debug) ddmlAddThread('debug_ddmlPopup.display', 'ddml', 'Adding a toolbar to the popup "' + this.name + '"');
		header = document.createElement('div');
		header.className = 'ddmlPopupHeader';
		if(this.icon || this.title) {
			var titleNode = document.createElement('div');
			titleNode.className = 'ddmlPopupTitle';
			if (typeof this.icon == 'string') titleNode.innerHTML = this.icon + this.title;
			else {
				titleNode.appendChild(this.icon);
				titleNode.appendChild(document.createTextNode(this.title));
			}
			header.appendChild(titleNode);
		}
		var closeButton = new ddmlButton('X', ddmlCloseThisPopupE, 'ddmlPopupButton');
		var maximizeButton = new ddmlButton('|=|', ddmlMaximizeThisPopupE, 'ddmlPopupButton');
		var minimizeButton = new ddmlButton('||', null, 'ddmlPopupButton');
		var debugButton = new ddmlButton('?', ddmlDebugThisPopupE, 'ddmlPopupButton');
		if (this.bShowClose) 		header.appendChild(closeButton.getObject());
		if (this.bAllowMaximize) 	header.appendChild(maximizeButton.getObject());
		if (this.bAllowMinimize) 	header.appendChild(minimizeButton.getObject());	
		if (this.debug)				header.appendChild(debugButton.getObject());
		innerDiv.appendChild(header);
	}
	//Set the contents to innerHTML if sent as a string, or append them if they are a node.
	if(typeof this.contents == 'string') {
		if (this.debug) ddmlAddThread('debug_ddmlPopup.display', 'ddml', 'Inserting string-based contents "' + this.contents + '"');
		var contents = document.createElement('div');
		contents.innerHTML = this.contents;
		innerDiv.appendChild(contents);
	} else if(this.contents && this.contents.nodeName) {
		if (this.debug) ddmlAddThread('debug_ddmlPopup.display', 'ddml', 'Inserting a node ' + getElementIDString(this.contents) + ' into the popup "' + this.name + '"');
		this.contents.style.display = 'block';
		this.contents.style.visibility = 'visible';
		innerDiv.appendChild(this.contents);
	} else {
		ddmlAddThread('error_ddmlPopup.display', 'ddml', 'No valid contents were declared - ' + getElementIDString(contents) + ' was passed.');
	}
	
	//Put it all together
	this.body.appendChild(innerDiv);
	this.body.style.position = 'absolute';
	this.body.style.top = '0px';
	this.body.style.left = '0px';
	this.body.style.display = 'block';
	document.body.appendChild(this.body);
	//if(this.bFade) this.fade(0);
	this.size();
	//Make positioning a little smarter when displaying around a node
	//NOTE: Repeated code from position() in here.  This needs to be optimized.
	if(this.target && this.target.length == 3 && this.target[0].nodeName) {
		//Pre-calculate the new position
		var newTop = xPageY(this.target[0]) - xHeight(this.body);
		var newBottom = xPageY(this.target[0]) + xHeight(this.target[0]) + xHeight(this.body);
		var newLeft = xPageX(this.target[0]) - xWidth(this.body);
		var newRight = xPageX(this.target[0]) + xWidth(this.target[0]) + xWidth(this.body);
		if(!this.bIgnoreWidthBoundaries) {
			switch(this.target[1].toLowerCase()) {
				case 'left':
					//If positioning it on the left will take it off the screen, move it to the right
					if(this._distanceFrom('left', newLeft) < 0 && //...and if the left will go off the screen
						this._distanceFrom('left', newLeft) < this._distanceFrom('right', newRight)) {
						//...and if the popup will fit better to the right than to the left of the node
							this.target[1] = 'right';
					}
					break;
				case 'right':
					//If positioning it on the right will take it off the screen, move it to the left
					if(this._distanceFrom('right', newRight) < 0 && //...and if the right will go off the screen
						this._distanceFrom('right', newRight) < this._distanceFrom('left', newLeft)) {
						//...and if the popup will fit better to the right than to the left of the node
							this.target[1] = 'left';
					}
					break;
				// 'middle' is handled in position() and doesn't account for "best-fit"
			}
		}
		if(!this.bIgnoreHeightBoundaries) {
			switch(this.target[2].toLowerCase()) {
				case 'top':
					//If positioning it on top will take it off the screen, move it to the bottom
					if(this._distanceFrom('top', newTop) < 0 && //...and if the top goes off the screen
						this._distanceFrom('top', newTop) < this._distanceFrom('bottom', newBottom)) {
						//...and if the popup will fit better below than above the node
							this.target[2] = 'bottom';
					}
					break;
				case 'bottom':
					//If positioning it on bottom will take it off the screen, move it to the top
					if(this._distanceFrom('bottom', newBottom) < 0 && //...and if the bottom will go off the screen
						this._distanceFrom('bottom', newBottom) < this._distanceFrom('top', newTop)) {
						//...and if the popup will fit better above than below the node
							this.target[2] = 'top';
					}
					break;
				// 'center' is handled in position() and doesn't account for "best-fit"
			}
		}
	}
	this.position();
	this.register(oParent);
	if(this.bFade) {
		if(this.body.currentStyle) this._existingIEFilter = this.body.currentStyle.filter;
		if(!this._existingIEFilter || this._existingIEFilter == 'undefined') this._existingIEFilter = '';
		this.fade(0);
		setTimeout('ddmlPopupFade(' + this.index + ', 1)', this.fadeSpeed);
	}
	
	//Register drag events for the header if allowed
	if(this.bAllowDrag && header) {
		if (this.debug) ddmlAddThread('debug_ddmlPopup.display', 'ddml', 'Enabling drag for the popup "' + this.name + '"');
		var finalDragEvent = (this.onDragEnd)?this.onDragEnd:null;
		xEnableDrag(header, ddmlPopupDragStart, ddmlPopupDrag, finalDragEvent);
	}
	
	//If there's any inputs in the popup, focus on the first
	var inputs = this.body.getElementsByTagName('input');
	var bFound = false;
	for(var i = 0; i < inputs.length; i ++) {
		if(inputs[i].type.search(/hidden/i) < 0 && isNodeVisible(inputs[i])) {
			bFound = true;
			inputs[i].focus();
			break;
		}
	}
	if(!bFound) {
		var selects = this.body.getElementsByTagName('select');
		for(var i = 0; i < selects.length; i ++) {
			if(selects[i].type.search(/hidden/i) < 0 && isNodeVisible(selects[i])) {
				selects[i].focus();
				break;
			}
		}
	}
	if(this.onAfterDisplay) this.onAfterDisplay();
	display = this.body;
}

ddmlPopup.prototype.maximize = function() {
	this.width = xClientWidth() - (this.padding);
	this.height = xb.clientHeight() - (this.padding);
	if (this.debug) ddmlAddThread('debug_ddmlPopup.maximize', 'ddml', 'Maximizing the popup "' + this.name + '" to width=' + this.width + ' and height=' + this.height);
}

ddmlPopup.prototype.size = function() {
	if(this.width && this.reNum.test(this.width))	xWidth(this.body, this.width);
	if(this.height && this.reNum.test(this.height)) xHeight(this.body, this.height);
	if(this.useBacking)	xResizeTo(this.body.getElementsByTagName('iframe')[0], xWidth(this.body), xHeight(this.body));
	if (this.debug) ddmlAddThread('debug_ddmlPopup.size', 'ddml', 'Attempted to resize the popup "' + this.name + '" to width=' + this.width + ' and height=' + this.height + 
		'.  Actual results are width=' + xWidth(this.body) + ' height=' + xHeight(this.body) + '.  If these numbers differ, the content of your popup ' +
		'couldn\'t be compressed and needs to be sized appropriatley before being added.');
}

ddmlPopup.prototype.position = function(){
	//Get the screen parameters and set the defaults to page center
	var screenWidth = xClientWidth();
	var screenHeight = xb.clientHeight();
	var width = xWidth(this.body);
	var height = xHeight(this.body);
	var newTop = xScrollTop() + (screenHeight / 2 - height / 2);
	var newLeft = xScrollLeft() + (screenWidth / 2 - width / 2);
	//If we're positioning the popup over a node
	if(this.target && this.target.length && this.target.length == 3) {
		if(this.target[0].nodeName) {
			var target = this.target[0];
			var targetTop = xPageY(target);
			var targetLeft = xPageX(target);
			var targetHeight = xHeight(target);
			var targetWidth = xWidth(target);
			switch(this.target[1]) {
				case 'middle':
					//Note that, unline left and right (which are handled in display()), this doens't handle best fit
					newLeft = targetLeft + targetWidth / 2 - width / 2;
					if(!this.bIgnoreWidthBoundaries) {
						if(newLeft < xScrollLeft()) newLeft = xScrollLeft();
						if(newLeft + width >= xClientWidth() + xScrollLeft()) newLeft = xClientWidth() + xScrollLeft() - width;
					}
					break;
				case 'left':
					newLeft = targetLeft - width;
					break;
				case 'right':
					newLeft = targetLeft + targetWidth;
					break;
				default:
					if(this.reNum.test(this.target[1])) {
						newLeft = targetLeft + (this.target[1] * 1);
					}
					break;
			}
			switch(this.target[2]) {
				case 'center':
					newTop = targetTop + targetHeight / 2 - height / 2;
					if(!this.bIgnoreHeightBoundaries) {
						if(newTop < xScrollTop()) newTop = xScrollTop();
						if(newTop + height >= xb.clientHeight() + xScrollTop()) newTop = xb.clientHeight() + xScrollTop() - height;
					}
					break;
				case 'top':
					newTop = targetTop - height;
					break;
				case 'bottom':
					newTop = targetTop + targetHeight;
					break;
				default:
					if(this.reNum.test(target[2])) newTop = targetTop + parseInt(target[2]);
					break;
			}
		}
		//Fixes for node-wrapping are done in the display() function.
	} 
	//Otherwise, if left right are declared
	else if (this.target && this.target.length && this.target.length == 2) {
		switch(this.target[0]) {
			case 'middle':
				break;
			case 'left':
				newLeft = 0;
				break;
			case 'right':
				newLeft = screenWidth - width;
				break;
			default:
				if(this.reNum.test(this.target[0])) newLeft = parseInt(this.target[0]);
				break;
		}
		switch(this.target[1]) {
			case 'center':
				break;
			case 'top':
				newTop = 0;
				break;
			case 'bottom':
				newTop = screenHeight - height;
				break;
			default:
				if(this.reNum.test(this.target[1])) newTop = parseInt(this.target[1]);
				break;
		}
		if(!this.bIgnoreHeightBoundaries) {
			if(newTop + height > screenHeight + xScrollTop()) newTop = screenHeight - height;
			if(newTop < 0) newTop = 0;
		}
		if(!this.bIgnoreWidthBoundaries) {
			if(newLeft + width > screenWidth + xScrollLeft()) newLeft = screenWidth - width;
			if(newLeft < 0) newLeft = 0;
		}
	}
	
	//Fix off-screen popups
	if (this.debug) ddmlAddThread('debug_ddmlPopup.position', 'ddml', 'Moving the popup "' + this.name + '" to x=' + newLeft + ', y=' + newTop);
	xLeft(this.body, newLeft);
	xTop(this.body, newTop);
}

//Compares a position value against a particular side of the rendering window and returns the distance from the edge.
//Negative returns indicate that the value exists off screen by the absolute amount.
//If value is not passed, the current value of the popup on the side it's compared to is used.
ddmlPopup.prototype._distanceFrom = function(side, value) {
	var retVal = 0;
	switch(side.toLowerCase()) {
		case 'left':
			if(!value) value = xLeft(this.body);
			retVal = value - xScrollLeft();
			break;
		case 'right':
			if(!value) value = xLeft(this.body) + xWidth(this.body);
			retVal = xClientWidth() + xScrollLeft() - value;
			break;
		case 'top':
			if(!value) value = xTop(this.body);
			retVal = value - xScrollTop();
			break;
		case 'bottom':
			if(!value) value = xTop(this.body) + xHeight(this.body);
			retVal = xb.clientHeight() + xScrollTop() - value;
			break;
	}
	return retVal;
}

ddmlPopup.prototype.fade = function(counter) {
	var newFade1Scale = (counter * this.fadeSize > 1)?1:counter * this.fadeSize;
	newFade1Scale = Math.round(newFade1Scale * 10) / 10;
	this.body.style.opacity = newFade1Scale;
	this.body.style.filter = this._existingIEFilter + ' progid:DXImageTransform.Microsoft.Alpha(opacity=' + (newFade1Scale * 100) + ', style=0)';
	counter ++;
	if(newFade1Scale < 1 && ddmlActivePopups[this.index] && ddmlActivePopups[this.index].fade)
		setTimeout('ddmlPopupFade(' + this.index  + ', ' + counter + ')', this.fadeSpeed);
	else {
		var origFilter = this.body.style.filter;
		this.body.style.filter = this._existingIEFilter;
	}
}

ddmlPopup.prototype.register = function(oParent) {
	//Register the popup internally
	this.body.ddmlPopup = ddmlActivePopups.length;
	this.index = ddmlActivePopups.length;
	ddmlActivePopups.push(this);
	//Register it in the Z-handler
	//ddmlRegisterPopup(this, oParent, this.bShowMask); //For z-indexing
}

ddmlPopup.prototype.destroy = function() {
	//Destroy the popup contents if they exist - otherwise this is an invalid popup, so an error is thrown.
	if(this.body && !this.nodeName) {
		var bContinue = (window.localPopupDestroy)?localPopupDestroy(this):true;
		if (this.onBeforeClose) bContinue = this.onBeforeClose();
		if (!bContinue) return;
		if (this.debug) ddmlAddThread('debug_ddmlPopup.destroy', 'ddml', 'Removing DOM references to popup "' + this.toString() + '"');
		//Remove it from the z-handler
		//ddmlUnregisterPopup(this);
		//Blow away the contents after backing up any forms (if you don't back them up, they can't submit from the popup!)
		var forms = this.body.getElementsByTagName('form');
		var bContinue = true;
		if(forms.length > 0) {
			for(var i = ddml_INTERNAL_activePopupFormRegister.length - 1; i >= 0 ; i --) {
				if(this.debug) ddmlAddThread('debug_ddmlPopup.destroy', 'ddml', 'Destroying saved item, ' + getElementIDString(ddml_INTERNAL_activePopupFormRegister[i]));
				for(var j = 0; j < forms.length; j ++) {
					if(forms[j] == ddml_INTERNAL_activePopupFormRegister) {
						bContinue = false;
						break;
					}
				}
				if(bContinue && ddml_INTERNAL_activePopupFormRegister[i]) {
					ddmlRemoveNode(ddml_INTERNAL_activePopupFormRegister[i]);
				}
				bContinue = true;
			}
			ddml_INTERNAL_activePopupFormRegister = new Array();
			for(var i = forms.length - 1; i >= 0 ; i --) {
				if(forms[i] && forms[i].style) {
					forms[i].style.display = 'none';
					forms[i].name += new Date();
					if(this.debug) ddmlAddThread('debug_ddmlPopup.destroy', 'ddml', 'Backing up item, ' + getElementIDString(forms[i]));
					ddml_INTERNAL_activePopupFormRegister.push(document.body.appendChild(forms[i]));
				}
			}
		}
		ddmlRemoveNode(this.body, true);
		//Remove the node from the popup register
		if (this.debug) ddmlAddThread('debug_ddmlPopup.destroy', 'ddml', 'Destryoing popup at index ' + this.index + ' of ' + ddmlActivePopups.length);
		ddmlActivePopups.splice(this.index - 1,1);
		if (this.debug) ddmlAddThread('debug_ddmlPopup.destroy', 'ddml', 'New length after destruction:' + ddmlActivePopups.length + '.');
		//Reset the positions of the other active popups
		for(var i = 0; i < ddmlActivePopups.length; i ++) {
			ddmlActivePopups[i].index = i + 1;
			if (ddmlActivePopups[i].body) ddmlActivePopups[i].body.ddmlPopup = i + 1;
		}
	} else {
		ddmlAddThread('error_ddmlPopup.destroy', 'ddml', 'The destroy function for popup ' + this + ' was called, but the popup had no content.  No popup destruction will occur.');
	}
	this.body = null;
	this.contents = null;
	this.reNum = null;
	if (this.onAfterClose) bContinue = this.onAfterClose();
}

/*

										HELPER FUNCTIONS
	* These functions exist to get or manipulate a particular popup from the inside.  Since there
	is no direct reference to the popup other than at the outer div of the popup itself, each of
	these functions is passed a node on the inside of the popup (usually a trigger button, but it
	can be any element) and browse up to the popup itself to perform manipulations.

	* ddmlGetThisPopup is the crucial function here - it finds the popup object and returns it.

	* Objects implementing ddmlPopup should define their helper functions in a similar manner.

*/

function ddmlGetThisPopup(node) {
	var origNode = node;
	if(node) {
		while(node.ddmlPopup == null && node.parentNode && node.parentNode.nodeType && node.parentNode.nodeType == 1) node = node.parentNode;
		if(node.ddmlPopup != null) {
			return ddmlActivePopups[(node.ddmlPopup * 1)];
		}
	}
	ddmlAddThread('error_ddmlGetThisPopup', 'ddml', 'System tried to get a popup and failed.  Called was ' + getElementIDString(origNode) +' and last node looked at was ' + getElementIDString(node));
	return null;
}

function ddmlGetTopPopup() {
	if(ddmlActivePopups.length > 0 && ddmlActivePopups[ddmlActivePopups.length - 1].bAllowEscape) {
		return ddmlActivePopups[ddmlActivePopups.length - 1];
	} else {
		return null;
	}
}

function ddmlCloseThisPopupE(e) {
	var event = new xEvent(e);
	ddmlCloseThisPopup(event.target);
}
function ddmlCloseThisPopup(node) {
	var popup = ddmlGetThisPopup(node);
	if(popup) {
		popup.destroy();
		return true;
	}
	ddmlAddThread('error_ddmlCloseThisPopup', 'ddml', 'System tried to close a popup and failed.  Called was ' + getElementIDString(node) +' and the popup object was ' + popup);
	return false;
}

function ddmlMaximizeThisPopupE(e) {
	var event = new xEvent(e);
	ddmlMaximizeThisPopup(event.target);
}

function ddmlMaximizeThisPopup(node) {
	var popup = ddmlGetThisPopup(node);
	if(popup) {
		ddmlAddThread('debug_ddmlMaximizeThisPopup', 'ddml', 'Maximizing popup at index ' + i + ' of ' + ddmlActivePopups.length);
		popup.maximize();
		popup.size();
		popup.position();
		return true;
	}
	ddmlAddThread('error_ddmlMaximizeThisPopup', 'ddml', 'System tried to maximize a popup and failed.  Called was ' + getElementIDString(node) +' and the popup object was ' + popup);
	return false;
}

function ddmlCloseAllPopups() {
	for(var i = ddmlActivePopups.length - 1; i >= 0; i --) {
		ddmlActivePopups[i].destroy();
	}
	ddmlActivePopups = new Array();
}

function ddmlCloseTopPopup() {
	if(ddmlActivePopups.length > 0 && ddmlActivePopups[ddmlActivePopups.length - 1].bAllowEscape) ddmlActivePopups[ddmlActivePopups.length - 1].destroy();
}

function ddmlDebugThisPopupE(e) {
	var event = new xEvent(e);
	ddmlDebugThisPopup(event.target);
}

function ddmlDebugThisPopup(node) {
	var popup = ddmlGetThisPopup(node);
	if(popup) {
		alert(popup.toString(true));
		return true;
	}
	ddmlAddThread('error_ddmlMaximizeThisPopup', 'ddml', 'System tried to maximize a popup and failed.  Called was ' + getElementIDString(node) +' and the popup object was ' + popup);
	return false;
}

function ddmlGetCurrentPopupTrace() {
	ddmlAddThread('debug_ddmlPopups', 'ddml', ddmlActivePopups.length + ' popups are currently registered in the system.');
	for(var i = 0; i < ddmlActivePopups.length; i ++) {
		ddmlAddThread('debug_ddmlPopups', 'ddml', 'Popup #' + (i + 1) + ' - ' + ddmlActivePopups[i]);
	}
}

function ddmlPopupFade(popupIndex, counter) {
	if(ddmlActivePopups[popupIndex]) {
		ddmlActivePopups[popupIndex].fade(counter);
	}
}

/*
CASQUE stuff that needed to be moved over
*/
if(window.addEventListener) window.addEventListener('keydown', clearTopPopupOnEscape, false);
else if(window.attachEvent) {
	window.attachEvent('onload', function() {document.body.attachEvent('onkeypress', clearTopPopupOnEscape); });
}
function clearTopPopupOnEscape(e) {
	if(!e) e = window.event;
	if(e.keyCode == 27) ddmlCloseTopPopup();
}

function ddmlAddThread() {
	return false;
};

function ddmlRemoveNode(node) {
	node.parentNode.removeChild(node);
	node.innerHTML = '';
	node = null;
}
function isNodeVisible(oNode) {
	var retVal = true;
	var loopNode = oNode;
	while(retVal && loopNode.parentNode) {
		if(loopNode.style.display.toLowerCase() == 'none' || getStyle(loopNode, 'display').toLowerCase() == 'none' || xb.getStyle(loopNode, 'visibility').toLowerCase() == 'hidden' || loopNode.style.visibility.toLowerCase() == 'hidden') {
			retVal = false;
		}
		loopNode = loopNode.parentNode;
	}
	return retVal;
}
function domChildren(parentNode) {
	if(parentNode) {
		var retVal = false;
		if(parentNode.children) {
			retVal = parentNode.children;
		} else if(parentNode.childNodes) {
			retVal = new Array();
			for(var i = 0; i < parentNode.childNodes.length; i ++) {
				(parentNode.childNodes[i].nodeType == 1)?retVal.push(parentNode.childNodes[i]):null;
			}
		}
		return retVal;
	} else {
		return new Array();
	}
}

function getElementIDString(node) {
	if(!node || !node.nodeName) return '(Invalid node)';
	else return node.nodeName + ' (id=' + node.id + ')';
}

