/**
 * @author Jon TJ
 * FormValidate v2.2
 * For use in conjunction with the CreateForm.php class and CKEditor to validate the required fields of a CMS form
 * 
 * valType: 0 - Not required but still prints the divs to receive error messages
 * valType: 1 - Not Null
 * valType: 2 - Equal to another field
 * valType: 3 - Contains an '@' and '.' for email addresses with characters before the '@' and between the '@' and last '.'
 * valType: 4 - Contains an http:// for web addresses and also a . that isnt directly after the http://
 * valType: 5 - Is not 'Please Select...'
 * valType: 6 - Is an integer
 * valType: 7 - If is NOT NULL, another given field must be NOT NULL also - (FILE UPLOAD FIELDS ONLY)
 * valType: 8 - If is 'Other...' another field must not be NULL and shall appear (DROP DOWN MENUS ONLY)
 * valType: 9 - Checks a ckeditor textarea for a value, must be NOT NULL
 * valType 10 - AJAX validation request
 * 
 * TO DO?:
 * valType: 11 - If is NOT NULL, another given field can be NULL (generally the field that can be NULL will be required otherwise)
 * valType: 12 - Check for file type - if its a .jpg/.jpeg, .gif or .png
 */

var ajaxValidationInProgress = false;	//boolean to determine if an ajax validation is underway, for pausing form submission
var arrayBuiltVal10Check = false;		//when a valType 10 is detected, do not allow the form to be submitted until the array is fully built
var allValidated = false;				//boolean that determines if all fields are validated
var arrayBuilt = false;					//boolean for build state of master array
var cache = new Array();				//initialise the validation requests cache
var dbEntryId;							//when validating type 10 edit forms, holds the database id of the current entry
var errorDiv;							//reference to the div field that will display the error message if needed
var errorDivName;						//name of the div field that will display the error message
var errMsg;								//error message that will be displayed if not validated
var equalField;							//the field that the validating field must be equal to for valType 2
var equalFieldId;						//reference to the string name of the equal to field
var equalFieldValue;					//reference to the value of the equal to field
var integerList = "0123456789";			//list that holds values accepted for valType 6
var fieldName;							//reference to the string name of the input field for the initial check on array build
var fieldType;							//type of field being validated
var fieldValue;							//reference to the value of the input field for the initial check on array build
var form;								//reference to the form itself
var formAction;							//action of the form once all fields are validated
var formId;								//id of the form
var inputFieldId;						//reference to the string name of the input field
var inputField;							//reference to the input field itself
var inputFieldValue;					//reference to the value of the input field
var numRequiredFields;					//number of fields that are required for validation
var serverAddress;						//varaible to hold the location of the server script to perform AJAX validation
var showErrors = false;					//when set to true, display detailed error messages when creating the XMLHttpRequest object
var submitAfterAjax = false;			//switch to cause javascript form submission if still validating an ajax field on click submit
var validateArray = new Array();		//array holding all fields that are validated, populated as they are validated
var validateArrayLength;				//number of items in the validate array
var valType;							//validation type, see above
var xmlHttp="uninitialiased";			//holds an instance of XMLHttpRequest object if valType 10 is detected

//////////////////////////////////////////////////////////////////////////////////////
// INITIAL BUILD ARRAY & INITIAL CHECKS
//////////////////////////////////////////////////////////////////////////////////////
function buildArray(){
	numRequiredFields = document.getElementById('numRequiredFields').value;
	dbEntryId = document.getElementById("databaseEntryId").value;
	//set the form action properties
	formAction = document.getElementById('validatedAction').value;
	formId = document.getElementById('formId').value;
	form = document.getElementById(formId);
	
	arrayBuilt = true;
	var fieldsString = document.getElementById('requiredFields').value;
	var fieldsArray = fieldsString.split(", ");
	for(var i in fieldsArray){
		fieldName = fieldsArray[i];
		valType = document.getElementById(fieldName+"-ValType").value;
		if(valType=='9'){
			var fieldRef = CKEDITOR.instances[fieldName];
			fieldValue = strip_tags(fieldRef.getData());
			fieldValue = trim(fieldValue.replace(/&nbsp;/gi, ""));
		}else{
			fieldValue = document.getElementById(fieldName).value;
		}
		var initValidation = checkInitValState();
		//if the valType is 10 ensure the array is fully built before allowing submission (disable the submit button until the number
		//of elements in the validateArray mathces the numRequiredFields)
		if(valType!=10){
			validateArray[fieldName] = initValidation;
		}else{
			//if the loop is not already underway, start it and disable the submit button
			if(!arrayBuiltVal10Check){
				arrayBuiltVal10Check = true;
				if(document.getElementById){ 
					// this is the way the standards work 
					document.getElementById("submitButton").disabled = true; 
				}else if(document.all){ 
					// this is the way old msie versions work 
					document.all["submitButton"].disabled = true; 
				}else if(document.layers){ 
					// this is the way nn4 works 
					document.layers["submitButton"].disabled = true; 
				}
				type10ArrayBuiltCheck();
			}
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function initType7(){
	var fieldsString = document.getElementById('valType7Fields').value;
	if(fieldsString!=""){
		var fieldsSecArray = fieldsString.split(", ");
		for(var i in fieldsSecArray){
			var type8NameValue = fieldsSecArray[i];
			var nameValueArray = type8NameValue.split('=');
			var type8Name = nameValueArray[1];
			//get error message and place it in relevant fields error div
			var errMsg = document.getElementById(nameValueArray[0]+"Error").innerHTML;
			var destErrDiv = document.getElementById(type8Name+"Error");
			destErrDiv.innerHTML = errMsg;
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function initType8(){
	var fieldsString = document.getElementById('valType8Fields').value;
	if(fieldsString!=""){
		var fieldsSecArray = fieldsString.split(", ");
		for(var i in fieldsSecArray){
			var type8NameValue = fieldsSecArray[i];
			var nameValueArray = type8NameValue.split('=');
			var type8Name = nameValueArray[1];
			//get error message and place it in relevant fields error div
			var errMsg = document.getElementById(nameValueArray[0]+"Error").innerHTML;
			var destErrDiv = document.getElementById(type8Name+"Error");
			destErrDiv.innerHTML = errMsg;
			var fieldTr = document.getElementById(type8Name+"Tr");
			if(fieldTr==undefined && fieldsString!=""){
				alert('TYPE 8 ERROR: No field to trigger is defined');
			}
			fieldTr.setAttribute('style', 'display:none;');
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function initType10(){
	var fieldsString = document.getElementById('valType10Fields').value;
	if(fieldsString!=""){
		xmlHttp = createXmlHttpRequestObject();
		serverAddress = "../validate/"+document.getElementById("valType10ServerAddress").value;
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function checkInitValState(){
	switch(valType){
		case '1':
			if(fieldValue==""){
				return 0;
			}else{
				return 1;
			}
		break;
		case '2':
			//in this version of FormValidate.js valType 2 will be to verify a password field ONLY, therefore will always return 0 
			//on first load whether the form is an edit or insert
			return 0;
		break;
		case '3':
			var apos=fieldValue.indexOf("@");
			var dotpos=fieldValue.lastIndexOf(".");
			if(apos<1||dotpos-apos<2){
				return 0;
			}else{
				return 1;
			}
		break;
		case '4':
			var httpString = "http://";
			var dotpos=fieldValue.lastIndexOf(".");
			if (fieldValue.indexOf(httpString)==(0) && dotpos>7) {
				return 1;
			}else{
				return 0;
			}
		break;
		case '5':
			if(fieldValue=="Please Select..."){
				return 0;
			}else{
				return 1;
			}
		break;
		case '6':
			var isNumber = true;
			var character;
			for(var i=0; i<fieldValue.length; i++){ 
				character = fieldValue.charAt(i); 
				if(integerList.indexOf(character) == -1){
					isNumber = false;
					break;
				}
			}
			if(isNumber==false){
				return 0;
			}else{
				return 1;
			}
		break;
		case '8':
			if(fieldValue=="Please Select..."){
				return 0;
			}else{
				return 1;
			}
		break;
		case '9':
			if(fieldValue==""){
				return 0;
			}else{
				return 1;
			}
		break;
		case '10':
			validateType10(fieldName, fieldValue);
		break;
	}
}
//////////////////////////////////////////////////////////////////////////////////////
// ERROR CHECKS
//////////////////////////////////////////////////////////////////////////////////////
function checkForErrors(_valType, _fieldType, _errorDivName, _errMsg, _equalFieldId){
	//set props
	valType = _valType;
	fieldType = _fieldType;
	errorDivName = _errorDivName;
	errMsg = _errMsg;
	equalFieldId = _equalFieldId;
	
	inputFieldId = extractTagId(errorDivName);
	inputField = document.getElementById(inputFieldId);
	inputFieldValue = inputField.value;
	
	if(!arrayBuilt){
		initType7();
		initType8();
		initType10();
		buildArray();
	}
	errorDiv = document.getElementById(errorDivName);
	
	if(fieldType=='checkbox'){
		validateCheckbox();
	}else{
		determineValType();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function checkNonRequired(){
	if(!arrayBuilt){
		initType7();
		initType8();
		initType10();
		buildArray();
	}
	checkOverallValidation();
}
//////////////////////////////////////////////////////////////////////////////////////
function checkType7(_fieldType, _errorDivName, _errMsg, _triggerNN){
	errMsg = _errMsg;
	fieldType = _fieldType;
	
	inputFieldId = extractTagId(_errorDivName);
	inputField = document.getElementById(inputFieldId);
	inputFieldValue = inputField.value;
	
	var fieldToValidate = document.getElementById(_triggerNN);
	var fieldToValValue = fieldToValidate.value;
	var initValState;
	if(fieldToValValue==""){
		initValState = 0;
	}else{
		initValState = 1;
	}
	
	var fieldToValTdId = _triggerNN+"Td";
	var fieldToValTd = document.getElementById(fieldToValTdId);
	var fieldToValLabel = fieldToValTd.innerHTML;
	
	var tempErrorDiv = document.getElementById(_triggerNN+'Error');
	
	if(inputFieldValue!=""){
		//value is not null, place onblur='' attribute into the relevant field and update array if required
		//add * to the field
		if(fieldToValLabel.indexOf('*')==-1){
			fieldToValTd.innerHTML = fieldToValTd.innerHTML+" *";
			//add the onblur attribute
			fieldToValidate.setAttribute('onblur', 'checkForErrors("1", "'+fieldType+'", "'+_triggerNN+'Error", "'+errMsg+'", "");');
			//add to the master array
			validateArray[_triggerNN] = initValState;
			validateArrayLength++;
			checkNonRequired();
		}
	}else{
		//value is null, remove onblur='' attribute from the relevant field and update array if required
		//remove * from the field
		if (fieldToValLabel.indexOf('*') != -1) {
			var tdHTMLlength = fieldToValTd.innerHTML.length;
			var newTdHTMLlength = tdHTMLlength - 2;
			fieldToValTd.innerHTML = fieldToValTd.innerHTML.substr(0, newTdHTMLlength);
			//remove the onblur attribute
			fieldToValidate.setAttribute('onblur', 'checkNonRequired()');
			//remove from the master array
			delete validateArray[_triggerNN];
			validateArrayLength--;
			tempErrorDiv.innerHTML = "";
			fieldToValidate.style.backgroundColor="";
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function checkType8(_fieldType, _errorDivName, _errMsg, _triggerNN){
	errMsg = _errMsg;
	fieldType = _fieldType;
	
	inputFieldId = extractTagId(_errorDivName);
	inputField = document.getElementById(inputFieldId);
	inputFieldValue = inputField.value;
	var inputFieldTdId = inputFieldId+"Td";
	var inputFieldTd = document.getElementById(inputFieldTdId);
	var inputFieldLabel = inputFieldTd.innerHTML;
	
	errorDiv = document.getElementById(_errorDivName);
	
	var fieldToValidate = document.getElementById(_triggerNN);
	var fieldToValValue = fieldToValidate.value;
	var initValState;
	if(fieldToValValue==""){
		initValState = 0;
	}else{
		initValState = 1;
	}
	var fieldToValTdId = _triggerNN+"Td";
	var fieldToValTd = document.getElementById(fieldToValTdId);
	var fieldToValLabel = fieldToValTd.innerHTML;
	
	var fieldToValTrId = _triggerNN+"Tr";
	var fieldToValTr = document.getElementById(fieldToValTrId);
	
	var tempErrorDiv = document.getElementById(_triggerNN+'Error');
	
	if(inputFieldValue=="Other..."){
		//value is not null, place onblur='' attribute into the relevant field and update array if required
		//check state of field using presence of *
		if(fieldToValLabel.indexOf('*')==-1){
			//add * to hidden field label
			fieldToValTd.innerHTML = fieldToValTd.innerHTML+" *";
			//remove * from dropdown label
			var tdHTMLlength = inputFieldTd.innerHTML.length;
			var newTdHTMLlength = tdHTMLlength - 2;
			inputFieldTd.innerHTML = inputFieldTd.innerHTML.substr(0, newTdHTMLlength);
			//add the onblur attribute
			fieldToValidate.setAttribute('onblur', 'checkForErrors("1", "'+fieldType+'", "'+_triggerNN+'Error", "'+errMsg+'", "");');
			//add to the master array
			validateArray[_triggerNN] = initValState;
			//show the tr
			fieldToValTr.removeAttribute('style');
			tempErrorDiv.setAttribute('style', 'display:none;');
			checkNonRequired();
		}
	}else{
		//value is null, remove onblur='' attribute from the relevant field and update array if required
		//check state of field using presence of *
		if (fieldToValLabel.indexOf('*') != -1) {
			//remove * from hidden field
			var tdHTMLlength = fieldToValTd.innerHTML.length;
			var newTdHTMLlength = tdHTMLlength - 2;
			fieldToValTd.innerHTML = fieldToValTd.innerHTML.substr(0, newTdHTMLlength);
			//add * to dropdown label
			inputFieldTd.innerHTML = inputFieldTd.innerHTML + " *";
			//remove the onblur attribute
			fieldToValidate.setAttribute('onblur', 'checkNonRequired()');
			//remove from the master array
			delete validateArray[_triggerNN];
			//hide the tr
			fieldToValTr.setAttribute('style', 'display:none;');
			fieldToValidate.style.backgroundColor="";
			tempErrorDiv.setAttribute('style', 'display:none;');
			checkNonRequired();
		}
	}
	if(inputFieldValue=="Please Select...") {
		validateArray[inputFieldId] = 0;
		inputField.style.backgroundColor="#FF0000";
		errorDiv.removeAttribute('style');
		checkNonRequired();
	}else{
		delete validateArray[inputFieldId];
		inputField.style.backgroundColor="";
		errorDiv.setAttribute('style', 'display:none;');
		checkNonRequired();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function checkType9(_name, _errorDivName, _errMsg){
	errorDiv = document.getElementById(_errorDivName);
	var field = CKEDITOR.instances[_name];
	var value = strip_tags(field.getData());//this removes all html tags so the string can be tested as plain text for NOT NULL status
	value = trim(value.replace(/&nbsp;/gi, ""));//this removes all white space before and after the string, also any instances of &nbsp; This is incase a value of 'enter' is not accepted and that actual plain text charactres must be present
	if(value==""){
		field.setUiColor('#FF0000');
		errorDiv.removeAttribute('style');
		validateArray[_name] = 0;
	}else{
		field.setUiColor('#CCCCCC');
		errorDiv.setAttribute('style', 'display:none;');
		validateArray[_name] = 1;
	}
	checkOverallValidation();
}
//////////////////////////////////////////////////////////////////////////////////////
function checkType10(_fieldName, _result){
	var errDiv = document.getElementById(_fieldName+"Error");
	var inpField = document.getElementById(_fieldName);
	if(_result==0){
		//invalid
		validateArray[_fieldName] = 0;
		errDiv.removeAttribute('style');
		inpField.style.backgroundColor="#FF0000";
	}else{
		//valid
		validateArray[_fieldName] = 1;
		errDiv.setAttribute('style', 'display:none;');
		inpField.style.backgroundColor="";
	}
	ajaxValidationInProgress = false;
	checkOverallValidation();
}
//////////////////////////////////////////////////////////////////////////////////////
function validateType10(_fieldName, _fieldValue){
	if(xmlHttp!="uninitialiased"){
		if(_fieldName){
			//if we received non-null parameters, we add them to cache in the form of a query string to be sent to the server for validation
			//encode values for safely adding them to an HTTP request query string
			_fieldValue = encodeURIComponent(_fieldValue);
			_fieldName = encodeURIComponent(_fieldName);
			//add the values to the queue
			cache.push("fieldValue="+_fieldValue+"&fieldName="+_fieldName+"&dbEntryId="+dbEntryId);
		}
		//try to connect to the server
		try{
			//continue only if the XMLHTTPRequest object isnt busy and the cache is not empty
			if((xmlHttp.readyState==4 || xmlHttp.readyState == 0) && cache.length > 0){
				ajaxValidationInProgress = true;
				//get a new set of parameters from the cache
				var cacheEntry = cache.shift();
				//make a server request to validate the extracted data
				xmlHttp.open("POST", serverAddress, true);
				xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				xmlHttp.onreadystatechange = handleRequestStateChange;
				xmlHttp.send(cacheEntry);
			}
		}catch(e){
			//display an error when failing to connect to the server
			displayError(e.toString());
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function determineValType(){
	switch(valType){
		case '1':
			performCheckV1();
		break;
		case '2':
			performCheckV2();
		break;
		case '3':
			performCheckV3();
		break;
		case '4':
			performCheckV4();
		break;
		case '5':
			performCheckV5();
		break;
		case '6':
			performCheckV6();
		break;
		case '10':
			validateType10(inputFieldId, inputFieldValue);
		break;
	}
	checkOverallValidation();
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV1(){
	if(inputFieldValue!=""){
		fieldIsValid();
		checkOverallValidation();
	}else{
		fieldIsNotValid();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV2(){
	//alert(equalFieldId);
	equalField = document.getElementById(equalFieldId);
	equalFieldValue = equalField.value;
	if(inputFieldValue==equalFieldValue && inputFieldValue!=""){
		fieldIsValid();
		checkOverallValidation();
	}else{
		fieldIsNotValid();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV3(){
	var apos=inputFieldValue.indexOf("@");
	var dotpos=inputFieldValue.lastIndexOf(".");
	if(apos<1||dotpos-apos<2){
		fieldIsNotValid();
	}else{
		fieldIsValid();
		checkOverallValidation();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV4(){
	var httpString = "http://";
	var dotpos=inputFieldValue.lastIndexOf(".");
	if(inputFieldValue.indexOf(httpString)==(0) && dotpos>7){
		fieldIsValid();
		checkOverallValidation();
	}else{
		fieldIsNotValid();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV5(){
	var pleaseSelString = "Please Select...";
	if(inputFieldValue!=pleaseSelString){
		fieldIsValid();
		checkOverallValidation();
	}else{
		fieldIsNotValid();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function performCheckV6(){
	var isNumber = true;
	var character;
	for(var i=0; i<inputFieldValue.length; i++){ 
		character = inputFieldValue.charAt(i); 
		if(integerList.indexOf(character) == -1){
			isNumber = false;
			break;
		}
	}
	if(isNumber==false){
		fieldIsNotValid();
	}else{
		fieldIsValid();
		checkOverallValidation();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function validateCheckbox(){
	if(inputField.checked){
		fieldIsValid();
		checkOverallValidation();
	}else{
		fieldIsNotValid();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function fieldIsValid(){
	validateArray[inputFieldId] = 1;
	errorDiv.setAttribute('style', 'display:none;');
	inputField.style.backgroundColor="";
}
//////////////////////////////////////////////////////////////////////////////////////
function fieldIsNotValid(){
	//set array then report error to user
	validateArray[inputFieldId] = 0;
	errorDiv.removeAttribute('style');
	inputField.style.backgroundColor="#FF0000";
}
//////////////////////////////////////////////////////////////////////////////////////
// FINAL CHECKS AND REPORTS
//////////////////////////////////////////////////////////////////////////////////////
function checkOverallValidation(){
	allValidated = true;
	var counter = 0;
	for(var i in validateArray){
		counter++;
		if(validateArray[i]==0){
			allValidated = false;
		}
	}
	if(allValidated){
		form.action = formAction;
	}else{
		form.action = "javascript:notAllValidated();";
	}
	if(submitAfterAjax){
		submitAfterAjax = false;
		document.forms[formId].submit();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function notAllValidated(){
	if(ajaxValidationInProgress){
		submissionWaitForAjax();
	}else{
		//loop through the array and any that arent validated should be highlighted
		for(var i in validateArray){
			if(validateArray[i] == 0){
				var errFieldName = i;
				var errFieldDivName = i + "Error";
				var valType = document.getElementById(errFieldName+"-ValType").value;
				var errField;
				var affectDiv = document.getElementById(errFieldDivName);
				if(valType != 9){
					errField = document.getElementById(errFieldName);
					errField.style.backgroundColor = "#FF0000";
				}else{
					errField = CKEDITOR.instances[errFieldName];
					errField.setUiColor('#FF0000');
				}
				affectDiv.removeAttribute('style');
			}
		}
		//report error
		alert("Not all required fields are correctly filled out.");
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function submissionWaitForAjax(){
	if(ajaxValidationInProgress){
		setTimeout("submissionWaitForAjax()", 200);
	}else{
		submitAfterAjax = true;
		checkOverallValidation();
	}
}
//////////////////////////////////////////////////////////////////////////////////////
// OTHER
//////////////////////////////////////////////////////////////////////////////////////
function strip_tags (str, allowed_tags) {
    // Strips HTML and PHP tags from a string
    var key = '', allowed = false;
    var matches = [];
    var allowed_array = [];
    var allowed_tag = '';
    var i = 0;
    var k = '';
    var html = '';
 
    var replacer = function(search, replace, str){
        return str.split(search).join(replace);
    };
    // Build allowes tags associative array
    if(allowed_tags){
        allowed_array = allowed_tags.match(/([a-zA-Z0-9]+)/gi);
    }
    str += '';
    // Match tags
    matches = str.match(/(<\/?[\S][^>]*>)/gi);
    // Go through all HTML tags
    for(key in matches){
        if(isNaN(key)){
            // IE7 Hack
            continue;
        }
        // Save HTML tag
        html = matches[key].toString();
        // Is tag not in allowed list? Remove from str!
        allowed = false;
        // Go through all allowed tags
        for(k in allowed_array){
            // Init
            allowed_tag = allowed_array[k];
            i = -1;
            if(i != 0){ i = html.toLowerCase().indexOf('<'+allowed_tag+'>');}
            if(i != 0){ i = html.toLowerCase().indexOf('<'+allowed_tag+' ');}
            if(i != 0){ i = html.toLowerCase().indexOf('</'+allowed_tag)   ;}
            // Determine
            if(i == 0){
				allowed = true;
				break;
            }
        }
        if(!allowed){
            str = replacer(html, "", str); // Custom replace. No regexing
        }
    }
    return str;
}
//////////////////////////////////////////////////////////////////////////////////////
function trim (str, charlist) {
    // Strips whitespace from the beginning and end of a string
    var whitespace, l = 0, i = 0;
    str += '';
    if(!charlist){
        // default list
        whitespace = " \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000";
    }else{
        // preg_quote custom list
        charlist += '';
        whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '$1');
    }
    l = str.length;
    for(i = 0; i < l; i++){
        if(whitespace.indexOf(str.charAt(i)) === -1){
            str = str.substring(i);
            break;
        }
    }
    l = str.length;
    for(i = l - 1; i >= 0; i--){
        if(whitespace.indexOf(str.charAt(i)) === -1){
            str = str.substring(0, i + 1);
            break;
        }
    }
    return whitespace.indexOf(str.charAt(0)) === -1 ? str : '';
}
//////////////////////////////////////////////////////////////////////////////////////
function extractTagId(errorDivName){
	var nameLength = errorDivName.length;
	var inputFieldIdLength = nameLength-5;// minus 5 to account for ERROR being added
	return errorDivName.substr(0, inputFieldIdLength);
}
//////////////////////////////////////////////////////////////////////////////////////
function print_r(theObj){
	if(theObj.constructor == Array || theObj.constructor == Object){
		document.write("<ul>")
		for(var p in theObj){
			if(theObj[p].constructor == Array|| theObj[p].constructor == Object){
				document.write("<li>["+p+"] => "+typeof(theObj)+"</li>");
        		document.write("<ul>");
        		print_r(theObj[p]);
        		document.write("</ul>")
      		}else{
				document.write("<li>["+p+"] => "+theObj[p]+"</li>");
			}
		}
		document.write("</ul>")
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function createXmlHttpRequestObject(){
	var xmlHttp;
	//this should work for all browsers except IE6 and older
	try{
		//try to create XMLHttpRequest object
		xmlHttp = new XMLHttpRequest();
	}catch(e){
		//assume IE6 or older when try block fails
		var XmlHttpVersions = new Array("MSXML2.XMLHTTP.6.0",
										"MSXML2.XMLHTTP.5.0",
										"MSXML2.XMLHTTP.4.0",
										"MSXML2.XMLHTTP.3.0",
										"MSXML2.XMLHTTP",
										"Microsoft.XMLHTTP");
		//try every prog id until one works
		for(var i=0; i<XmlHttpVersions.length && !xmlHttp; i++){
			try{
				//try to create XMLHttpRequest object
				xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
			}catch(e){};
		}
	}
	//return the created object or display an error message
	if(!xmlHttp){
		displayError("Error creating the XMLHttpRequest object");
	}else{
		return xmlHttp;
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function displayError(message){
 	//ignore errors if showErrors is false
	if(showErrors){
		//turn error displaying off
		showErrors = false;
		//display error message
		alert("Error encountered: \n"+message);
		//retry validation after 10 seconds
		setTimeout("validate();", 10000);
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function handleRequestStateChange(){
 	//when readyState is 4 we are ready to read the server response
	if(xmlHttp.readyState==4){
		//continue only if HTTP status is OK
		if(xmlHttp.status==200){
			try{
				readResponse();
			}catch(e){
				//display error message
				displayError(e.toString());
			}
		}else{
			//display error message
			displayError(xmlHttp.statusText);
		}
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function readResponse(){
	//retrieve the servers response
	var response = xmlHttp.responseText;
	//server error?
	if (response.indexOf("ERRNO") >= 0 || response.indexOf("error:") >= 0 || response.length == 0) {
		throw (response.length == 0 ? "Server error." : response);
	}
	//get response in XML format (assume the response is valid XML)
	var responseXml = xmlHttp.responseXML;
	//get the document element
	var xmlDoc = responseXml.documentElement;
	var result = xmlDoc.getElementsByTagName("result")[0].firstChild.data;
	var returnedFieldName = xmlDoc.getElementsByTagName("fieldName")[0].firstChild.data;
	//check whether the array is already complete, if not it is being initialised, otherwise it is reporting a response
	if(validateArrayLength==numRequiredFields){
		checkType10(returnedFieldName, result);
	}else{
		ajaxValidationInProgress = false;
		//update the array with the response
		validateArray[returnedFieldName] = result;
		//call validateType10() again in case there are values left in the cache
		setTimeout("validateType10();", 500);
	}
}
//////////////////////////////////////////////////////////////////////////////////////
function type10ArrayBuiltCheck(){
	validateArrayLength = 0;
	for(var i in validateArray){
		validateArrayLength++;
	}
	if(validateArrayLength == numRequiredFields){
		if(document.getElementById){ 
			// this is the way the standards work 
			document.getElementById("submitButton").disabled = false; 
		}else if(document.all){ 
			// this is the way old msie versions work 
			document.all["submitButton"].disabled = false; 
		}else if(document.layers){ 
			// this is the way nn4 works 
			document.layers["submitButton"].disabled = false; 
		}
		checkOverallValidation();
	}else{
		setTimeout("type10ArrayBuiltCheck()", 100);
	}
}
//////////////////////////////////////////////////////////////////////////////////////