/**
 * Form Validation
 * 
 * This is a library of functions to do common form validation tasks
 * ie make sure a checkbox has been checked or that fields have values etc
 *
 * @author	cam @ uq.edu.au (remove spaces)
 * @date	20030709
 */


/**
 * Validate Form
 *
 * This function checks that the passed in form fields have 
 * a value assigned to them, using various functions in this file.
 *
 * Note the additional parameters argument, which allows you to 
 * set parameters keyed on the same key as required values
 *
 * Example Usage :
 * <script type="text/javascript">
 *	<!--
 *		var required_values = new Array();
 *		
 *		required_values["elves"] = "Elvenkind";
 *	//-->
 *	</script>
 *	<form	onsubmit="return validate_form(this, required_values)"> 
 *		<input type="text" name="elves" />
 *		<input type="submit" value="test" />
 *	</form>
 *
 * @param	object	form
 * @param	array	required_values - key is form element name, value is friendly name to display in error
 * @param	array	additional_parameters	optional - additional parmaters
 * @access	public
 * @return	bool	have_values
 */
function validate_form(form, required_values, additional_parameters) {
	var additionals_exist = additional_parameters != undefined;
	
	for (var i in required_values) {
		var element = eval('form.' + i);

		// all functions take arrays as arguments
		var element_array = new Array();
		element_array[i] = required_values[i];

		var return_val = true;

		// any additional parameters for this element
		var additional_parameter = (additionals_exist && (additional_parameters[i] != undefined)) ? additional_parameters[i] : undefined;

		switch (element.type) {
			case 'select-multiple' :
			case 'select-one' :
				return_val = select_selected(form, element_array, additional_parameter);
				break;
			case 'file' :
			case 'hidden' :
			case 'password' :
			case 'text' :
			case 'textarea' :
				return_val = have_values(form, element_array);
				break;
			case undefined :
			case 'checkbox' :
			case 'radio' :
				if (element.length != undefined) {
					return_val = group_checked(form, element_array);
				}
				else {
					if (element.checked) {
						return_val = true;
					}
					else {
						alert('This checkbox must be selected');
						return_val = true;
					}
				}
				break;
		}

		if (return_val == false) {
			return (false);
		}
	}
	return (true);
}


/**
 * Have Values
 *
 * This function checks the passed in text form fields have 
 * a value assigned to them
 *
 * Example Usage :
 * <script type="text/javascript">
 *	<!--
 *		var required_values = new Array();
 *		
 *		required_values["strider"] = "Aragorn";
 *	//-->
 *	</script>
 *	<form	onsubmit="return have_values(this, required_values)"> 
 *		<input type="text" name="strider" />
 *		<input type="submit" value="test" />
 *	</form>
 *
 * @param	object	form
 * @param	array	required_values - key is form element name, value is friendly name to display in error
 * @access	public
 * @return	bool	have_values
 */
function have_values(form, required_values) {
	for (var i in required_values) {
		if (eval('form.' + i + '.value == \'\'')) {
			alert(required_values[i] + ' must have a value.');
			return (false);
		}
	}
	return (true);
}


/**
 * Checkbox Checked
 *
 * Checks the passed in form has at least one checkbox checked
 * will ignore checkboxes specified in the second argument
 *
 * Example Usage :
 * <script type="text/javascript">
 *	<!--
 *		var ignore_checkboxes = new Array('Bombur');
 *	//-->
 *	</script>
 *	<form	onsubmit="return checkbox_checked(this, ignore_checkboxes)"> 
 *		Bifur <input type="checkbox" name="Bifur" />
 *		Bofur <input type="checkbox" name="Bofur" />
 *		Bombur <input type="checkbox" name="Bombur" />
 *		<input type="submit" value="test" />
 *	</form>
 *
 * @param	object	form
 * @param	array	ignore_checkboxes	these checkboxes will not effect the returned value
 * @access	public
 * @return	bool	checkbox_checked
 */
function checkbox_checked(form, ignore_checkboxes) {
	var check_ignore = ignore_checkboxes != undefined;
	
	for (var i = 0; i < form.elements.length; i++) {
		if (form.elements[i].type == 'checkbox') {
			if (check_ignore && in_array(form.elements[i].name, ignore_checkboxes)) {
				continue;
			}
			if (form.elements[i].checked) {
				return (true);
			}
		}
	}

	var alert_string = 'You must check at least one checkbox.';

	if (check_ignore) {
		alert_string += " (Other than " + ignore_checkboxes.join(", ") + ")";
	}

	alert(alert_string);

	return (false);
}


/**
 * Group Checked
 *
 * Checks the passed in set of radio buttons or checkboxes has at least one option checked
 *
 * Example Usage :
 * <script type="text/javascript">
 *		var required_radios = new Array();
 *		required_radios["dwarves"] = "Bilbo's Companions";
 * </script>
 *		
 *	<form	onsubmit="return group_checked(this, required_radios)"> 
 *			Ori <input type="radio" name="dwarves" value="ori" />
 *			Nori <input type="radio" name="dwarves" value="nori" />
 *			Dori <input type="radio" name="dwarves" value="dori" />
 *			<input type="submit" value="test" />
 *		</form>
 *
 * @param	object	form
 * @param	array	groups - key is form element name, value is friendly name to display in error
 * @access	public
 * @return	bool	group_selected
 */
function group_checked(form, groups) {
	for (var group_element in groups) {
		var group = eval('form.' + group_element);
		var group_ok = false;
		
		for (var i = 0; i < group.length; i++) {
			if (group[i].checked) {
				group_ok = true;
				break;
			}
		}

		if (!group_ok) {
			alert('You must select at least one value for ' + groups[group_element]);

			return (false);
		}
	}

	return (true);
}


/**
 * Select Selected
 *
 * Checks that the selected field in the passed in selects 
 * are not empty strings (or equal to second parameter)
 *
 * Example Usage :
 * <script type="text/javascript">
 *		var required_selects = new Array();
 *		required_selects["maia"] = "Wizards";
 * </script>
 *		
 *	<form	onsubmit="return select_selected(this, required_selects)"> 
 *			<select name="maia" size="4">
 *				<option value="">None</option>
 *				<option value="white">Gandalf</option>
 *				<option value="manycoloured">Saruman</option>
 *				<option value="brown">Radagast</option>
 *			</select>
 *			<input type="submit" value="test" />
 *		</form>
 *
 * @param	object	form
 * @param	array	selects - key is form element name, value is friendly name to display in error
 * @param	string	error_value	if this value is selected, false returned (defaults to '') 
 * @access	public
 * @return	bool	select_selected
 */
function select_selected(form, selects, error_value) {
	if (error_value == undefined) {
		error_value = '';
	}
	
	for (var select_element in selects) {
		var select_object = eval('form.' + select_element);

		if (select_object.selectedIndex < 0) {
			alert('You must select at least one value for ' + selects[select_element]);
			return (false);
		}

		if (select_object[select_object.selectedIndex].value == error_value) {
			alert('You must select a different value for ' + selects[select_element]);
			return (false);
		}
	}

	return (true);
}


/** 
 * In Array
 *
 * Searches for needle in haystack where types
 * can be compared with == operator
 *
 * @param	object	needle	object searched for
 * @param	array	haystack	array to search within
 * @access	public
 * @return	bool	in_array
 */
function in_array(needle, haystack) {
	for (var i in haystack) {
		if (haystack[i] == needle) {
			return (true);
		}
	}
	return (false);
}

