/**
 * NSX Internal Common JavaScript Functions.
 *
 * This file contains a library of common functions used throughout the NSX
 * Internal application.  Other JavaScript files should not be expected to
 * function without it.
 *
 * @author Daniel J. Summers <daniel@djs-consulting.com>
 * @version $Revision: 5 $
 * @since 1
 * @package NSXapp
 * @subpackage View
 */

/**
 * Add an event handler to an object.
 *
 * @param poObject The object to which the event handler should be added.
 * @param psEventType The event which should be handled.
 * @param poFunction The name of the function to handle the event.
 */
function addEventHandler(poObject, psEventType, poFunction) {
	
	if (poObject.addEventListener){ 
		poObject.addEventListener(psEventType, poFunction, false); 
		return true; 
	}
	else if (poObject.attachEvent) {
		var r = poObject.attachEvent("on" + psEventType, poFunction);
		return r;
	}
	else {
		return false;
	} 
}

/**
 * Remove all white space from both sides of a string.
 *
 * @param psString The string to trim.
 * @return The trimmed string.
 */
function trim(psString) {
	return ltrim(rtrim(psString));
}

/**
 * Remove white space from the front (left side) of a string.
 *
 * @param psString The string to trim.
 * @return The trimmed string.
 */
function ltrim(psString) {
	while (psString.substring(0,1) == " ") {
		psString = psString.substring(1);
	}
	return psString;
}

/**
 * Remove white space from the back (right side) of a string.
 *
 * @param psString The string to trim.
 * @return The trimmed string.
 */
function rtrim(psString) {
	while (psString.substring(psString.length - 1) == " ") {
		psString = psString.substring(0, psString.length - 1);
	}
	return psString;
}

/**
 * Shortcut for "document.getElementById".
 *
 * @return The specified element.
 */
function getElement(psElementId) {
	return document.getElementById(psElementId);
}

/**
 * Validate a string field, ensuring it has some text.
 *
 * @param psElementId The ID of the HTML element to validate.
 * @param psErrorMessage The message to show the user if it's blank.
 * @return True if it's good, false if not.
 */
function validateString(psElementId, psErrorMessage) {
	
	var oElement = getElement(psElementId);
	
	if (trim(oElement.value) == "") {
		alert(psErrorMessage);
		oElement.className = "errorField";
		oElement.focus();
		return false;
	}
	
	oElement.className = "";
	return true;
}

/**
 * Ensure that at least one box in a set has been selected.
 *
 * @param psElementName The name of the option group to validate.
 * @param psErrorMessage The error message to display if one isn't selected.
 *		(passing a blank error message causes the function to simply return true
 *		or false.)
 * @param psLabelName The name of the label to change if there is an error.
 * @param psClassName The CSS class name of the label.
 * @return True if one is selected, false if none are.
 */
function validateOptionGroup(psElementName, psErrorMessage, psLabelName, psClassName) {
	
	var oOpts = document.getElementsByName(psElementName);
	
	for (i = 0; i < oOpts.length; i++) {
		if (oOpts[i].checked) {
			if (psLabelName != "") {
				getElement(psLabelName).className = psClassName;
			}
			return true;
		}
	}
	
	if (psErrorMessage > "") {
		alert(psErrorMessage);
	}
	if (psLabelName != "") {
		getElement(psLabelName).className = psClassName + " errorField";
	}
	return false;
}

/**
 * Validate a dropdown list, ensuring the top option is not selected.
 *
 * @param psElementId The ID of the element to validate.
 * @param psErrorMessage The error message to display if the top option is selected.
 * @return True if a selection has been made, false if not.
 */
function validateDropdown(psElementId, psErrorMessage) {
	
	var oElement = getElement(psElementId);
	
	if (oElement.selectedIndex == 0) {
		alert(psErrorMessage);
		oElement.className = "errorField";
		oElement.focus();
		return false;
	}
	
	oElement.className = "";
	return true;
}

/**
 * Validate a numeric string with a set length.
 *
 * @param psElementId The ID of the element to validate.
 * @param piLength The length of the string.
 * @param psErrorMessage The error message to display if it is not valid.
 * @return True if it's valid, false if not.
 */
function validateNumericString(psElementId, piLength, psErrorMessage) {
	
	var oElement = getElement(psElementId);
	
	if (trim(oElement.value).length == piLength) {
		if (isNumeric(oElement.value)) {
			oElement.className = "";
			return true;
		}
	}
	
	alert(psErrorMessage);
	oElement.className = "errorField";
	oElement.focus();
	return false;
}

/**
 * Validate Date.
 *
 * Quickly validates a date in the form "YYYY-MM-DD".
 *
 * @param psElementId The ID of the element to validate.
 * @param psErrorMessage The error message to display if it is not valid.
 * @return True if valid, false if not.
 */
function validateDate(psElementId, psErrorMessage) {
	
	var oElement = getElement(psElementId);
	var oPieces = oElement.value.split("-");
	
	if ((oPieces.length == 3)
			&& (isNumeric(oPieces[0]))
			&& ((oPieces[1] >= 1) && (oPieces[1] <= 12))
			&& ((oPieces[2] >= 1) && (oPieces[2] <= 31))) {
		// Why does the date have to be in this format?  ;(
		sDate = oPieces[1] + "/" + oPieces[2] + "/" + oPieces[0];
		if (!isNaN(parseInt(Date.parse(sDate)))) {
			// Good enough for government work.
			oElement.className = "";
			return true;
		}
	}
	
	// Must not be good if we got here...
	alert(psErrorMessage);
	oElement.className = "errorField";
	oElement.focus();
	return false;
}

/**
 * Checks a string for all numeric characters.
 *
 * @param psString The string to check.
 * @return True if all characters are numbers, false otherwise.
 */
function isNumeric(psString) {
	
	var sNumbers = "0123456789";
	
	for (x = 0; x < psString.length; x++) {
		if (sNumbers.indexOf(psString.charAt(x)) < 0) {
			return false;
		}
	}
	
	return true;
}

/**
 * Enable an element.
 *
 * @param psString The ID of the element to enable.
 */
function enable(psString) {
	getElement(psString).disabled = false;
}

/**
 * Disable an element.
 *
 * @param psString The ID of the element to disable.
 */
function disable(psString) {
	getElement(psString).disabled = true;
}

/**
 * Test whether a checkbox is checked or not.
 *
 * @param psElementId The ID of the element to test.
 * @return True if checked, false if cleared.
 */
function isChecked(psElementId) {
	return getElement(psElementId).checked;
}

/**
 * Moves an individual from an Available list to an Assigned list.
 */
function moveRight() {
	
	var oAvail = getElement("txtAvailable");
	var oAsg = getElement("txtAssigned");
	
	if (oAvail.selectedIndex >= 0) {
		var iIndex = oAvail.selectedIndex;
		var oOption = oAvail.options[iIndex];
		oAvail.remove(iIndex);
		try {
			// IE doesn't like this.
			oAsg.add(oOption, null);
		}
		catch (oException) {
			// IE likes this better.
			oAsg.add(oOption);
		}
		if (oAvail.options.length <= iIndex) {
			oAvail.selectedIndex = iIndex;
		}
	}
	
}

/**
 * Moves an individual from an Assigned list to an Available list.
 */
function moveLeft() {
	
	var oAvail = getElement("txtAvailable");
	var oAsg = getElement("txtAssigned");
	
	if (oAsg.selectedIndex >= 0) {
		var oOption = oAsg.options[oAsg.selectedIndex];
		oAsg.remove(oAsg.selectedIndex);
		try {
			// IE doesn't like this.
			oAvail.add(oOption, null);
		}
		catch (oException) {
			// IE likes this better.
			oAvail.add(oOption);
		}
	}
	
}

/**
 * Convert Multiple-Select Box to Array.
 *
 * Multiple select boxes do not get posted with the form.  This creates an
 * array of input elements with the values in the box specified.
 *
 * @param psSelectBox The ID of the select box.
 * @param psFormId The ID of the form.
 * @param psName The name the array should have.
 */
function convertMultiSelectToArray(psSelectBox, psFormId, psName) {
	
	var oBox = getElement(psSelectBox);
	
	for (i = 0; i < oBox.options.length; i++) {
		var oInput = document.createElement("input");
		oInput.type = "hidden";
		oInput.name = psName + "[]";
		oInput.value = oBox.options[i].value;
		getElement(psFormId).appendChild(oInput);
	}
}

/**
 * Runs an AJAX request.
 *
 * @param psUrl The URL of the page to retrieve.
 * @param poFunction The function to handle the return data.
 * @return False if the object can't be instantiated
 */
var oXmlRequest;
function runAjaxRequest(psUrl, poFunction) {
	
	try {
		// Everything but IE
		oXmlRequest = new XMLHttpRequest();
	} catch (e) {
		try {
			// IE
			oXmlRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				oXmlRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {
				alert("Sorry - your browser does not support the lookup designed for this page.");
				return false;
			}
		}
	}
	
	oXmlRequest.onreadystatechange = poFunction;
	oXmlRequest.open("GET", psUrl, true);
	oXmlRequest.send(null);
}

/**
 * Parse XML Document.
 *
 * Parse a string into an XML document (used with AJAX requests).
 *
 * @param psString The string with the XML text.
 * @return A DOM document.
 */
function parseXmlDocument(psString) {
	
	var doc;
	
	if (document.implementation.createDocument) {
		// Not IE.
		var parser = new DOMParser();
		doc = parser.parseFromString(psString, "text/xml");
	}
	else {
		 if (window.ActiveXObject) {
			// IE.
			doc = new ActiveXObject("Microsoft.XMLDOM");
			doc.async="false";
			doc.loadXML(psString);
		}
	}
	return doc;
}