/**
 *------------------------------------------------------------------------------
 * This set of JavaScript functions can be used to validate form entries.  
 * Obviously, only the existence of non-optional text or selection of a radio
 * button can be validated -- the actual values themselves cannot be checked.
 *------------------------------------------------------------------------------
 * <form onSubmit="<element setup>; return validateForm(this);">
 *------------------------------------------------------------------------------
 * <element setup>:
 *   o - this.<element_name>.optional = true; 
 *   o - this.<numerical_element>.min = <min value>;
 *   o - this.<numerical_element>.max = <max value>;
 *------------------------------------------------------------------------------
 */

/**
 *------------------------------------------------------------------------------
 * Function returns true if the supplied string (form element) consists of
 * only newline, tab and space characters 
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - element : The string to be tested for blankness
 *------------------------------------------------------------------------------
 * Returns true if the supplied element is essentially "blank"
 *------------------------------------------------------------------------------
 */
function isBlank(element) {
	var pattern = /^\s*$/;
	return pattern.test(element);
}

/**
 *------------------------------------------------------------------------------
 * Function returns true if the supplied array contains the value specified
 * within the second parameter.
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - element : The element to search for within the array
 *   o - array   : The array whose elements are to be parsed
 *   o - sorted  : true if the array can be assumed to be sorted
 *------------------------------------------------------------------------------
 * Returns true if the array contains the element
 *------------------------------------------------------------------------------
 */
function arrayContains(element, array, sorted) {
	if (array.length==0) {
		return false;
	} else {
		var length = array.length;
		for (var i=0; i<length; i++) {
			if (array[i] == element) {
				return true;
			} else if ((array[i] > element) && (sorted)) {
				return false;
			}
		}
	}
	return false;
}

/**
 *------------------------------------------------------------------------------
 * This function parses a supplied string and replaces all occurences of shell
 * meta characters with an alternative "safe" character.
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - textObject : The form object to parse
 *------------------------------------------------------------------------------
 * Returns nothing; changes the form objects' value directly.
 *------------------------------------------------------------------------------
 */
function replaceMetaChars(textObject) {
	var str = textObject.value;
	var metaStr = new Array ("*","?","|","~","`","<",">","$(");
	var altStr  = "_";

	var length = metaStr.length;

	for (var i=0; i<length; i++) {
		if (str.indexOf(metaStr[i]) != -1) {
			str = replaceString (str, metaStr[i], altStr);
		}
	}
	textObject.value = str;
}


/**
 *------------------------------------------------------------------------------
 * This function searches for the occurrence of a specified string within a 
 * given string and replaces it with an alternative.
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - sourceStr : The string to parse for the given character
 *   o - searchStr  : The character to search for
 *   o - replaceStr : The character to replace
 *------------------------------------------------------------------------------
 * Returns nothing and re-assigns the replacement to the argument directly.
 *------------------------------------------------------------------------------
 */
function replaceString (sourceStr, searchStr, replaceStr) {
	var src = sourceStr;
	while (src.indexOf(searchStr) != -1) {
		// alert ("found '"+searchStr+"' within '"+src+"'");
		var pos = src.indexOf(searchStr);
		src = src.substring(0,pos) + replaceStr + src.substring((pos+searchStr.length), src.length);
	}
	return src;
}

/**
 *------------------------------------------------------------------------------
 * This function checks for the existence of an alias for a given name within
 * an array.
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - name    : The name to search for
 *   o - aliases : An array listing a series [name,alias] pairs
 *------------------------------------------------------------------------------
 * returns the alias or the original name if no alias exists
 *------------------------------------------------------------------------------
 */
function getAlternative(name, aliases) {
	var length = aliases.length;
	for (var i=0; i<length; i++) {
		if (aliases[i][0] == name) {
			return aliases[i][1];
		}
	}
	return name;
}

/**
 *------------------------------------------------------------------------------
 * This function performs the form validation.  It currently checks for:
 *   o - empty text/textarea values
 *   o - no selected option in a select/select multiple element
 *   o - no selected radio button
 *------------------------------------------------------------------------------
 * Arguments:
 *   o - form : The form whose elements require validation
 *------------------------------------------------------------------------------
 * Returns true if all the form elements are deemed to be valid
 *------------------------------------------------------------------------------
 */
function validateForm(form) {
	var msg="";
	var emptyText="";
	var emptySelect="";
	var unspecifiedSelect="";
	var emptyRadio="";
	var radioEmpty = new Array();
	var radioSelected = new Array();
	var errors="";
	var fLength = form.length;

	for (var i=0; i<fLength; i++) {
		var element = form.elements[i];
		// alert (element.name + " == " + element.value);
		if (!element.optional) {
		        

			var name = getAlternative(element.name, formAliases);
			//
			// test the text elements first
			//
			if ((element.type == "text") || (element.type == "textarea")) {
				//
				// Replace all shell meta characters
				//
				replaceMetaChars(element);
				// check if the field is empty:
				if ((element.value == null) || (element.value == "") || isBlank(element.value)) {
					emptyText += "\n\to - " + name;
					continue;
				}
				//
				// if they are numerical, check if they are outwith the specified range
				//
				if (element.numeric || (element.min != null) || (element.max != null)) {
					var v = parseFloat(element.value);
					if (isNaN(v) ||	((element.min != null) && (v < element.min)) ||	((element.max != null) && (v > element.max))) {
						errors += "\nThe '" + name + "' field must be a number";
						if (element.min != null) {
							errors += " greater than " + element.min;
						}
						if (element.max != null && element.min != null) {
							errors += " and less than " + element.max;
						} else if (element.max != null) {
							errors += " less than " + element.max;
						}
						errors += "\n";
					}
				}
				
				//
				// test the select elements
				//
			} else if ((element.type == "select-one") || (element.type == "select-multiple")) {
				if (element.value == "unspecified") {
					unspecifiedSelect += "\n\to - " + name;
                }
				if (element.selectedIndex < 0) {
					emptySelect += "\n\to - " + name;
				}
				//
				// test the radio buttons
				//
			} else if (element.type == "radio") {
				if (element.checked == false) {
					if (radioEmpty.length == 0) {
						radioEmpty[radioEmpty.length] = name;
					} else {
						if (arrayContains(name, radioEmpty, true)) {
							continue;
						} else {
							radioEmpty[radioEmpty.length] = name;
							radioEmpty.sort();
						}
					}
				} else {
					radioSelected[radioSelected.length] = name;
				}
			}
		}
	}
	
	var eLength=radioEmpty.length;
	var selected = radioSelected.toString();
	for (i=0; i<eLength; i++) {
		if (selected.search(radioEmpty[i]) == -1) {
			emptyRadio += "\n\to - " + radioEmpty[i].replace(/_or_/,'/');
		}
	}
	
	if (!errors && !emptyText && !emptyRadio && !emptySelect && !unspecifiedSelect) {
		return true;
	} 
	if (emptyRadio) {
		msg += "\nYou must select at least one of the radio options for:\n" + emptyRadio + "\n";
	}
	if (emptyText) {
		msg += "\nPlease enter a value for the following fields:\n" + emptyText + "\n";
	}
	if (errors) {
		msg += errors;
	}
	if (emptySelect) {
		msg += "\nYou must select at least one element for the following selection lists:\n" + emptySelect + "\n";
	}
	if (unspecifiedSelect) {
		msg += "\nPlease ensure you select an item from the following drop-down menus:\n" + unspecifiedSelect + "\n";
	}

	alert (msg);
	return false;
}

