/** ---------------------------------------------------------------------
 Javascript form validation function.
 
 Provide validation function to check for required fields, to check ranges,
 email address validity, phone numbers and ages.
 
 These validation function will return true if called from a browser that
 does not support Javascript, and validation will instead have to happen 
 on the server.
 
 (c) 2004 Sarah Henderson, Purple Starfish Web Development
------------------------------------------------------------------------*/

var proceed = 2;

var nbsp = 160;    	// non-breaking space character
var textNode = 3; 	// DOM text nodetype
var emptyString = /^\s*$/

/** ---------------------------------------------------------------------
 Trim leading/trailing whitespace off string
------------------------------------------------------------------------*/

function trim(s) {
  return s.replace(/^\s+|\s+$/g, '')
};

/** ---------------------------------------------------------------------
 Display warning/error message in HTML element
 commonCheck function must have previously been called
------------------------------------------------------------------------*/

function showMessage(messageElementID,    	// ID of element to display message in
             messageType, 					// class to give element ("warning" or "error")
             message) 						// string to display
{
  // setting an empty string can give problems if later set to a 
  // non-empty string, so ensure a space present. (For Mozilla and Opera one could 
  // simply use a space, but IE demands something more, like a non-breaking space.)
	var displayMessage;
	var messageElement = document.getElementById(messageElementID);
		
	if (emptyString.test(message)) {
		displayMessage = String.fromCharCode(nbsp);    
	} else {
		displayMessage = message;
	}

	messageElement.firstChild.nodeValue = displayMessage;  
	messageElement.className = messageType;
};

/** ---------------------------------------------------------------------
 Common code for all validation functions.
 1. Check for browsers that don't support Javascript
 2. Checks for required fields
 Returns true (validation passed), false (validation failed) 
 	or proceed (don't know yet)
------------------------------------------------------------------------*/

function commonCheck    (validationElement,   	// element to be validated
                         messageElementID,   	// ID of element to receive info/error message
                         required)   			// true if required
{

	// check if client side javascript is possible.  If not, will rely on server side checks only
	if (!document.getElementById) return true;  // not available on this browser - leave validation to the server
	var messageElement = document.getElementById(messageElementID);
	if (!messageElement.firstChild) return true;  // not available on this browser 
	if (messageElement.firstChild.nodeType != textNode) return true;  // messageElement is wrong type of node  
	
	if (emptyString.test(validationElement.value)) {
		if (required) {
			showMessage (messageElementID, "error", "Required");  
			validationElement.focus();
			return false;
		} else {
			showMessage (messageElementID, "warning", "");   // OK
			return true;  
		}
	}
	return proceed;
}

/** ---------------------------------------------------------------------
 Validate that something has been entered.  Returns true if there is 
 content, and false if there is not.
------------------------------------------------------------------------*/

function validateRequired(validationElement,   // element to be validated
                          messageElementID )  // id of element to receive info/error message
{
	var status = commonCheck (validationElement, messageElementID, true);
	if (status != proceed) return status;
	
	showMessage (messageElementID, "warning", "");  
	return true;
};

/** ---------------------------------------------------------------------
 Validate that a checkbox has been checked
------------------------------------------------------------------------*/

function validateCheckbox(validationElement,   // element to be validated
                         messageElementID )  // id of element to receive info/error message
{

	var status = commonCheck (validationElement, messageElementID, true);
	if (status != proceed) return status;
	
	var checked = validationElement.checked;
	if (!checked) {

		showMessage (messageElementID, "error", "You must check the box");
		validationElement.focus();
		return false;
	}
	
	showMessage (messageElementID, "warning", "");
	return true;
};

/** ---------------------------------------------------------------------
 Validate that a selection has been made from a group of radio buttons
------------------------------------------------------------------------*/

function validateRadio  (validationElement,   // element to be validated
                         messageElementID )  // id of element to receive info/error message
{
	var status = commonCheck (validationElement, messageElementID, true);
	if (status != proceed) return status;
	
	var selectionMade = false; 
	
	for (i=0; i < validationElement.length; i++) {
		if (validationElement[i].checked) {
			selectionMade = true;  
			break;
		}
	}
	
	if (!selectionMade) {
		showMessage (messageElementID, "error", "You must make a selection");
		return false;
	}
	
	showMessage (messageElementID, "warning", "");
	return true;
};

/** ---------------------------------------------------------------------
 Validate an e-mail address
------------------------------------------------------------------------*/

function validateEmail  (validationElement,   // element to be validated
                         messageElementID,   // id of element to receive info/error message
                         required)   // true if required
{
	var status = commonCheck (validationElement, messageElementID, required);
	if (status != proceed) return status;
	
	var emailAddress = trim(validationElement.value);  // value of field with whitespace trimmed off
	var emailExpression = /^[^@]+@[^@.]+\.[^@]*\w\w$/
	if (!emailExpression.test(emailAddress)) {
		showMessage (messageElementID, "error", "This email address is not valid");
		validationElement.focus();
		return false;
	}
	
	emailExpression = /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/
	if (!emailExpression.test(emailAddress)) {
		showMessage (messageElementID, "warning", "Unusual e-mail address - double check if correct");
	} else {
		showMessage (messageElementID, "warning", "");
	}
	return true;
};


/** ---------------------------------------------------------------------
 Validates a telephone number.  Allows only numbers, spaces, hyphens, brackets
 and a + sign.  Disallows numbers less than 7 digits or more than 15 digits.
 Warns if the number is more than 12 digits
------------------------------------------------------------------------*/

function validatePhone  (validationElement,   // element to be validated
	                         messageElementID,   // id of element to receive info/error message
	                         required)   // true if required
{
	var status = commonCheck (validationElement, messageElementID, required);
	if (status != proceed) return status;
	
	var phoneNumber = trim(validationElement.value);  // value of field with whitespace trimmed off
	var phoneExpression = /^\+?[0-9 ()-]+[0-9]$/
	
	if (!phoneExpression.test(phoneNumber)) {
		showMessage (messageElementID, "error", "Characters permitted are digits, space, (), - and +");
		validationElement.focus();
		return false;
	}
	
	var digits = 0;
	for (var i = 0; i < phoneNumber.length; i++) {
		if (phoneNumber.charAt(i)>='0' && phoneNumber.charAt(i)<='9') digits++;
	}
	
	if (digits < 7) {
		showMessage (messageElementID, "error", digits + " digits - too short");
		validationElement.focus();
		return false;
	}
	
	if (digits > 15) {
		showMessage (messageElementID, "error", digits + " digits - too long");
		validationElement.focus();
		return false;
	}
	
	if (digits > 12) {
		showMessage (messageElementID, "warning", digits + " digits - check if correct");
		return true;
	} 
	
	showMessage (messageElementID, "warning", "");
	return true;
};

/** ---------------------------------------------------------------------
 Validate a person's age.  Must be a valid number between 0 and 150
 Warns if the person is older than 100, or younger than 10
------------------------------------------------------------------------*/

function validateAge    (validationElement,   // element to be validated
                         messageElementID,   // id of element to receive info/error message
                         required)   // true if required
{
	var status = commonCheck (validationElement, messageElementID, required);
	if (status != proceed) return status;
	
	var age = trim(validationElement.value);
	var ageExpression = /^[0-9]{1,3}$/
	
	if (!ageExpression.test(age)) {
		showMessage (messageElementID, "error", "Must be a number");
		validationElement.focus();
		return false;
	}
	
	if (age >= 150) {
		showMessage (messageElementID, "error", "Not a valid age");
		validationElement.focus();
		return false;
	}
	
	if (age < 0) {
		showMessage (messageElementID, "error", "Not a valid age");
		validationElement.focus();
		return false;
	}
	
	if (age > 110) {
		showMessage (messageElementID, "warning", "Older than 100: check if correct");
		return true;
	}
	
	if (age < 10) {
		showMessage (messageElementID, "warning", "Younger than 10: check if correct");
		return true;
	}
	
	showMessage (messageElementID, "warning", "");
	return true;
};

/** ---------------------------------------------------------------------
 Validate that a number is within a given range.  Must be a valid number.
 WARNING NOT TESTED WARNING NOT TESTED WARNING NOT TESTED WARNING NOT TESTED
------------------------------------------------------------------------*/

function validateRange  (validationElement,   // element to be validated
                         messageElementID,   // id of element to receive info/error message
                         maxValue,   // value must be less than or equal to this number
                         minValue,   // value must be greater than or equal to this number                                                  
                         required)   // true if required
{
	var status = commonCheck (validationElement, messageElementID, required);
	if (status != proceed) return status;
	
	var number = trim(validationElement.value);
	var numberExpression = /^[0-9]{1,3}$/
	
	if (!numberExpression.test(number)) {
		showMessage (messageElementID, "error", "Not a valid number");
		validationElement.focus();
		return false;
	}
	
	if (number > maxValue) {
		showMessage (messageElementID, "error", "Value cannot be greater than " + number);
		validationElement.focus();
		return false;
	}
	
	if (number < minValue) {
		showMessage (messageElementID, "error", "Value cannot be less than " + number);
		validationElement.focus();
		return false;
	}
	
	showMessage (messageElementID, "warning", "");
	return true;
};
