window.onload = initialise;

function initialise()
{
	var objForms = document.getElementsByTagName('form');

	// Attach an event handler for each form
	for (var iCounter=0; iCounter<objForms.length; iCounter++)
		objForms[iCounter].onsubmit= function(){return validateForm(this);}
}


// Event handler for the form
function validateForm(objForm)
{
	var arClass = new Array();
	var arVisited = new Array();
	var iErrors = 0, iCounter;
	var objField = objForm.getElementsByTagName('input');
	var objLabel = objForm.getElementsByTagName('label');
	var objList = document.createElement('ol');
	var strError;

	// Get the id or name of the form, to make a unique
	// fragment identifier
	if (objForm.id)
		var strLinkID = objForm.id + 'ErrorID';
	else
		var strLinkID = objForm.name + 'ErrorID';

	// Iterate through input form controls, looking for validation classes
	for (var iFieldCounter=0; iFieldCounter<objField.length; iFieldCounter++)
	{
		// Checkboxes and radio buttons are grouped by the name attribute
if ((objField[iFieldCounter].type == 'checkbox' || objField[iFieldCounter].type == 'radio') &&
!objField[iFieldCounter].className.match(/optional/i))
		{
			bCheckRequired = true;

			// Check if it's already been validated
			for (iCounter=0; iCounter<arVisited.length; iCounter++)
				if (arVisited[iCounter] == objField[iFieldCounter].name)
					bCheckRequired = false;

			if (bCheckRequired)
			{
				if (!validateChecked(objForm, objField[iFieldCounter].name))
				{
					// Search the label for the error prompt
					for (iCounter=0; iCounter<objLabel.length; iCounter++)
						if (objLabel[iCounter].htmlFor == objField[iFieldCounter].id)
							strError = objLabel[iCounter].firstChild.nodeValue;

					strError = 'Select an option from the group containing "' + strError + '"';
					if (iErrors == 0)
						addError(objList, strError, objField[iFieldCounter].id, strLinkID);
					else
						addError(objList, strError, objField[iFieldCounter].id, '');

					iErrors++;
				}

				arVisited.push(objField[iFieldCounter].name)
			}
		}
		else
		{
			// Get the class for the field, and look for the appropriate class
			arClass = objField[iFieldCounter].className.split(' ');
			for (var iClassCounter=0; iClassCounter<arClass.length; iClassCounter++)
			{
				switch (arClass[iClassCounter])
				{
					case 'string':
						if (!isString(objField[iFieldCounter].value, arClass))
						{
							if (iErrors == 0)
								logError(objField[iFieldCounter], objLabel, objList, strLinkID);
							else
								logError(objField[iFieldCounter], objLabel, objList, '');
							iErrors++;
						}
						break;
					case 'number':
						if (!isNumber(objField[iFieldCounter].value, arClass))
						{
							if (iErrors == 0)
								logError(objField[iFieldCounter], objLabel, objList, strLinkID);
							else
								logError(objField[iFieldCounter], objLabel, objList, '');
							iErrors++;
						}
						break;
					case 'email' :
						if (!isEmail(objField[iFieldCounter].value, arClass))
						{
							if (iErrors == 0)
								logError(objField[iFieldCounter], objLabel, objList, strLinkID);
							else
								logError(objField[iFieldCounter], objLabel, objList, '');
							iErrors++;
						}
						break;
				}
			}
		}
	}

	// Validate select options
	var objField = objForm.getElementsByTagName('select');
	for (iFieldCounter=0; iFieldCounter<objField.length; iFieldCounter++)
	{

		if (objField[iFieldCounter].selectedIndex == 0 &&
!objField[iFieldCounter].className.match(/optional/i))
		{
			// Search the label for the error prompt
			for (iCounter=0; iCounter<objLabel.length; iCounter++)
				if (objLabel[iCounter].htmlFor == objField[iFieldCounter].id)
					strError = objLabel[iCounter].firstChild.nodeValue;

			if (iErrors == 0)
				addError(objList, strError, objField[iFieldCounter].id, strLinkID);
			else
				addError(objList, strError, objField[iFieldCounter].id, '');

			iErrors++;
		}
	}

	if (iErrors > 0)
	{
		// If not valid, display error messages
		var objError = objForm.getElementsByTagName('div');
		
		// Look for existing errors
		for (var iCounter=0; iCounter<objError.length; iCounter++)
			if (objError[iCounter].className == 'validationerrors')
				var objExisting = objError[iCounter];

		var objNew = document.createElement('div');
		var objTitle = document.createElement('h2');
		var objParagraph = document.createElement('p');
		var objAnchor = document.createElement('a');

		if (iErrors == 1)
			objAnchor.appendChild(document.createTextNode('1 Error in Submission'));
		else
			objAnchor.appendChild(document.createTextNode(iErrors + ' Errors in Submission'));
		objAnchor.href = '#' + strLinkID;
		objAnchor.className = 'submissionerror';

		objTitle.appendChild(objAnchor);
		objParagraph.appendChild(document.createTextNode('Please review the following'));
		objNew.className = 'validationerrors';

		objNew.appendChild(objTitle);
		objNew.appendChild(objParagraph);
		objNew.appendChild(objList);
		
		// If there were existing error, replace them with the new lot,
		// otherwise add the new errors to the start of the form
		if (objExisting)
			objExisting.parentNode.replaceChild(objNew, objExisting);
		else
		{
			var objPosition = objForm.firstChild;
			objForm.insertBefore(objNew, objPosition);
		}
		
		objAnchor.focus();
		
		// Don't submit the form
		objForm.submitAllowed = false;
		return false;
	}

	// Submit the form
	return true;
}

// Function to add a link in a list item that points to problematic field control
function addError(objList, strError, strID, strErrorID)
{
	var objListItem = document.createElement('li');
	var objAnchor = document.createElement('a');
	
	// Fragment identifier to the form control
	objAnchor.href='#' + strID;

	// Make this the target for the error heading
	if (strErrorID.length > 0)
		objAnchor.id = strErrorID;

	// Use the label prompt for the error message
	objAnchor.appendChild(document.createTextNode(strError));
	// Add keyboard and mouse events to set focus to the form control
	objAnchor.onclick = function(event){return focusFormField(this, event);}
	objAnchor.onkeypress = function(event){return focusFormField(this, event);}
	objListItem.appendChild(objAnchor);
	objList.appendChild(objListItem);
}

function focusFormField(objAnchor, objEvent)
{
	// Allow keyboard navigation over links
	if (objEvent && objEvent.type == 'keypress')
		if (objEvent.keyCode != 13 && objEvent.keyCode != 32)
			return true;

	// set focus to the form control
	var strFormField = objAnchor.href.match(/[^#]\w*$/);
	var objForm = getForm(strFormField);
	objForm[strFormField].focus();
	return false;
}

// Function to return the form element from a given form field name
function getForm(strField)
{
	var objElement = document.getElementById(strField);

	// Find the appropriate form
	do
	{
		objElement = objElement.parentNode;
	} while (!objElement.tagName.match(/form/i) && objElement.parentNode);

	return objElement;
}

// Function to log the error in a list
function logError(objField, objLabel, objList, strErrorID)
{
	// Search the label for the error prompt
	for (var iCounter=0; iCounter<objLabel.length; iCounter++)
		if (objLabel[iCounter].htmlFor == objField.id)
			var strError = objLabel[iCounter].firstChild.nodeValue;

	addError(objList, strError, objField.id, strErrorID);
}

// Validation routines - add as required

function isString(strValue, arClass)
{
	var bValid = (typeof strValue == 'string' && strValue.replace(/^\s*|\s*$/g, '') != '' && isNaN(strValue));

	return checkOptional(bValid, strValue, arClass);
}

function isEmail(strValue, arClass)
{
	var objRE = /^[\w-\.\']{1,}\@([\da-zA-Z-]{1,}\.){1,}[\da-zA-Z-]{2,}$/;
	var bValid = objRE.test(strValue);

	return checkOptional(bValid, strValue, arClass);
}

function isNumber(strValue, arClass)
{
	var bValid = (!isNaN(strValue) && strValue.replace(/^\s*|\s*$/g, '') != '');

	return checkOptional(bValid, strValue, arClass);
}

function checkOptional(bValid, strValue, arClass)
{
	var bOptional = false;

	// Check if optional
	for (var iCounter=0; iCounter<arClass.length; iCounter++)
		if (arClass[iCounter] == 'optional')
			bOptional = true;

	if (bOptional && strValue.replace(/^\s*|\s*$/g, '') == '')
		return true;

	return bValid;
}

function validateChecked(objForm, strName)
{
	var objField = objForm.getElementsByTagName('input');

	for (var iCounter=0; iCounter<objField.length; iCounter++)
		if (objField[iCounter].name == strName && objField[iCounter].checked)
			return true;

	return false;
}







