/*
 * Copyright (c) 1997-2009, Ron Lussier. All rights reserved.
 *
 * This software is an unpublished work subject to a confidentiality agreement
 * and protected by copyright and trade secret law. Unauthorized copying,
 * redistribution or other use of this work is prohibited. All copies must
 * retain this copyright notice. Any use or exploitation of this work without
 * authorization could subject the perpetrator to criminal and civil liability.
 *
 * The above copyright notice does not indicate actual or intended publication
 * of this source code.
 */

/*---------------------------------------------------------------------------------------------------------
 * This file contains code used by Earthenberm applications for presenting dialogs
 * to the user.
 *
 * This file requires the following Earthenberm files to be included:
 *      eb-common.js
 *		eb-dom.js
 *      eb-effects.js
 *---------------------------------------------------------------------------------------------------------*/

if (typeof EB == "undefined") {
	/**
	 * The EARTHENBERM global namespace object.
	 */
	var EB = {};
	}

if (typeof EB.dialog == "undefined") {
	/**
	 * The EARTHENBERM dialog namespace object.
	 */
	EB.dialog = {};
	}

/* Constructed at the END of this file:
 *		EB.dialogManager
 */
 
/*
 * The dialogImpl class is a singleton that manages all of the Earthenberm DHTML dialogs.
 */
EB.dialogManagerImpl = function() {

	/*-----------------------------------------------------------------------------------------------------
	 *	MEMBER VARIABLES
	 *-----------------------------------------------------------------------------------------------------*/

	/*
	 * The z-index to be used for new overlays.  This value changes as new dialogs are
	 * constructed.
	 */
	if ((typeof EB.effects != 'undefined') &&
		(typeof EB.effects.OVERLAY_Z_INDEX != 'undefined')) {
		this.CURRENT_Z_INDEX = EB.effects.OVERLAY_Z_INDEX + 10;
		}
	else {
										// Start with an arbitrary high z-index.
		this.CURRENT_Z_INDEX = 100;
		}

	/*
	 * Member variable for the list of active dialogs.
	 */
	this.activeDialogList = new Array();

	/*
	 * A counter mainly used to differentiate dialog core IDs.
	 */
	this.dialogUniqueId = 0;

	this.fetchComplete = false;
	this.occlusionComplete = false;
	this.fetchResults = null;

	/*-----------------------------------------------------------------------------------------------------
	 *	PUBLIC FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/

	/*
	 * global variables
	 */
	EB.dialog.OVERLAY_OPACITY = 0.80;
	EB.dialog.TIMER = 5;
	EB.dialog.SPEED = 10;
	EB.dialog.WRAPPER = 'PageContent';


	/*-----------------------------------------------------------------------------------------------------
	 *	CONTEXT-SENSITIVE HELP FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/

	/**
	 * Keeps track of whether we're currently showing a context-sensitive help panel.
	 */
	EB.dialog.contextHelpId = 'GDContextHelpPanel';
	EB.dialog.contextHelpShown = false;

	/**
	 * Function to show context help in a pop-up panel.
	 *
	 * @param positionPoint		The ID or object 'containing' the help popup.  The popup will be positioned
	 *							relative to this item.
	 * @param helpContentsId	The ID of the element containing the help text.  This must be a string.
	 * @param width				The width of the help box in pixels.
	 */
	function showHelp(positionPoint, helpContentsId, width) {
		positionPoint = id(positionPoint);

		if (!positionPoint) {
			positionPoint = id('PageContent');

			if (!positionPoint) {
				alert('Sorry, help cannot be displayed..');
				return;
			}
		}

		if (typeof helpContentsId !== 'string') {
			alert('Sorry, help cannot be displayed..');
			return;
		}

		var		helpContents = id(helpContentsId);

		if (!helpContents) {
			alert('Sorry, help cannot be displayed...');
			return;
		}
		
		if (typeof width === 'undefined') {
			width = 250;
		}

		var		helpContentsHTML = helpContents.innerHTML;
		
		if (EB.dialog.contextHelpShown) {
			panelClose(EB.dialog.contextHelpId);
			document.onclick = null;
		}

		panelCreate(EB.dialog.contextHelpId, helpContentsHTML, positionPoint, width, 17, -5, null, null, null, 
					'#e3e3e3', false, true );

		/*
		 * Set an onclick handler to catch clicks outside of the panel.
		 * We do this in a 'setTimeout()' method because we don't want to catch click that occurred initially
		 * to bring up the help dialog.
		 */
		setTimeout( installDismissHelpHandler, 1);

		panelShow(EB.dialog.contextHelpId);
		EB.dialog.contextHelpShown = true;

		return false;
	}

	function installDismissHelpHandler() {
		document.onclick = function(event) {
			var		popup = id(EB.dialog.contextHelpId);
			var		descendant;

			event = EB.dom.fixEvent(event);

			descendant = EB.dom.isDescendant(event.target, popup);

			if (!event.target) {
				alert('target is null');
			}
			else if (!descendant) {
				document.onclick = null;

				panelClose(EB.dialog.contextHelpId);
				EB.dialog.contextHelpShown = false;
			}

			return true;
		};
	}


	/*-----------------------------------------------------------------------------------------------------
	 *	PANEL MANAGEMENT FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/

	/**
	 * Function to create a hidden dialog panel.  To display the panel, call 'panelShow(dialogId)'.
	 *
	 * @param dialogId			The ID to be given to the panel.  This must be a string value.
	 * @param contentHTML		The initial HTML to use to populate the dialog.
	 * @param dialogParent		The parent of the dialog.  The dialog will be positioned absolutely in
	 *							relation to this parent.  This may be 'null' to position the panel with
	 *							relation to the page content area.  This is useful for getting around
	 *							$%#@* IE bugs.
	 * @param width				The width to give the panel.
	 * @param top				The absolute top position of the dialog, or null.
	 * @param left				The absolute left position of the dialog, or null.
	 * @param bottom			The absolute bottom position of the dialog, or null.
	 * @param right				The absolute right position of the dialog, or null.
	 * @param zIndex			The zIndex of the dialog.  If not specified, this defaults to '1000'.
	 * @param bgColor			The background color for the contents of the panel.  Defaults to 'white'.
	 * @param showClose			Boolean parameter indicating whether or not the 'close' field should be shown.
	 *							Defaults to 'true'.
	 * @param clickAwayClose	Boolean parameter indicating whether or not the dialog should close
	 *							if the user clicks anywhere outside of its area.  Defaults to 'false'.
	 */
	function panelCreate(dialogId, contentHTML, dialogParent, width, top, left, bottom, right, zIndex,
							bgColor, showClose, clickAwayClose) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}

		if (typeof bgColor !== 'string') {
			bgColor = 'white';
		}

		dialogParent = id(dialogParent);

		if (dialogParent == null) {
			dialogParent = id('PageContent');	// Make relative to page content.
		}

		if ((dialogParent == null) || (typeof dialogParent !== 'object')) {

			dialogParent = document.body;		// Not a great recovery, but this is a coder error.
		}

		if (typeof width !== 'number') {
			width = 200;
		}

		if (typeof top !== 'number') {
			top = null;
		}

		if (typeof left !== 'number') {
			left = null;
		}

		if (typeof bottom !== 'number') {
			bottom = null;
		}

		if (typeof right !== 'number') {
			right = null;
		}

		if (top == null && bottom == null) {
			top = 1;
		}

		if (left == null && right == null) {
			left = 1;
		}

		if (typeof zIndex !== 'number') {
			zIndex = 10000;
		}

		if (typeof showClose !== 'boolean') {
			showClose = true;
		}

		if (dialogParent) {
			var		resultsWindow = document.createElement('div');
			
			resultsWindow.clickAwayClose = clickAwayClose;

			if (resultsWindow) {
				resultsWindow.id = dialogId;

				resultsWindow.className = 'gdPanel';
				resultsWindow.style.display = 'none';
				resultsWindow.style.backgroundColor = bgColor;
				resultsWindow.style.zIndex = zIndex;
				resultsWindow.style.width = width + 'px';

				if (top) {
					resultsWindow.style.top = top + 'px';
				}

				if (left) {
					resultsWindow.style.left = left + 'px';
				}

				if (bottom) {
					resultsWindow.style.bottom = bottom + 'px';
				}

				if (right) {
					resultsWindow.style.right = right + 'px';
				}

				dialogParent.appendChild( resultsWindow );

				var		panelHTML = '';

				if (showClose) {
					panelHTML += "<a href='#' onclick='return EB.dialogManager.panelHide(\"" + dialogId + "\");'>" +
												"<div class='closeBox'></div></a>";
				}
				panelHTML += "<div id='" + dialogId + "Contents'>" + contentHTML + "</div>";

				if (showClose) {
					panelHTML = "<div class='gdPanelClosable'>" + panelHTML + '</div>';
				}

				resultsWindow.innerHTML = panelHTML;
			}
		}
	}

	/**
	 * Function to display a dialog panel.
	 *
	 * @param dialogId		The ID of the panel.  This must be a string value.
	 */
	function panelShow(dialogId) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}

		var		panel = id(dialogId);

		if (panel) {
			panel.style.display = 'block';
		}

		/*
		 * Construct a 'shim' ilayer below the popup, with the same size as the popup.
		 * This is required when the popup appears over a 'select' control.
		 */
		EB.effects.showBrowserShim(panel);
	}

	/**
	 * Function to ensure that the specified panel is visible in the browser, by showing the panel and
	 * scrolling if necessary.
	 *
	 * @param dialogId		The ID of the panel.  This must be a string value.
	 */
	function panelReveal(dialogId) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}

		panelShow(dialogId);

		var		panel = id(dialogId);

		if (panel) {
			panel.scrollIntoView();
		}
	}

	/**
	 * Function to hide a dialog panel.
	 *
	 * @param dialogId		The ID of the panel.  This must be a string value.
	 */
	function panelHide(dialogId) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}

		var		panel = id(dialogId);

		if (panel) {
			panel.style.display = 'none';
			EB.effects.deleteBrowserShim(panel);
		}
	}

	/**
	 * Function to close a dialog panel.  This destroys the panel and its contents.
	 *
	 * @param dialogId		The ID of the panel.  This must be a string value.
	 */
	function panelClose(dialogId) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}
		
		panelHide(dialogId);

		var		panel = id(dialogId);

		if (panel) {
			panel.parentNode.removeChild(panel);
			delete panel;
		}
	}

	/**
	 * Function to change the contents of a dialog panel.
	 *
	 * @param dialogId		The ID to be given to the dialog.  This must be a string value.
	 * @param contentsHTML	The replacement HTML for the panel.
	 */
	function panelSetContents(dialogId, contentsHTML) {
		if (typeof dialogId !== 'string') {
			throw 'dialogId parameter to panelCreate() must be a string';
		}

		var		panel = id(dialogId);

		if (panel) {
			var		panelContents = id(dialogId + 'Contents');

			panelContents.innerHTML = contentsHTML;

			/*
			 * Construct a 'shim' ilayer below the popup, with the same size as the popup.
			 * This is required when the popup appears over a 'select' control.
			 */
			EB.effects.showBrowserShim(panel); 
		}
	}


	/*-----------------------------------------------------------------------------------------------------
	 *	MESSAGE DIALOG MANAGEMENT FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/

	/**
	 * Function to show a prompt popup dialog box.  This code does not support automatically adding buttons
	 * because our custom buttons are generated by a tag, so buttons should be included in an HTML block on
	 * the page.
	 *
	 * @param title				The title for the dialog.  This may be passed as null if you do not want a
	 *							title.
	 * @param message			The message to display in the dialog.  This may be HTML code.  If this
	 *							value is null, then 'contentsId' is used instead to get the message text.
	 * @param contentsId		The ID of an element in the current document.  If 'message' is not
	 *							specified, then the contents of this element will be used for the dialog
	 *							contents.
	 * @param onClose			Function to be called when the dialog is closed.  The function will be
	 *							passed a single parameter.  This will be the button 'value' parameter, or
	 *							if the close box is clicked, null.
	 * @param showClose			Boolean parameter indicating whether or not the 'close' field should be shown.
	 *							Defaults to 'false'.
	 */
	function showPromptDialog(title, message, contentsId, showClose, onClose) {
	
		if (typeof message !== 'string') {
			message = "I got nothin'";

			var		content = id(contentsId);
			
			if (content) {
				message = content.innerHTML;
			}
		}
		
		showDialog(title, message, 'prompt', null, showClose, onClose);
	}

	/**
	 * Function to show an information popup dialog box.  See 'showDialog' for details on parameters.
	 */
	function showInfoDialog(title, message, autoHideTime, showClose, onClose) {
		showDialog(title, message, 'info', autoHideTime, showClose, onClose);
	}

	/**
	 * Function to show a success popup dialog box.  See 'showDialog' for details on parameters.
	 */
	function showSuccessDialog(title, message, autoHideTime, showClose, onClose) {
		showDialog(title, message, 'success', autoHideTime, showClose, onClose);
	}

	/**
	 * Function to show a warning popup dialog box.  See 'showDialog' for details on parameters.
	 */
	function showWarningDialog(title, message, autoHideTime, showClose, onClose) {
		showDialog(title, message, 'warning', autoHideTime, showClose, onClose);
	}

	/**
	 * Function to show an error popup dialog box.  See 'showDialog' for details on parameters.
	 */
	function showErrorDialog(title, message, autoHideTime, showClose, onClose) {
		showDialog(title, message, 'error', autoHideTime, showClose, onClose);
	}

	/**
	 * Function to show a generic popup dialog box.  Only one of these can be on display within any 
	 * one browser window.
	 *
	 * @param type				The type of dialog being displayed.  This should be one of the following
	 *							strings:
	 *								info
	 *								prompt
	 *								success
	 *								warning
	 *								error
	 * @param title				The title for the dialog.  This may be passed as null to use the default
	 *							title based on the type.
	 * @param message			The message to be displayed in the dialog box.
	 * @param autoHideTime		If specified, then this dialog will be automatically dismissed after the
	 *							specified number of seconds have passed.
	 * @param showClose			Boolean parameter indicating whether or not the 'close' field should be shown.
	 *							Defaults to 'true'.
	 * @param onClose			Function to be called when the dialog is closed.  The function will be
	 *							passed a single parameter.  This will be the button 'value' parameter, or
	 *							if the close box is clicked, null.
	 * @param buttons			An array of button values.  Each value contains the following elements:
	 *								cancelButton:	boolean indicating if this button should be drawn
	 *												as a 'cancel' button.
	 *								label:			string containing the text for the button.
	 *								value:			any data value... this will be passed to the 'onClose'
	 *												callback.
	 *							If this value is 'null', no buttons will be shown.
	 * @param buttonWidth		If a number, specifies the width of the buttons in pixels.  Otherwise
	 *							each button sizes to its contents.
	 */
	function showDialog(title, message, type, autoHideTime, showClose, onClose, buttons, buttonWidth) {
		if ((typeof type !== 'string') ||
			(type !== 'info' && type !== 'prompt' && type !== 'success' && type !== 'warning')) {
			type = 'error';
		}

		if (typeof title !== 'string') {
			title = '';
		}

		if (typeof message !== 'string') {
			message = '';
		}

		if (typeof showClose !== 'boolean') {
			showClose = true;
		}

		var		dialog;
		var		dialogHeader;
		var		dialogClose;
		var		dialogTitle;
		var		dialogContent;
		var		dialogMask;
	
		if (!id('GDPopupDialog')) {
			dialog = document.createElement('div');
			dialog.id = 'GDPopupDialog';
			dialogHeader = document.createElement('div');
			dialogHeader.id = 'GDPopupDialogHeader';
			dialogTitle = document.createElement('div');
			dialogTitle.id = 'GDPopupDialogTitle';
			dialogClose = document.createElement('div');
			dialogClose.id = 'GDPopupDialogClose'
			dialogContent = document.createElement('div');
			dialogContent.id = 'GDPopupDialogContent';
			dialogMask = document.createElement('div');
			dialogMask.id = 'GDPopupDialogMask';
			document.body.appendChild(dialogMask);
			document.body.appendChild(dialog);

			dialog.appendChild(dialogHeader);
			dialogHeader.appendChild(dialogTitle);
			dialogHeader.appendChild(dialogClose);

			dialog.appendChild(dialogContent);

			dialogClose.setAttribute('onclick', 'EB.dialogManager.hideDialog()');
			dialogClose.onclick = EB.dialogManager.hideDialog;
		}
		else {
			dialog = id('GDPopupDialog');
			dialogHeader = id('GDPopupDialogHeader');
			dialogTitle = id('GDPopupDialogTitle');
			dialogClose = id('GDPopupDialogClose');
			dialogContent = id('GDPopupDialogContent');
			dialogMask = id('GDPopupDialogMask');
			dialogMask.style.visibility = "visible";
			dialog.style.visibility = "visible";
		}
		
		dialog.style.opacity = .00;
		dialog.style.filter = 'alpha(opacity=0)';
		dialog.alpha = 0;

		var		width = _getPageWidth();
		var		height = _getPageHeight();
		var		left = _getLeftPosition();
		var		top = _getTopPosition();
		var		dialogWidth = dialog.offsetWidth;
		var		dialogHeight = dialog.offsetHeight;
		var		dialogTop = Math.round(top + (height / 3) - (dialogHeight / 2));
		var		dialogLeft = Math.round(left + (width / 2) - (dialogWidth / 2));

		dialogTop = String(dialogTop) + 'px';
		dialogLeft = String(dialogLeft) + 'px';

		dialog.style.top = dialogTop;
		dialog.style.left = dialogLeft;
		dialogHeader.className = type + "Header";

		if (title && (title.length > 0)) {
			/*
			 * Set the title into the title block.
			 */
			dialogTitle.innerHTML = title;
		}
		else {
			/*
			 * Hide the title block.
			 */
			dialogTitle.style.display = 'none';
		}

		dialogContent.className = type;
		dialogContent.innerHTML = message;
		
		var		content = id(EB.dialog.WRAPPER);

		dialogMask.style.height = content.offsetHeight + 'px';
		dialog.timer = setInterval("EB.dialogManager._fadeDialog(true)", EB.dialog.TIMER);

		if (autoHideTime > 0) {
			dialogClose.style.visibility = "hidden";
			window.setTimeout("EB.dialogManager.hideDialog()", (autoHideTime * 1000));
		}
		else {
			if (showClose) {
		    	dialogClose.style.visibility = "visible";
			}
			else {
				dialogClose.style.visibility = 'hidden';
			}
		}
	}

	/**
	 * Function to hide & close a generic popup dialog box.  If a dialog box is not active, this function
	 * does nothing.
	 */
	function hideDialog() {
		var		dialog = id('GDPopupDialog');

		clearInterval(dialog.timer);
		dialog.timer = setInterval("EB.dialogManager._fadeDialog(false)", EB.dialog.TIMER);
	}

	/**
	 * Function to add a dialog to the page.  The specified body content will be surrounded with
	 * the correct dialog decoration.
	 *
	 * @param dialogHtml		The HTML specifying the body of the dialog.  This HTML will be
	 *							wrapped in several <div> tags.
	 * @param dialogWidth		The width of the dialog contents in pixels.  This defaults to the value
	 *							EB.dialogManager.DEFAULT_WIDTH.  (Note that the actual 
	 *							dialog will be slightly wider once borders are added.
	 * @param occlude			If true, the page will be occluded before the dialog is presented.
	 *							The default value is 'true'.
	 * @param closeable			true if this dialog can be closed by the user.  This parameter is optional
	 *							and defaults to false.
	 * @param onClose			The JavaScript to invoke if the dialog is closed.  This parameter is optional.
	 *
	 * TODO: We should save a reference to the occlusion object along with the new dialog, so that they can be removed together.
	 */
	function addCustomDialog( dialogHtml, dialogWidth, occlude, closeable, onClose, extraData ) {
		if (typeof dialogWidth != 'number') {
			dialogWidth = -1;
			}

		if (typeof occlude != 'boolean') {
			occlude = true;
			}
			
		if (typeof extraData == 'undefined') {
			extraData = null;
			}

		if (occlude) {
			this.fetchResults = null;
			this.fetchComplete = true;
			this.occlusionComplete = false;

			var			dialogZIndex = this.CURRENT_Z_INDEX + 1;

			this.activeDialogList.push( new EB.dialog( dialogHtml, dialogWidth, dialogZIndex,
														closeable, onClose, extraData ) );

			EB.effects.occludePage( this._onOcclusionComplete, null, null,
											this.CURRENT_Z_INDEX );
			this.CURRENT_Z_INDEX += 2;
			}
		else {
			this.activeDialogList.push( new EB.dialog( dialogHtml, dialogWidth, this.CURRENT_Z_INDEX,
														closeable, onClose, extraData ) );
			this.CURRENT_Z_INDEX++;
			this.getCurrentDialog().display();
		}
	}

	/**
	 * Function to add a dialog to the page.  The specified URL should return a HTML code fragment
	 * representing the dialog.  Ajax will be used to fetch the HTML from the specified URL.
	 *
	 * @param dialogUrl			The URL of the dialog to load.
	 * @param dialogWidth		The width of the dialog contents in pixels.  This defaults to the value
	 *							EB.dialogManager.DEFAULT_WIDTH.  (Note that the actual 
	 *							dialog will be slightly wider once borders are added.
	 * @param occlude			If true, the page will be occluded before the dialog is presented.
	 *							The default value is 'true'.
	 * @param closeable			true if this dialog can be closed by the user.  This parameter is optional
	 *							and defaults to false.
	 * @param onClose			The JavaScript to invoke if the dialog is closed.  This parameter is optional.
	 * @param wrapperClass		A class name that can be used to wrap the dialog.  This can be used to
	 *							affect dialog appearance.
	 * @param onLoadComplete	An optional function to be called when the dialog has been loaded.
	 * @param extraData			Extra data that will be returned by the dialog in the 'onLoadComplete'
	 *							callback.  This parameter is optional.
	 *
	 * TODO: We should save a reference to the occlusion object along with the new dialog, so that they can be removed together.
	 */
	function addAjaxDialog( dialogUrl, dialogWidth, occlude, closeable, onClose, wrapperClass,
							onLoadComplete, extraData ) {
		if (typeof dialogWidth != 'number') {
			dialogWidth = -1;
			}
	
		if (typeof occlude != 'boolean') {
			occlude = true;
			}
	
		if (typeof onLoadComplete != 'function') {
			onLoadComplete = null;
			}
			
		if (typeof extraData == 'undefined') {
			extraData = null;
			}

		var			dialogZIndex = this.CURRENT_Z_INDEX + 1;

		this.activeDialogList.push( new EB.dialog( null, dialogWidth, dialogZIndex, closeable, onClose,
															wrapperClass, onLoadComplete, extraData ) );

		this.fetchResults = null;
		this.fetchComplete = false;

		if (occlude) {
			this.occlusionComplete = false;

			EB.effects.occludePage( this._onOcclusionComplete, null, null,
											this.CURRENT_Z_INDEX );
			this.CURRENT_Z_INDEX++;
			this._fetchAjaxDialog( dialogUrl );
		}
		else {
			this.occlusionComplete = true;
			
			this._fetchAjaxDialog( dialogUrl );
		}

		this.CURRENT_Z_INDEX++;
	}

	/**
	 * Returns the currently-active dialog.
	 *
	 * @returns		The currently-active dialog object, or null if there is no active dialog.
	 */
	function getCurrentDialog() {
		if ((this.activeDialogList == null) || (this.activeDialogList.length == 0)) {
			return null;
		}

		return this.activeDialogList[ this.activeDialogList.length - 1 ];
	}

	/**
	 * Closes the currently-active dialog.
	 *
	 * TODO: We should also remove any associated occlusion.
	 */
	function deleteCurrentDialog() {
		if ((this.activeDialogList == null) || (this.activeDialogList.length == 0)) {
			return;
			}

		var		dialog = this.activeDialogList.pop();
		var		objBody = document.getElementsByTagName("body").item(0);
		
		objBody.removeChild( dialog.wrapper );
		}
		
	/**
	 * Closes all dialogs and removes occlusion.
	 *
	 */
	function closeAllDialogs() {
		this.deleteCurrentDialog();
		EB.effects.revealPage();
		}


	/*-----------------------------------------------------------------------------------------------------
	 * INTERNAL FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/
	
	/**
	 * Function to get the HTML content for a dialog from an Ajax request.
	 *
	 * @param dialogUrl			The URL of the dialog to load.
	 */
	function _fetchAjaxDialog( dialogUrl ) {
		EB.ajax.request( dialogUrl, this._onFetchAjaxDialogComplete );
	}

	/*
	 * Callback triggered when an Ajax request for a dialog has completed.
	 *
	 * @param results		The results of the request, as returned from the EB.ajax.request
	 *						method.
	 */
	function _onFetchAjaxDialogComplete( results ) {
		// Sadly, 'this' isn't carried along to a callback, so we need to get a context...
		var		dialogManager = EB.dialogManager;

		dialogManager.fetchComplete = true;
		dialogManager.fetchResults = results;
	
		if (dialogManager.occlusionComplete) {
			if ((results == null) || !results.success) {
				dialogManager._displayAjaxError( results );
			}
			else {
				dialogManager.getCurrentDialog().display( results.responseText );
				if (dialogManager.getCurrentDialog().onLoadComplete != null) {
					dialogManager.getCurrentDialog().onLoadComplete( dialogManager.getCurrentDialog().getExtraData() );
				}
			}
		}
	}
	
	/*
	 * Callback triggered when the occlusion of a page is complete.
	 */
	function _onOcclusionComplete() {

		// Sadly, 'this' isn't carried along to a callback, so we need to get a context...
		var		dialogManager = EB.dialogManager;

		dialogManager.occlusionComplete = true;
	
		if (dialogManager.fetchComplete) {
			if ((dialogManager.fetchResults == null) || !dialogManager.fetchResults.success) {
				dialogManager._displayAjaxError( results );
			}
			else {
				dialogManager.getCurrentDialog().display( dialogManager.fetchResults.responseText );
				if (dialogManager.getCurrentDialog().onLoadComplete != null) {
					dialogManager.getCurrentDialog().onLoadComplete( dialogManager.getCurrentDialog().getExtraData() );
				}
			}
		}
	}
	
	/**
	 * Method to display an error if the Ajax call is not successful.
	 */
	function _displayAjaxError( results ) {
		alert( "Could not load dialog!" );
		alert( results.httpMethod + "( " + results.url + " )\n\n" +
				"Response " + results.status + ": " + results.statusText );
	
		EB.effects.revealPage( null );
		}
		
	/**
	 * Utility method to calculate the current window width.
	 */
	function _getPageWidth() {
		return window.innerWidth != null ? window.innerWidth : document.documentElement && document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body != null ? document.body.clientWidth : null;
	}

	/**
	 * Utility method to calculate the current window height.
	 */
	function _getPageHeight() {
		return window.innerHeight != null? window.innerHeight : document.documentElement && document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body != null? document.body.clientHeight : null;
	}

	/**
	 * Utility method to calculate the current window vertical offset.
	 */
	function _getTopPosition() {
		return typeof window.pageYOffset != 'undefined' ? window.pageYOffset : document.documentElement && document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ? document.body.scrollTop : 0;
	}


	/**
	 * Utility method to calculate the current window left offset.
	 */
	function _getLeftPosition() {
		return typeof window.pageXOffset != 'undefined' ? window.pageXOffset : document.documentElement && document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ? document.body.scrollLeft : 0;
	}

	/**
	 * Function called repeatedly to fade a dialog in and out.
	 *
	 * @param show		true if the dialog should be shown, and false otherwise.
	 */
	function _fadeDialog(show) {
		if (typeof show !== 'boolean') {
			show = true;
		}

		var		dialog = id('GDPopupDialog');
		var		value;
	
		if (show) {
			value = dialog.alpha + EB.dialog.SPEED;
		}
		else {
			value = dialog.alpha - EB.dialog.SPEED;
		}
	
		dialog.alpha = value;
		dialog.style.opacity = (value / 100);
		dialog.style.filter = 'alpha(opacity=' + value + ')';
	
		if (value >= 99) {
			clearInterval(dialog.timer);
			dialog.timer = null;
		}
		else if (value <= 1) {
			dialog.style.visibility = "hidden";
			id('GDPopupDialogMask').style.visibility = "hidden";

			clearInterval(dialog.timer);
		}
	}


	/*-----------------------------------------------------------------------------------------------------
	 *	FUNCTION EXPOSITION
	 *-----------------------------------------------------------------------------------------------------*/

	this.showHelp = showHelp;
	this.panelCreate = panelCreate;
	this.panelShow = panelShow;
	this.panelHide = panelHide;
	this.panelClose = panelClose;
	this.panelSetContents = panelSetContents;

	this.showInfoDialog = showInfoDialog;
	this.showPromptDialog = showPromptDialog;
	this.showSuccessDialog = showSuccessDialog;
	this.showWarningDialog = showWarningDialog;
	this.showErrorDialog = showErrorDialog;
	this.showDialog = showDialog;
	this.hideDialog = hideDialog;

	this.addCustomDialog = addCustomDialog;
	this.addAjaxDialog = addAjaxDialog;
	this.getCurrentDialog = getCurrentDialog;
	this.deleteCurrentDialog = deleteCurrentDialog;
	this.closeAllDialogs = closeAllDialogs;

	/*
	 * Internal functions
	 */
	this._fetchAjaxDialog = _fetchAjaxDialog;
	this._onOcclusionComplete = _onOcclusionComplete;
	this._onFetchAjaxDialogComplete = _onFetchAjaxDialogComplete;
	this._displayAjaxError = _displayAjaxError;
	this._fadeDialog = _fadeDialog;
	}

/*
 * A new class defining a single instance of a dialog.
 *
 * @param dialogHtml		An optional parameter containing the HTML for the body of the dialog.
 *							This HTML will be wrapped in several <div> tags.
 * @param dialogWidth		The requested width for this dialog.
 * @param zIndex			The z-index at which this dialog should be displayed.  Higher
 *							z-index values appear on top of lower values.
 * @param closeable			true if this dialog can be closed by the user.  This parameter is optional
 *							and defaults to false.
 * @param onClose			The JavaScript to invoke if the dialog is closed.  This parameter is optional.
 * @param onLoadComplete	A function to be called when the dialog has been loaded.
 * @param extraData			Extra data that will be returned by the dialog in the 'onLoadComplete' callback.
 */
EB.dialog = function( dialogHtml, dialogWidth, zIndex, closeable, onClose, wrapperClass, onLoadComplete,
						extraData ) {

	/*-----------------------------------------------------------------------------------------------------
	 *	MEMBER VARIABLES
	 *-----------------------------------------------------------------------------------------------------*/
	/*
	 * Default width for dialogs when it is not otherwise specified.
	 */
	if (typeof dialogWidth == 'undefined') {
		dialogWidth = -1;
		}

	if (typeof dialogHtml == 'undefined') {
		dialogHtml = '';
		}

	if (typeof zIndex == 'undefined') {
		zIndex = 0;
		}

	if (typeof closeable != 'boolean') {
		closeable = false;
		}

	if (typeof onClose != 'string') {
		onClose = null;
		}

	if (typeof onLoadComplete != 'function') {
		onLoadComplete = null;
		}
		
	if (typeof extraData == 'undefined') {
		extraData = null;
		}

	this.contents = dialogHtml;
	this.width = dialogWidth;
	this.wrapper = null;
	this.coreId = null;
	this.core = null;
	this.zIndex = zIndex;
	this.closeable = closeable;
	this.onClose = onClose;
	this.wrapperClass = wrapperClass;
	this.onLoadComplete = onLoadComplete;
	this.onLoadComplete = onLoadComplete;
	this.extraData = extraData;

	/*-----------------------------------------------------------------------------------------------------
	 *	PUBLIC FUNCTIONS
	 *-----------------------------------------------------------------------------------------------------*/

	/**
	 * Function to replace the contents of a dialog.  If the 'display()' method has not yet been
	 * called, the contents will be saved, but not displayed.
	 *
	 * @param dialogHtml		The HTML specifying the body of the dialog.  This HTML will be
	 *							wrapped in several <div> tags.
	 */
	function setContents( dialogHtml ) {
		if (typeof dialogHtml != 'string') {
			return;
			}

		this.contents = dialogHtml;
											/* If the dialog has already been displayed, replace
												the contents */

		if (this.core != null && typeof this.core != 'undefined') {
			if ((typeof this.core == 'object') && (this.core != null)) {
				EB.dom.setElementInnerHTML( this.core, this.contents );
				}
			}
		}

	/**
	 * Function to add this dialog to the page.  The specified body content will be surrounded with
	 * the correct dialog decoration.
	 *
	 * @param dialogHtml		The HTML specifying the body of the dialog.  This HTML will be
	 *							wrapped in several <div> tags.
	 */
	function display( dialogHtml ) {
		if ((typeof this.wrapper == 'undefined') || (this.wrapper == null)) {
			var		dialogLayoutHtml;
			var		middleDiv;
			var		objBody = document.getElementsByTagName("body").item(0);

			// Call setContents() which ignores invalid values.
			this.setContents( dialogHtml );

			this.coreId = 'GD_dialog_core_' + EB.dialogManager.dialogUniqueId;
			EB.dialogManager.dialogUniqueId++;
			
			// TODO: Get this working with DIVs and not the ugly table/spacer hack!

			var 	spacer = "<img src='/static/img/spacer.gif' width='18' height='18' alt=''/>"
			var		closeableHTML = '';
			var		contentsStyle = '';

			if (this.closeable) {
				closeableHTML +=
						"<div class='closeBox' onclick='";

				if (this.onClose) {
					closeableHTML += this.onClose + ';';
				}

				closeableHTML += "EB.dialogManager.closeAllDialogs();return false;'></div>";
			}

			if (this.width > 0) {
				dialogLayoutHtml =
					"<div class='GD_dialog'>\n" +
					"<div class='frame' style='width:" + this.width + "px;'>";
			
				contentsStyle += 'width:' + (this.width - 76) + 'px;';
			}else {
				dialogLayoutHtml =
					"<div class='GD_dialog'>\n" +
					"<div class='frame' style='width:716px;'>";
			
				contentsStyle += 'width:640px;';
			}

			var		tableClass = '';

			if (this.wrapperClass) {
				tableClass = " class='" + this.wrapperClass + "'";
			}

			dialogLayoutHtml +=
						"<table" + tableClass + ">\n" +
							"<tr>\n" +
								"<td class='dlgTopLeft'>" + spacer + "</td>\n" +
								"<td class='dlgTop'>" + spacer + "</td>\n" +
								"<td class='dlgTopRight'><div class='popupPositionPoint'>" + closeableHTML + "</div>" +
									spacer + "</td>\n" +
							"</tr>\n" +
							"<tr>\n" +
								"<td class='dlgLeft'>" + spacer + "</td>\n" +
								"<td class='dlgContents'>\n" +
									"<div id='" + this.coreId + "' class='dlgContents clearfix' style='" + contentsStyle + "'>\n" +
										this.contents +
									"</div>\n" +
								"</td>\n" +
								"<td class='dlgRight'>" + spacer + "</td>\n" +
							"</tr>\n" +
							"<tr>\n" +
								"<td class='dlgBottomLeft'>" + spacer + "</td>\n" +
								"<td class='dlgBottom'>" + spacer + "</td>\n" +
								"<td class='dlgBottomRight'>" + spacer + "</td>\n" +
							"</tr>\n" +
						"</table>\n" +
					"</div>\n" +
					"</div>\n" +
					"<div>&nbsp;</div>";

			this.wrapper = document.createElement("div");
			this.wrapper.setAttribute('class','GD_dialog_wrapper');
			this.wrapper.style.display = 'none';

			EB.dom.setElementInnerHTML( this.wrapper, dialogLayoutHtml );
			
			var		pageSizeArray = EB.dom.getPageSize();
			var		pageScrollArray = EB.dom.getPageScroll();

			this.wrapper.style.position = 'absolute';
			this.wrapper.style.top = pageScrollArray[1] + 'px';
			this.wrapper.style.left = pageScrollArray[0] + 'px';
			this.wrapper.style.width = '100%';
			this.wrapper.style.height = '100%';

			this.wrapper.style.zIndex = this.zIndex;
			this.wrapper.style.display = 'block';

			objBody.appendChild( this.wrapper );
			
			this.core = id( this.coreId );

			if (this.width > 0) {
				this.core.style.width = this.width;
			}
		}
		else {
			EB.dom.setElementInnerHTML( this.core, this.contents );
		}
	}


	/**
	 * Function to add this dialog to the page.  The specified body content will be surrounded with
	 * the correct dialog decoration.
	 *
	 * @param dialogHtml		The HTML specifying the body of the dialog.  This HTML will be
	 *							wrapped in several <div> tags.
	 */
	function getExtraData() {
		return this.extraData;
		}


	/*-----------------------------------------------------------------------------------------------------
	 *	FUNCTION EXPOSITION
	 *-----------------------------------------------------------------------------------------------------*/

	this.setContents = setContents;
	this.display = display;
	this.getExtraData = getExtraData;
	}

/*
 * If it doesn't already exist, construct an instance of the dialogManagerImpl class, stored in
 * the EB.dialogManager variable.
 */
if (typeof EB.dialogManager == "undefined") {
	/**
	 * The EARTHENBERM dialog manager object.
	 */
	EB.dialogManager = new EB.dialogManagerImpl();
	}
