/*
 * 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 visual effects.
 *
 * This file requires the following Earthenberm files to be included:
 *      eb-dom.js
 *--------------------------------------------------------------------------------*/

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

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

/*
 * The z-index of the overlay.  Anything being displayed over the overlay should have a z-index
 * larger than this.
 */
EB.effects.OVERLAY_Z_INDEX = 50000;

/*
 * The default speed at which the page occlusion occurs, in seconds.
 */
EB.effects.DEFAULT_OCCLUDE_SPEED = 0.2;

/*
 * Controls transparency of shadow overlay.  1.0 is fully solid.  0.0 is fully transparent.
 */
EB.effects.OVERLAY_OPACITY = 0.80;

/*
 * The z-index of the overlay.  Anything being displayed over the overlay should have a z-index
 * larger than this.
 */
EB.effects._overlayCount = 0;


/*--------------------------------------------------------------------------------
 * Popup message boxes
 *--------------------------------------------------------------------------------*/

/**
 * Shows or hides the specified popup box.
 *
 * The optional 'show' parameter may be true or false.  If it is not specified, it defaults to 'true'.
 * 
 * The optional 'popupPoint' can be specified as the new parent for the popup.
 * This is normally used with popupPoint being relatively or absolutely positioned and 'popup' being
 * absolutely positioned so that it is relative to 'popupPoint'.
 *
 * The 'top', 'left', 'bottom', and 'right' parameters can be used to override the absolute positioning of
 * the element.  Only one of 'top' or 'bottom' should be used; likewise, only one of 'left' vs. 'right' should
 * be used.  If a parameter is not used, pass 'null'.
 *
 * It is assumed that the popup is displayed as a block element.
 */
EB.effects.showPopup = function( popup, display, popupPoint, top, left, bottom, right, zIndex ) {
	popup = id( popup );

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

	if (popup) {
		/*
		 * Only do anything if the popup object actually exists.
		 */
		if (display) {
			/*
			 * Show popup.
			 */
			popupPoint = id( popupPoint );

			/*
			 * If the popup is already displayed, hide it.
			 */	
			popup.style.display = 'none';

			if (popupPoint) {
				/*
				 * Reparent the popup if requested.
				 */
				popupPoint.appendChild( popup );
			}

			/*
			 * Position the popup.
			 */
			if (typeof top == 'number') {
				popup.style.bottom = 'auto';
				popup.style.top = top + 'px';
			}
			else if (typeof bottom == 'number') {
				popup.style.top = 'auto';
				popup.style.bottom = bottom + 'px';
			}

			if (typeof left == 'number') {
				popup.style.right = 'auto';
				popup.style.left = left + 'px';
			}
			else if (typeof right == 'number') {
				popup.style.left = 'auto';
				popup.style.right = right + 'px';
			}

			/*
			 * 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.
			 * This function does nothing for non-IE6 browsers.
			 */
			EB.effects.constructBrowserShim(popup);

			/*
			 * Finally, display the popup.
			 */	
			popup.style.display = 'block';

			if (typeof zIndex === 'number') {
				popup.style.zIndex = zIndex;
				}

			EB.effects.showBrowserShim(popup);
		}
		else {
			/*
			 * Hide popup.
			 */
			popup.style.display = 'none';

			EB.effects.deleteBrowserShim(popup);
		}
	}
}


/*--------------------------------------------------------------------------------
 * IE6 Shim Utilities
 *
 * IE 6 does not properly handle z-index (or for that matter, anything else.)
 * One trick to get z-index to work better is to add a ilayer 'shim' under the
 * absolutely-positioned element.  This code assists in that.
 *--------------------------------------------------------------------------------*/

/**
 * Construct a 'shim' ilayer below an absolutely-positioned element, with the same size as the element.
 *
 * The new ilayer gets its (absolute) position from the specified element, and its z-index is one less than
 * that of the element.  The shim is constructed as a sibling of the element, just before the element
 * in the DOM. Lastly, the shim is initially constructed with 'display: none'.
 */
EB.effects.constructBrowserShim = function(popup) {
	popup = id(popup);

	if (popup && EB.isIE() && (EB.getIEVersion() < 7)) {
		var			ieShim;

		if (popup.ieShimLayer) {
			ieShim = popup.ieShimLayer;
		}
		else {
			ieShim = document.createElement('iframe');
			popup.ieShimLayer = ieShim;
		}
	
		ieShim.setAttribute('src', 'javascript:false;document.write("");');
		ieShim.setAttribute('frameBorder', '0');

		ieShim.style.display = 'none';

		popup.parentNode.insertBefore(ieShim, popup);
	
		ieShim.style.position = 'absolute';
	
		ieShim.style.borderWidth = '0px';
		ieShim.style.overflow = 'hidden';
	
		var		zIndex = EB.dom.getStyle(popup, 'zIndex');
		if (zIndex && (zIndex != '')) {
			ieShim.style.zIndex = zIndex - 1;
		}
	
		return ieShim;
	}
	else {
		popup.ieShimLayer = null;
	}
}

/**
 * Show a 'shim' ilayer below an absolutely-positioned element, with the same size as the element.
 * If necessary, a shim will be constructed.
 */
EB.effects.showBrowserShim = function(popup) {
	popup = id(popup);

	if (popup && !popup.ieShimLayer) {
		EB.effects.constructBrowserShim(popup);
	}

	if (popup && popup.ieShimLayer) {
		popup.ieShimLayer.style.display = 'block';

	    popup.ieShimLayer.style.top = EB.dom.getStyle(popup, 'top');
	    if (!popup.ieShimLayer.style.top || popup.ieShimLayer.style.top.length == '') {
		    popup.ieShimLayer.style.bottom = EB.dom.getStyle(popup, 'bottom');
	    }

	    popup.ieShimLayer.style.left = EB.dom.getStyle(popup, 'left');
	    if (!popup.ieShimLayer.style.left || popup.ieShimLayer.style.left.length == '') {
		    popup.ieShimLayer.style.right = EB.dom.getStyle(popup, 'right');
	    }

	    popup.ieShimLayer.style.width = popup.offsetWidth + 'px';
	    popup.ieShimLayer.style.height = popup.offsetHeight + 'px';
	}
}

/**
 * Hide & destroy a 'shim' ilayer below an absolutely-positioned element.
 */
EB.effects.deleteBrowserShim = function(popup) {
	if (popup && popup.ieShimLayer) {
		/*
		 * If we created an IE shim layer, remove it from the DOM and then stop referring to it.
		 */
		popup.ieShimLayer.style.display = 'none';
		popup.ieShimLayer.parentNode.removeChild(popup.ieShimLayer);
		popup.ieShimLayer = null;
	}
}


/*--------------------------------------------------------------------------------
 * Prompts in edit fields
 *--------------------------------------------------------------------------------*/

/**
 * Toggles a 'prompt' associated with the specified field.
 *
 * Note that the CSS class associated with the field will be swapped between 'dimmed' and no class
 * at all.  If you want to apply a different class to the field, this function will need additional
 * functionality.  (I.e., two new parameters for prompt and data contents.)
 *
 * @param field				The field ID or object.
 * @param focus				true if the field is getting focus, and false otherwise.
 * @param promptString		The string to use as a prompt within the field when it does not have
 *							focus.
 */
EB.effects.toggleFieldPrompt = function( field, focus, promptString ) {
	field = id(field);

	if (focus) {
		if (field.value == promptString) {
			field.value = '';
		}

		field.className = 'fieldData';
	}
	else {
		if ((field.value == '') || (field.value == promptString)) {
			field.value = promptString;
			field.className = 'fieldDefault';
		}
		else {
		field.className = 'fieldData';
		}
	}
}

/**
 * Hides the current page behind a dark gray veil.  This is performed asyncronously.
 *
 * @param onComplete		An optional function to be called once the occlusion has completed.
 *							This value may be null.
 * @param onOccludeClick	An optional function to be called if the user clicks on the occlusion
 *							surface.  This value may be null.
 * @param speed				How long the occlusion animation should take, in seconds.  Use the
 *							value '0' if you don't want animation.
 * @param zIndex			The z-index for the occluding veil.  This defaults to the
 *							value of EB.effects.OVERLAY_Z_INDEX, but may be
 *							overridden to be any value.  The z-index should be greater than '0'
 *							if you want it to appear in front of the page.
 *
 * @see EB.effects.revealPage()
 */
EB.effects.occludePage = function(onComplete, onOccludeClick, speed, zIndex) {
	if ((typeof speed == "undefined") || (speed == null)) {
    	speed = EB.effects.DEFAULT_OCCLUDE_SPEED;
		}

	if ((typeof zIndex != "number")) {
    	zIndex = EB.effects.OVERLAY_Z_INDEX;
		}

 	// Add overlay <div>
 	
 	EB.effects._addOverlay( zIndex, onOccludeClick );

	if (EB.effects._overlayCount == 0) {
		EB.effects._hideSelectBoxes();
		EB.effects._hideFlash();
		}

 	EB.effects._overlayCount++;

	// stretch overlay to fill page and fade in
	var		occlusionOverlayAnim;
	var		attributes;

	var		attributes = {
			   opacity: { from: 0, to: EB.effects.OVERLAY_OPACITY }
			};
	var		pageSizeArray = EB.dom.getPageSize();
	var		overlay = id('GD_overlay');

	EB.dom.setElementOpacity( 'GD_overlay', 0.0 );
	if (EB.getIEVersion() == 6) {
		/*
		 * Work-around for an IE6 bug where ;'fixed' positioning doesn't work.
		 */
		overlay.style.position = 'absolute';
		EB.dom.setElementSize( 'GD_overlay', pageSizeArray[0] + 2000, pageSizeArray[1] + 2000 );
	}
	else {
		overlay.style.position = 'fixed';
		EB.dom.setElementSize( 'GD_overlay', pageSizeArray[0], pageSizeArray[1] );
	}

	overlay.style.top = '0';
	overlay.style.left = '0';

	EB.dom.setElementDisplay( 'GD_overlay', 'block' );

	var		GD_overlayAnim;

	occlusionOverlayAnim = new YAHOO.util.Anim('GD_overlay', attributes, speed );

	if (typeof onComplete == 'function') {
		occlusionOverlayAnim.onComplete.subscribe( onComplete );
		}

	occlusionOverlayAnim.animate(); 
	}

/**
 * Hides the current page behind a dark gray veil.  This is performed asyncronously.
 *
 * @param onComplete	An optional function to be called once the occlusion has completed. 
 * @param speed			how long the occlusion animation should take, in seconds.  Use the
 *						value '0' if you don't want animation.
 *
 * @see EB.effects.occludePage()
 */
EB.effects.revealPage = function( onComplete, speed ) {
	if (typeof speed == "undefined") {
    	speed = EB.effects.DEFAULT_OCCLUDE_SPEED;
		}

	/* Only do this if the overlay exists and is displayed. */

	if (EB.dom.elementExists('GD_overlay') &&
		(EB.dom.getElementDisplay('GD_overlay') != 'none')) {

		var		attributes = {
				   opacity: { to: 0.0  }
				};

		var		revealOverlayAnim;

		revealOverlayAnim = new YAHOO.util.Anim('GD_overlay', attributes, speed );

		if (typeof onComplete == 'function') {
			EB.effects._revealCompleteCallback = onComplete;
			}
		else {
			EB.effects._revealCompleteCallback = null;
			}
		revealOverlayAnim.onComplete.subscribe( EB.effects._onRevealPageComplete );
	
		revealOverlayAnim.animate();
		}
	}


/*--------------------------------------------------------------------------------
 * INTERNAL FUNCTIONS
 *--------------------------------------------------------------------------------*/

/**
 * Callback used to perform processing once the occlusion has been removed from the page.
 */
EB.effects._onRevealPageComplete = function() {
	EB.dom.setElementOpacity( 'GD_overlay', 0.0 );
	EB.dom.setElementDisplay( 'GD_overlay', 'none' );

	EB.effects._overlayCount--;
	
	if (EB.effects._overlayCount == 0) {
		EB.effects._showSelectBoxes();
		EB.effects._showFlash();
		}

	var		objBody = document.getElementsByTagName('body').item(0);

	/* If a callback is specified, call it. */

	if (EB.effects._revealCompleteCallback != null) {
		EB.effects._revealCompleteCallback();
		EB.effects._revealCompleteCallback = null;
		}
	}

/**
 * Function to create the necessary occlusion overlay on the page.  The overlay div is created as
 * the last child of the body of the current document.
 *
 * @param zIndex			The z-index for the occluding veil.
 * @param onOccludeClick	An optional function to be called if the user clicks on the occlusion
 *							surface.  This value may be null.
 */
EB.effects._addOverlay = function( zIndex, onOccludeClick ) {
	var		objBody = document.getElementsByTagName("body").item(0);
	var		objOverlay = objBody.childNodes['GD_overlay'];

	if (null == objOverlay) {

		// Code inserts html at the bottom of the page that looks similar to this:
		//
		//	<div id="GD_overlay"></div>

		objOverlay = document.createElement("div");
	
		objOverlay.setAttribute('id','GD_overlay');

		objOverlay.style.position = 'absolute';
		objOverlay.style.top = '0px';
		objOverlay.style.left = '0px';
		objOverlay.style.display = 'none';
		objOverlay.style.opacity = 0.0;
		objOverlay.style.zIndex = zIndex;

		objBody.appendChild( objOverlay );
		}

	if (typeof onOccludeClick == 'function') {
		objOverlay.onclick = onOccludeClick;
		}
	else {
		objOverlay.onclick = null;
		}
	}

/**
 * Function to show all <select> boxes on the page.
 */
EB.effects._showSelectBoxes = function() {
	var selects = document.getElementsByTagName("select");

	for (i = 0; i != selects.length; i++) {
		selects[i].style.visibility = "visible";
		}
	}

/**
 * Function to hide all <select> boxes on the page.
 */
EB.effects._hideSelectBoxes = function() {
	var selects = document.getElementsByTagName("select");

	for (i = 0; i != selects.length; i++) {
		selects[i].style.visibility = "hidden";
		}
	}

/**
 * Function to show all flash boxes on the page.  Actually, this will show all <object> or <embed>
 * defined page elements.
 */
EB.effects._showFlash = function() {
	var flashObjects = document.getElementsByTagName("object");

	for (i = 0; i < flashObjects.length; i++) {
		flashObjects[i].style.visibility = "visible";
		}

	var flashEmbeds = document.getElementsByTagName("embed");

	for (i = 0; i < flashEmbeds.length; i++) {
		flashEmbeds[i].style.visibility = "visible";
		}
	}

/**
 * Function to hide all flash boxes on the page.  Actually, this will hide all <object> or <embed>
 * defined page elements.
 */
EB.effects._hideFlash = function(){
	var flashObjects = document.getElementsByTagName("object");

	for (i = 0; i < flashObjects.length; i++) {
		flashObjects[i].style.visibility = "hidden";
		}

	var flashEmbeds = document.getElementsByTagName("embed");

	for (i = 0; i < flashEmbeds.length; i++) {
		flashEmbeds[i].style.visibility = "hidden";
		}
	}
