/*
	File: form.js
		Functions for processing and validating form fields.
*/


/*
	Function: sFormRetrieveValue
		Determines the type of the form element and returns its current value.

	Arguments:
		oElement - The form element from which to retrieve the value
		
	Returns:
		empty string if element does not support a useful result.
		otherwise, returns a string with current value of item
		string can be empty if no value is currently set
*/

jQuery.fn.extend({
								 
	formvalue: function(bElementValue, bNoDisabled) {
		var elem = this[0];
		if (elem.disabled && bNoDisabled) {
			return '';
		}
		if (elem) {
			switch (elem.type) {
				case 'checkbox':
					return elem.checked ? String(elem.value) : '';
	
				case 'radio':
					if (bElementValue) {
						return elem.checked ? String(elem.value) : '';
					}
					var oRadioElement = elem.form[elem.name];
					for (var j = 0; j < oRadioElement.length; ++j) {
						if (oRadioElement[j].checked) {
							return String(oRadioElement[j].value);
						}
					}
					return '';
	
				case 'select-one':
				case 'select-multiple':
					if (elem.selectedIndex >= 0) {
						return String(elem.options[elem.selectedIndex].value);
					}
					return '';
					
				default:
					return elem.value || '';
			}
		}
		return '';
	},
	
	getFields: function() {
		
		var rselectTextarea = /select|textarea/i,
				rinput = /text|hidden|password|search/i;
		
		var oFields = {};
		this.filter(function(){
			return this.name && !this.disabled && (this.checked || rselectTextarea.test(this.nodeName) || rinput.test(this.type));
		})
		.map(function(){
			val = jQuery(this).formvalue();
			val !== null && val !== '' && (oFields[this.name] = val);
		});
		return oFields;
	},

	setFields: function() {
		return this.map(function(){
			return this.elements ? jQuery.makeArray(this.elements) : this;
		})
		.filter(function(){
			return this.name && !this.disabled &&
				(this.checked || rselectTextarea.test(this.nodeName) ||
					rinput.test(this.type));
		})
		.map(function(i, elem){
			var val = jQuery(this).val();

			return val == null ?
				null :
				jQuery.isArray(val) ?
					jQuery.map( val, function(val, i){
						return {name: elem.name, value: val};
					}) :
					{name: elem.name, value: val};
		}).get();
	}
});


/*
	Function: sFormCheckValue
		Enforces required fields on a form.

	Arguments:
		sName - the name of the field to check
		sValue - the value to test
		
	Returns:
		null if no error, otherwise a string containing the error message.
*/
function sFormCheckValue(sName, sValue) {
	
	var sResult = '';
	if (sName != null && sName.charAt(0) == '*') { // leading * in name indicates required field
		var sName = sName.substring(1); // trim leading * from name
		if (sName.toLowerCase().indexOf('email') != -1) { // do extended email checking
			if (sValue == '') {
				sResult += 'Please enter an email address for '+sName+'\n\n';
			}
			else {
				var rWhitespace = /\s/;
				var rEmail = /^[^\(\)\[\]\.\\@, ;:]+(\.[^\(\)\[\]\.\\@, ;:]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
				if (rWhitespace.test(sValue)) {
					sResult += 'Email addresses cannot contain spaces\n\n';
				}
				if (sValue.indexOf('@') == -1) {
					sResult += 'Email addresses must contain an @ symbol\n\n';
				}
				if (!rEmail.test(sValue)) {
					sResult += 'There appears to be a mistake in the\nemail address you have entered.\nPlease check the address and try again.\n\n'; 
				}
			}
		}
		else if (sValue == '') {
			sResult += 'Please enter a value for '+sName+'\n\n';
		}
	}
	return sResult;
}

/*
	Function: bValidateForm
		Checks the form for fields marked as required and enforces the required value(s) before submitting. Required
		fields are those indicated by an asterisk at the start of their name.

	Arguments:
		oForm - the DOM form object to validate.
		
	Returns:
		True if the form validates, otherwise an alert box is displayed with an error message, and the return value is false.
*/
function bValidateForm(oForm) {
	var sResult = '';
	var oFirstElement = null;
	for (var i = 0; i < oForm.elements.length; ++i) {
		var oElement = oForm.elements[i];
		var sElementName = oElement.name;
		var sElementValue = $(oElement).formvalue();
		if (sElementName != null && sElementValue != null) {
			// check value, append any error messages returned
			sResult += sFormCheckValue(sElementName, sElementValue);
			// if non-editable form item, and value starts with *, make that field mandatory
			if (sElementValue.charAt(0) == '*' && (oElement.type == 'radio' || oElement.type == 'checkbox')) {
				var oTemp = oElement.form[sElementValue.substring(1)];
				if (oTemp != null) {
					sResult += sFormCheckValue(sElementValue, $(oTemp).formvalue());
				}
			}
			// if error save element for later focus
			if (oFirstElement == null && sResult != '') {
				oFirstElement = oElement;
			}
		}
	}
	if (sResult != '') {
		alert(sResult);
		if (oFirstElement != null && oFirstElement.focus != null) {
			oFirstElement.focus();
		}
		return false;
	}
	return true;
}

/*
	Function: oAccumulateForm
		Reads and concatenates the field values in the form

	Arguments:
		oForm - the DOM form object to accumulate
		
	Returns:
		An object with the accumulated values
*/
function oAccumulateForm(oForm, oFormValues) {
	oFormValues = oFormValues || {};
	for (var i = 0; i < oForm.elements.length; ++i) {
		// read single values for collections, and do not read disabled fields
		var oValue = $(oForm.elements[i]).formvalue(false, true);
		if (oValue) {
			oFormValues[oForm.elements[i].name] = oValue;
		}
	}
	return oFormValues;
}

function oAccumulateForms(oFormValues) {
	oFormValues = oFormValues || {};
	$('form').each(function() {
		oAccumulateForm(this, oFormValues);
	});
	return oFormValues;
}

/*
	Function: sAccumulateForms
		Reads and concatenates the field values of all forms on the page

	Arguments:
		none
		
	Returns:
		A string of the accumulated values, in URL format.
*/

function sAccumulateForms() {
	var oFormValues = oAccumulateForms();
	var asResult = [''];
	for (var x in oFormValues) {
		if (oFormValues.hasOwnProperty(x) && oFormValues[x]) {
			asResult[asResult.length] = encodeURIComponent(x) + '=' + encodeURIComponent(oFormValues[x]);
		}
	}
	return asResult.join('&');
}

/*
	Function: SetSelect
		Sets the currently selected entry of a select list.

	Arguments:
		oSelect - the DOM select object to set the value of
		sValue - the value to find in the list and set as currently selected
		
	Returns:
		nothing
		
	Notes:
		The function fails silently if the value is not found in the list of values held by the select object.
		
	See Also:
		<SetRadio> sets the value of a radio button list
*/
function SetSelect(oSelect, sValue) {
	for (var i = 0; i < oSelect.length; ++i) {
		if (oSelect.options[i].value == sValue) {
			oSelect.selectedIndex = i;
			return;		}
	}
}

/*
	Function: SetRadio
		Sets the currently selected entry of a radio button list.

	Arguments:
		oRadio - the DOM radio button collection to set the value of
		oValue - the value assigned to the required radio button
		
	Returns:
		nothing
		
	See Also:
		<SetSelect> sets the value of a select list
*/
function SetRadio(oRadio, oValue) {
	for (var i = 0; i < oRadio.length; ++i) {
		oRadio[i].checked = (oRadio[i].value == oValue);
	}
}

