/*
 * form validation object
 *
 * usage:
 *
 * put the following code after the form element
 *
 * checkForm = new validateForm();
 * checkForm.setup (
 *	{
 * 		formElement:	'id of form element',
 *		messageType:	'alert',
 * 		inputElements: {
 * 			'element name':	{
 * 				'type':		'validation type',
 * 				'name':		'display name for error alert'
 * 			},
 * 			'element name':	{
 * 				'type':		'validation type',
 * 				'name':		'display name for error alert'
 * 			}
 * 	}
 * );
 *
 *
 * messageType		string		type of message to display (currently alert or highlight)
 *
 */
validateForm = function(messageType) {

	this.formElement = false;
	this.inputElements;		//	array of elements to validate. name, validation type and form display name
	validateForm.messageType = 'alert';
}

/*
 * setup the form elements and validation types
 *
 * params:		object
 * params.formElement		id of form to validate
 * params.messageType		type or error message to display(optinal)
 * params.inputElements		form elements to check 
 * 
 */
validateForm.prototype.setup = function(params) {

	//	set the form element
	if (typeof(params['formElement']) == "string") {
		this.setFormElement(document.getElementById(params['formElement']));
		if (validateForm.formElement) {
			this.onSubmit(validateForm.formElement);
		}
	}
	
	//	set the message type
	if (typeof(params['messageType']) == "string") {
		this.setMessageType(params['messageType']);
	}
	
	//	set the input elements
	validateForm.inputElements = params['inputElements'];

}

/*
 * set the form
 */
validateForm.prototype.setFormElement = function(formElement) {

	validateForm.formElement = formElement;
}

/*
 * set the message type
 */
validateForm.prototype.setMessageType = function(messageType) {

	if (typeof(messageType) != 'undefined') {
		validateForm.messageType = messageType;
	}
}

/*
 * set the onsubmit of the form
 */
validateForm.prototype.onSubmit = function(formElement) {
	validateForm.formElement.onsubmit = this.validate;
}

/*
 * add an element to the form checker
 *
 * elementName		string		name of the input element
 * type				string		validation type
 * name				string		display name for the input field (to display in the error)
 */
validateForm.prototype.addElement = function(elementName, type, name) {

	validateForm.inputElements.elementName = {
		'type':		type,
		'name':		name
	};

}
/*
 * validate the form
 * if there are validation errors, display an alert, focus on the first error and return false
 */
validateForm.prototype.validate = function() {

	var returnValue = true;
	var error, fieldName, element, i, i2, radioElement;
	var errorArray = new Object();

	//	do the validation
	if (validateForm.formElement) {
		for (i in validateForm.inputElements) {
			if (typeof(validateForm.formElement[i]) != 'undefined') {
				error = validateForm.element(validateForm.formElement[i], validateForm.inputElements[i].type, validateForm.inputElements[i].name);
				if (error) {
					errorArray[i] = error;
				}
			}
		}
	}
	
	//	if there are errors, display them
	switch (validateForm.messageType) {
		case 'alert':
			returnValue = validateForm.errorAlert(errorArray);
			break;
		case 'highlight':
			returnValue = validateForm.errorHighlight(errorArray, validateForm.formElement['leftNavContact'].value);

			break;
	}
	
	return returnValue;

}

/* 
 * alert error
 */
validateForm.prototype.errorAlert = function(errorArray) {

	var returnValue = true;
	var errorStr = '';
	var firstElement = false;
	
	for (i in errorArray) {
		if (firstElement == false) {
			firstElement = i;
		}
		errorStr += errorArray[i] + '\n';
	}
	if (errorStr !== '') {
		errorStr = 'There are errors with the form: \n\n' + errorStr;
		alert(errorStr);
		validateForm.formElement[firstElement].focus();
		returnValue = false;
	}
	
	return returnValue;

}


/*
 * highlight error
 *
 * this will highlight errors in a form
 * the form must be in the std-form format used on the ww website
 * if isNav == 1 then the validation is on the left navigation contact form
 */
validateForm.errorHighlight = function(errorArray, isNav) {

	var returnValue = true;
	var firstElement = false;
	var element, firstChild, formElement, radioElement, i, i2;
	var errorStr = '';
	
	for (i in errorArray) {
		if (firstElement == false) {
			firstElement = i;
			element = validateForm.formElement[i];
			if (typeof(element.type) == 'undefined') {
				element = element[0];
			}
			element = element.parentNode.parentNode.parentNode;
			for (var i2 = 0; i2 < element.childNodes.length; i2++) {
				if (element.childNodes[i2].nodeType == 1) {
					element.childNodes[i2].className = 'no-class';
				}
			}
		}
		//	higlight the errors
		
		formElement = validateForm.formElement[i];
		if (typeof(formElement.type) == 'undefined') {
			formElement = formElement[0];
		}
		
		formElement.parentNode.parentNode.className = 'validate-error';
		errorStr += '<li>' + errorArray[i] + '</li>';
	}
	
	if (firstElement) {
		element = validateForm.formElement[firstElement];
		if (typeof(element.type) == 'undefined') {
			element = element[0];
		}
		element.focus();
		returnValue = false;
		if (isNav == 1)
		{
			errorStr = '<img src="/images/caution.gif" / style=""> Please check the following and try again:<ul style="padding:0px 0px 5px 25px;display:block;font-size:11.5px;">' + errorStr + '</ul>'
		}
		else
		{
			errorStr = '<img src="/images/caution.gif" /> Please check the following and try again:<ul>' + errorStr + '</ul>'
		}	
		//	display the errors
		element = document.getElementById('error-msg-nav');
		if (element)
		{
			element.className =  'validate-error';
			element.innerHTML = errorStr;
			element = document.getElementById('error-msg');
		}
		else
		{
			element = document.getElementById('error-msg');
			if (!element)
			{
				element = document.createElement('tr');
				element.appendChild(document.createElement('td'));
				element.id = 'error-msg';
				element.className =  'validate-error';
				element.firstChild.colSpan= '2';
				element.firstChild.innerHTML = errorStr;
				firstChild = formElement.parentNode.parentNode.parentNode.firstChild;
				formElement.parentNode.parentNode.parentNode.insertBefore(element, firstChild);
			}
			else
			{
				if (element.firstChild.nodeType == 1)
				{
					element.firstChild.innerHTML = errorStr;
				} else {
					element.firstChild.nextSibling.innerHTML = errorStr;
				}
				element.className =  'validate-error';
			}
		}	
	}
	
	return returnValue;
}

/*
 * return the value for a form element (including radio buttons)
 */
validateForm.elementValue = function(element) {
	var value = false;
	if (typeof(element.value) == 'undefined') {
		var radioElement = this.radioValue(element);
		if (radioElement) {
			value = radioElement.value;
		}
	} else {
		value = element.value;
	}
	return value;
}


/*
 * get the selected element for a radio button input group
 * 
 * element		object		html from radio button object
 */
validateForm.radioValue = function(element) {
	var checkedElement = false;
	
	for (i=0; i < element.length; i++){
		if (element[i].checked == true) {
			checkedElement = element[i];
		}
	}
	
	return checkedElement;
}
 
/*
 * validate a form element
 *
 * element:		object		form element
 * type:		string		type of validation
 * fieldName:	string		display name for the field (optional)
 */
validateForm.element = function(element, type, fieldName) {
	
	var returnValue, labels, value;
	
	value = validateForm.elementValue(element);
	
	switch (type) {
		case 'email':
			returnValue = validateForm.email(value);
			break;
		case 'empty':
			returnValue = validateForm.empty(value);
			break;
		case 'name':
			returnValue = validateForm.humanName(value);
			break;
		case 'phoneNumber':
			returnValue = validateForm.phoneNumber(value);
			break;
		case 'address':
			returnValue = validateForm.address(value);
			break;
		case 'suburb':
			returnValue = validateForm.suburb(value);
			break;
		case 'postcode':
			returnValue = validateForm.postcode(value);
			break;
		case 'date':
			returnValue = validateForm.date(value);
			break;
	}
	
	if (returnValue) {
		//	if there is a fieldName, use it
		if (fieldName !== false) {
			if (fieldName !== '') {
				returnValue = fieldName + ' ' + returnValue;
			}
			
		//	else try to get the label for the element
		} else {
			elements = document.getElementsByTagName('label');
			for (var i in elements) {
				if (elements[i].htmlFor == element.name) {
					returnValue = elements[i].innerHTML + ' ' + returnValue;
				}
			}
		}
	}
	return returnValue;
}

/*
 * validate a email address
 * return false if valid, else return error messge
 */
validateForm.email = function(string) {
	
	var checkTLD=1;
	var returnValue = false;

	/* The following is the list of known TLDs that an e-mail address must end with. */
	
	var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;
	
	/* The following pattern is used to check if the entered e-mail address
	fits the user@domain format.  It also is used to separate the username
	from the domain. */
	
	var emailPat=/^(.+)@(.+)$/;
	
	/* The following string represents the pattern for matching all special
	characters.  We don't want to allow special characters in the address. 
	These characters include ( ) < > @ , ; : \ " . [ ] */
	
	var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";
	
	/* The following string represents the range of characters allowed in a 
	username or domainname.  It really states which chars aren't allowed.*/
	
	var validChars="\[^\\s" + specialChars + "\]";
	
	/* The following pattern applies if the "user" is a quoted string (in
	which case, there are no rules about which characters are allowed
	and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
	is a legal e-mail address. */
	
	var quotedUser="(\"[^\"]*\")";
	
	/* The following pattern applies for domains that are IP addresses,
	rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
	e-mail address. NOTE: The square brackets are required. */
	
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;
	
	/* The following string represents an atom (basically a series of non-special characters.) */
	
	var atom=validChars + '+';
	
	/* The following string represents one word in the typical username.
	For example, in john.doe@somewhere.com, john and doe are words.
	Basically, a word is either an atom or quoted string. */
	
	var word="(" + atom + "|" + quotedUser + ")";
	
	// The following pattern describes the structure of the user
	
	var userPat=new RegExp("^" + word + "(\\." + word + ")*$");
	
	/* The following pattern describes the structure of a normal symbolic
	domain, as opposed to ipDomainPat, shown above. */
	
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");
	
	/* Finally, let's start trying to figure out if the supplied address is valid. */
	
	/* Begin with the coarse pattern to simply break up user@domain into
	different pieces that are easy to analyze. */
	
	var matchArray=string.match(emailPat);
	
	if (matchArray==null) {
	/* Too many/few @'s or something; basically, this address doesn't
	even fit the general mould of a valid e-mail address. */
		returnValue = "Email address seems incorrect (check @ and .'s)";
		return returnValue;
	}
	var user=matchArray[1];
	var domain=matchArray[2];
	
	// Start by checking that only basic ASCII characters are in the strings (0-127).
	
	for (i=0; i<user.length; i++) {
		if (user.charCodeAt(i)>127) {
			returnValue = "Ths username contains invalid characters.";
			return returnValue;
		  }
	}
	for (i=0; i<domain.length; i++) {
		if (domain.charCodeAt(i)>127) {
			returnValue ="Ths domain name contains invalid characters.";
			return returnValue;
		}
	}
	
	// See if "user" is valid 
	
	if (user.match(userPat)==null) {
	
	// user is not valid
		returnValue ="The username doesn't seem to be valid.";
		return returnValue;

	}
	
	/* if the e-mail address is at an IP address (as opposed to a symbolic
	host name) make sure the IP address is valid. */
	
	var IPArray=domain.match(ipDomainPat);
		if (IPArray!=null) {
		// this is an IP address
			for (var i=1;i<=4;i++) {
				if (IPArray[i]>255) {
					alert("Destination IP address is invalid!");
					return returnValue;
			   }
			}
		return returnValue;
	}
	
	// Domain is symbolic name.  Check if it's valid.
	 
	var atomPat=new RegExp("^" + atom + "$");
	var domArr=domain.split(".");
	var len=domArr.length;
	for (i=0;i<len;i++) {
		if (domArr[i].search(atomPat)==-1) {
			returnValue = "The domain name does not seem to be valid.";
			return returnValue;
		}
	}
	
	/* domain name seems valid, but now make sure that it ends in a
	known top-level domain (like com, edu, gov) or a two-letter word,
	representing country (uk, nl), and that there's a hostname preceding 
	the domain or country. */
	if (checkTLD && domArr[domArr.length-1].length!=2 && 
	domArr[domArr.length-1].search(knownDomsPat)==-1) {
		returnValue ="The address must end in a well-known domain or two letter " + "country.";
		return returnValue;
	}
	
	// Make sure there's a host name preceding the domain.
	if (len<2) {
		returnValue ="This address is missing a hostname!";
		return returnValue;
	}
	
	return returnValue;
}

/*
 * check that something is entered
 * return false if there is a value, else return error messge
 */
validateForm.empty = function(string) {

	var returnValue = false;
	if (string == '' || typeof(string) == 'undefined'){
		returnValue = 'required';
	}
	
	return returnValue;
}

/*
 * check that a string contains valid characters for a name and is 2 digits long
 * return false if there is a value, else return error messge
 */
validateForm.humanName = function(string) {

	var returnValue = false;
	if (typeof(string) == 'undefined') {
		returnValue = 'required';
	} else if(string.length < 2){
		returnValue = 'must be at least two characters in length';
	} else if(/^[a-zA-Z \-']+$/.test(string) != true) {
		returnValue = 'contains invalid characters';
	}
	
	return returnValue;
}

/*
 * check that a string contains a valid phone number
 * return false if valid, else return error messge
 */
validateForm.phoneNumber = function(string) {

	var returnValue = false;
	if (typeof(string) == 'undefined') {
		returnValue = 'required';
	} else if(string.length < 6){
		returnValue = 'must be at least six digits';
	} else if(/^[0-9 ]+$/.test(string) != true) {
		returnValue = 'contains invalid characters. It should contain only numbers.';
	}
	
	return returnValue;
}

/*
 * check that a string contains a valid postcode
 * return false if valid, else return error messge
 */
validateForm.postcode = function(string) {

	var returnValue = false;
	if (typeof(string) == 'undefined') {
		returnValue = 'required';
	} else if(string.length < 3){
		returnValue = 'must be at least three characters';
	} else if(/^[0-9a-zA-Z \-]+$/.test(string) != true) {
		returnValue = 'contains invalid characters';
	}
	
	return returnValue;
}

/*
 * check that a string contains a valid address
 * return false if valid, else return error messge
 */
validateForm.address = function(string) {

	var returnValue = false;
	if (typeof(string) == 'undefined') {
		returnValue = 'required';
	} else if(string.length < 3){
		returnValue = 'must be at least three characters';
	} else if(/^[0-9a-zA-Z \-'#./]+$/.test(string) != true) {
		returnValue = 'contains invalid characters';
	}
	
	return returnValue;
}

/*
 * check that a string contains a valid suburb
 * return false if valid, else return error messge
 */
validateForm.suburb = function(string) {

	var returnValue = false;
	if (typeof(string) == 'undefined') {
		returnValue = 'required';
	} else if(string.length < 3){
		returnValue = 'must be at least three characters';
	} else if(/^[0-9a-zA-Z \-'#]+$/.test(string) != true) {
		returnValue = 'contains invalid characters';
	}
	
	return returnValue;
}

/*
 * validate a dd/mm/yyyy date
 * return false if valid, else return error message
 */
validateForm.date = function(dateString) {

	var day = dateString.substring(0,1);
	var month = dateString.substring(3,4);
	var year = dateString.substring(6,9);
	var testDate = new Date(year,month,day);
	var returnValue;
	
	if ((day==testDate.getDate()) && (month==testDate.getMonth()) && (year==testDate.getFullYear())) {
		returnValue = false;
	} else {
		returnValue = 'Invalid Date, dd/mm/yyyy required';
	}
	
	return returnValue;
}
