	/**
	* variable to hold the html node listing all Error Messages that will be displayed to the user
	*/
	var ErrorMsgNode;
	
	/**
	* test whether the form has been invalidated at least once
	*/
	var dirty = false;
	
	/**
	* Class ErrorNodeList is a linked list to store html nodes (and respective error messages) which caused failure of input validation. 
	* It provides basic functionality of linked list and functionality specific to handling input error causing html nodes. 
	*/
	var ErrorNodeList = {
		
		/**
		* array of html nodes which caused failure of input validation. 
		* Each element is itself an array that holds 
		* - input error causing html node, 
		* - error message to flag out input error to the user
		* Note that each element being an array can be extended to hold other potentially useful structures 
		* in input validation handling, for example parent tag, lable that goes with the input field 
		* that caused validation failures etc
		*/
		ErrorNodes:null,
		
		/**
		*  pointer to the last element in the linked list.
		*/
		last:-1,
		
		/**
		*  pointer to the current element in the linked list to be read out. 
		*/
		iterator:-1,
		
		/**
		* initialises linked list
		* called from procedure validate()
		*/
		init:function() {
			ErrorNodeList.ErrorNodes = new Array();
		},
		
		/**
		* creates a new element and adds it to the linked list.
		* @param: node - an input error causing html node.
		* @param: message - helpful message to the user to flag out input error
		* called from procedure validate()
		*/
		add:function(node, message) {
			ErrorNodeList.ErrorNodes[++ErrorNodeList.last] = new Array(node, message);
		},
		
		/**
		* returns next html input error causing html node that we stored in the linked list
		*/
		nextNode:function() {
			//TODO: better array bounds checking
			if(ErrorNodeList.iterator == -1 || ErrorNodeList.iterator > ErrorNodeList.last) return null;
			return ErrorNodeList.ErrorNodes[++ErrorNodeList.iterator][0];
		},
		
		nextErrorMessage:function () {
			if(ErrorNodeList.iterator == -1 || ErrorNodeList.iterator > ErrorNodeList.last) return null;
			return ErrorNodeList.ErrorNodes[++ErrorNodeList.iterator][1];
		},
		
		/**
		* resets linked list to nothing
		* called form cleanup procedure
		*/
		reset:function() {
			ErrorNodeList.last = -1;
			ErrorNodeList.iterator = -1;
			ErrorNodeList.ErrorNodes = null;
		},
		
		/**
		*  creates and returns html block to output summary of error messages to the user
		*@ param: div_id that is not used but is currently a place holder for the future improvements 
		*  to the code without changing the function signature.
		* 
		*/
		//TODO: needs refactoring to make use of the linked list functionality, e.g. nextNode, nextMessage
		createErrorSummary:function(div_id){
			
			var ErrorMsgDiv = document.createElement('div');
			var ErrorHeading = document.createElement('p');
			ErrorHeading.className = "errorText";
			var textNode = document.createTextNode("One or more required fields is invalid or incomplete.");
			var textNode2 = document.createTextNode("Please enter / amend your answer.");
			var br = document.createElement("br"); 
			ErrorHeading.appendChild(textNode);
			ErrorHeading.appendChild(br);
			ErrorHeading.appendChild(textNode2);
			ErrorMsgDiv.appendChild(ErrorHeading);
			/* This has been disabled here as it is not wanted
			var ErrorListTag = document.createElement('ul');
			ErrorMsgDiv.appendChild(ErrorListTag);
			for(var i=0; i <= ErrorNodeList.last; i++) {
				
				var ErrorListItem = document.createElement('li');
				var errorText = document.createTextNode(ErrorNodeList.ErrorNodes[i][1]);
				ErrorListTag.appendChild(ErrorListItem);
				ErrorListItem.appendChild(errorText);
			}*/
			return ErrorMsgDiv;

		},
		
		/**
		*  updates the style of the input field that caused validation failure
		* @ param: styleType a constant telling wich style to use. 
		* This is to create indirection in order to keep the function open to future extentions
		* not used
		*/
		setErrorNodeStyle:function(styleType) {
			for(var i=0; i <= ErrorNodeList.last; i++) {
				switch(styleType) {
					case "RED": (ErrorNodeList.ErrorNodes[i][0]).style.backgroundColor = "red";
					break;
					case "WHITE": (ErrorNodeList.ErrorNodes[i][0]).style.backgroundColor = "white";
					break;
					default: (ErrorNodeList.ErrorNodes[i][0]).style.backgroundColor = "white";
				
				}
			}

		},
	/**
	*  updates the style of the lable for the html form field that caused validation failure
	* @ param: styleType a constant telling wich style to use. 
	* This is to create indirection in order to keep the function open to future extentions
	* called from procedures validate() and cleanup()
	* 
	*/
	setLableStyle: function (styleType) {
		var labels = document.getElementsByTagName("label");
		for (var i=0; i<labels.length; i++) {
			for(var j=0; j <= ErrorNodeList.last; j++) {
			var forAtt = labels[i].getAttribute("htmlFor"); //ie
			if (forAtt ==null) { forAtt = labels[i].getAttribute("for");} //firefox
			if( forAtt == (ErrorNodeList.ErrorNodes[j][0]).getAttribute("name")) {
					switch(styleType) {
							case "RED": labels[i].className = "errorText";
							break;
							case "BLACK": labels[i].className = "";
							break;
							default: labels[i].className = "";
					} 

					/*switch(styleType) {
							case "RED": labels[i].style.color = "red";
							break;
							case "BLACK": labels[i].style.color = "black";
							break;
							default: labels[i].style.color = "white";
						} */
					
					}
				}
			}
		}
	}

//-------------------------------------------------------------------------------------------------------------
	/**
	* validates any blank input, e.g. from text field or dropdown list
	* @param: inputValue - an input string to validate
	* called from procedure validate()
	*/
	function blankInput(inputValue) {
		var ret;
		(inputValue =="" || inputValue == "Please Select") ? ret= false : ret = true;
		return ret;
	}
	
	/**
	* validates email input field against regular expression representing an e-mail pattern 
	* as well as blank input and very long email - over 50 characters
	* @ param: emailValue - an input email string to validate
	* called from procedure validate()
	*/
	function validateEmail(emailValue) { 
		regexpEmail =  /^\w+([\.\-']?\w+)*@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
		if((emailValue.length >50) || (emailValue.match(regexpEmail) == null)) {
			return false;
		}	
		return true;
	}

	/**
	* validates a telephone number regular expression where 
	* numbers, spaces allowed, ( ) , + and - symbols allowed, maximum = 20 characters
	* as well as blank input
	* @ param: preferredContactNumberValue - a telephone number string to validate
	* called from procedure validate()
	*/
	function validatePreferedContactNumber(preferredContactNumberValue) { 
		regexPreferedContactNumber = /^[\d\-\+\(\) ]+$/;		
		if((preferredContactNumberValue.length > 20) || (preferredContactNumberValue.match(regexPreferedContactNumber) == null)) {
			return false;
		}
		return true;
	}

	function validateNonNumberField(evalText) { 
		regexNonNumber = /[^\sa-zA-Z\'\-]+/;		
		if(evalText.match(regexNonNumber) == null) {
			return false;
		}
		return true;
	}

	/**
	* cleans up previous validation markup in the html form before the next validation is performed
	* called from procedure validate()
	*/
	function cleanup() {
		var parentOfErrorMsgNode = document.getElementById("errorContainer");
		
		/* This may throw an error when the back button is pressed */
		try {
			parentOfErrorMsgNode.removeChild(ErrorMsgNode);
		} catch (error) {}	

		ErrorNodeList.setLableStyle("BLACK");
		ErrorNodeList.reset();
	}
	
	/**
	* the main function that contralls form validation
	* called from onsubmit attribute of the form
	* returns false if validation failed
	*/
	function validate() {
		var allValid = true; //result of all inputs validation
		if(dirty) cleanup(); //cleanup html created by previous validation
		
		/**
		* create object to store input nodes that failed validation
		*/
		ErrorNodeList.init();
		
		/*
		* validate each input field
		*/
		var title = document.getElementsByName("title");
		var titleValue = title[0].options[title[0].selectedIndex].text;
		if(!blankInput(titleValue)) {
			ErrorNodeList.add(title[0], "Please select a Title from the drop down list"); 
			allValid = false;
		}
				
		var forename = document.getElementsByName("forename");
		if((!blankInput(forename[0].value)) || (forename[0].value.length > 50) || validateNonNumberField(forename[0].value)) {
			ErrorNodeList.add(forename[0], "The Forename field is invalid. Please enter your Forename");
			allValid = false;
		}
				
		var surname = document.getElementsByName("surname");
		if((!blankInput(surname[0].value)) || (surname[0].value.length > 50) || validateNonNumberField(surname[0].value)) {
			ErrorNodeList.add(surname[0], "The Surname field is invalid. Please enter your Surname");
			allValid = false;
		}
				
		var email = document.getElementsByName("email");
		if(!validateEmail(email[0].value)) {
			ErrorNodeList.add(email[0], "The Email address is invalid. Please enter your email in the correct format");
			allValid = false;
		}
				
		var preferredContactNumber = document.getElementsByName("preferredContactNumber");
		if(!validatePreferedContactNumber(preferredContactNumber[0].value)) {
			ErrorNodeList.add(preferredContactNumber[0], "Please enter your contact number");
			allValid = false;	
		}
					
		var preferredContactTime = document.getElementsByName("preferredContactTime");
		var preferredContactTimeValue = preferredContactTime[0].options[preferredContactTime[0].selectedIndex].text;
		if(!blankInput(preferredContactTimeValue)) {
			ErrorNodeList.add(preferredContactTime[0], "Please select a Preferred contact time from the drop down list");	
			allValid = false;	
		}

		var detailsOfEnquiry = document.getElementsByName("detailsOfEnquiry");
		var detailsOfEnquiryValue = detailsOfEnquiry[0].value;
		if(detailsOfEnquiryValue.length > 500) {
			ErrorNodeList.add(detailsOfEnquiry[0], "Please select a Preferred contact time from the drop down list");	
			allValid = false;	
		}
		
		/**
		* makes changes to the html form if input validation failed to flag out input errors
		*/			
		if(!allValid) {

			/**
			* html node to which the tag containing error messages will be attached as a child
			*/
			var parentOfErrorMsgNode = document.getElementById("errorContainer");

			/**
			* html element containing error messages
			*/
			ErrorMsgNode = ErrorNodeList.createErrorSummary("errorSummary");
			parentOfErrorMsgNode.appendChild(ErrorMsgNode);
			ErrorNodeList.setLableStyle("RED");
			/*
			* indicates that the style and content of the html form was alteres 
			* since the last input validation failure
			*/
			dirty = true;
		}
		
		return allValid;
	}


	var hasBeenSubmitted = false;
	
	function checkSubmitted() {
		
		if(hasBeenSubmitted) {
			alert("The system is currently processing the action you requested. Please wait...");
			return false;
		} else {
			if(validate()) {
				hasBeenSubmitted = true;
				return true;
			}
			return false;
		}
	
	}
