var messageText = "";
var isFocusSet;
// numeric range constants
var MAX_ADO_INTEGER = Math.pow(2, 31) -1;
var MIN_ADO_INTEGER = Math.pow(-2, 31);
var MAX_ADO_BIGINT = Math.pow(2, 63) -1;
var MIN_ADO_BIGINT = Math.pow(-2, 63);

// performs automatic validation based on control validation and mandatory attributes
// parameter may be passed to validate sub-set of controls
function validateForm() {
	var colFields;
	
	messageText = "";
	isFocusSet = false;
	
	// Iterate through all fields and check using standard validation
	/*
	if (arguments.length > 0) {
		colFields = new Enumerator(document.all(arguments[0]).all);
	}
	else {
		colFields = new Enumerator(document.forms[0].all);
	}
	*/
	
		
	// loop through controls
	
	/*for(; !colFields.atEnd(); colFields.moveNext()) {
		// get control type
		var control = colFields.item();
	*/
	for(var z = 0; z < document.forms[0].length ; z++){
		if(document.forms[0].elements[z].id)
		{
			var control = document.getElementById(document.forms[0].elements[z].id);
		}
		else
		{
			continue;
		}
		
		
		var controlValue = "";
		var messageMandatory = "must be supplied.";
		
		// get control value
		//switch (control.tagName.toLowerCase()) {
		switch (control.type.toLowerCase()) {
			//we must check spans as radio button lists are rendered inside a span, unfortunatly
			//the surrounding span has the mandatory attribute. 
			case "span":
				//a span might have a radio button list inside of it
				tmpRadioGroupName = genRadioGroupName(control.id);
				if(tmpRadioGroupName != null){
					radioButtons = document.getElementsByName(tmpRadioGroupName);
					if(radioButtons != null){
						//we have found a radio button group inside the span, so now find which one is selected
						for(i = 0; i < radioButtons.length; i++){
							radioButton = radioButtons[i];
							if(radioButton.checked){
								controlValue = radioButton.value;
								break;
							}
						}
					}
				}
				else{
					
					//the span has no id, this could include a single checkbox
					//as asp.net creates a checkbox wrapped in a span with no id
					checkBoxes = control.getElementsByTagName('input');
					if(checkBoxes && (checkBoxes.length == 1)){
						checkBox = checkBoxes[0];
						if(checkBox && (checkBox.type == 'checkbox')){
							if(checkBox.checked){
								controlValue = checkBox.value;
							}
							else{
								//we set a friendly error message for a check box
								messageMandatory = 'must be selected';
							}
						}
					}
				}
				break;
			case "password":
			case "text":
			case "input":
				controlValue = control.value;
				break;
				
			case "textarea":
				controlValue = control.value;
				
				// check that we have not exceeded max length
				if (control.maxlength && controlValue.length > control.maxlength) {
					addError(control, "must not exceed " + control.maxlength + " characters.");
				}
				break;
			case "select-one":
				controlValue = control.selectedItem;
				break;
			case "select":
					controlValue = control.value;
				messageMandatory = "must be selected.";
				
				/* need to be able to search on "disabled" criteria so comment out for now
					   need to check whether this has knock on effects for other pages...
				// check that selected item is not disabled
				if (control.selectedIndex != -1)
				{
					var selectedOption = control.options[control.selectedIndex];
					
					if (selectedOption.className == "disabled") {
						addError(control, "selection is invalid - the selected option is disabled.");
					}
				}*/
				break;
		}
		// check for mandatory
		if ((control.getAttribute("mandatory") == "true") &&
			((controlValue == "") ||
			(control.type.toLowerCase() == "select-one" && controlValue == "-1")))		
		{

			addError(control, messageMandatory);
		}
		else if(control.getAttribute("mandatory") == "true" && control.type.toLowerCase() == "select" && controlValue == "-1") {
				addError(control, messageMandatory);
		}
		
		else if((control.getAttribute("mandatory") == "true")&&
			(control.getAttribute("minLength") > 0 && controlValue.length < control.getAttribute("minLength")))
			{
				addError(control, " must be at least " + control.getAttribute("minLength") + " characters.");
			
		}
		else if (control.getAttribute("textBoxStyle") !=null)
		{
			switch (control.getAttribute("textBoxStyle").toLowerCase()) {
				case "integerasstring":
				case "integer":
					// check if the value is a number
					if ((controlValue != controlValue.match("[0-9]+") && control.getAttribute("mandatory") == "True") || (controlValue != controlValue.match("[0-9]+") && control.getAttribute("mandatory") == "False" && controlValue != "")) {
						addError(control, "must be a valid integer value.");
					}
					else if (parseInt(controlValue) < MIN_ADO_INTEGER || parseInt(controlValue) > MAX_ADO_INTEGER) {
						addError(control, "is beyond the number range (" + MIN_ADO_INTEGER + " to " + MAX_ADO_INTEGER + ")");
					}
					break;
				
				case "longasstring":
				case "long":
					// check if the value is a number
					if(controlValue == "")
					{
						break;
					}
					if (controlValue != controlValue.match("[0-9]+")) {
						addError(control, "must be a valid integer value.");
					}
					else if (parseInt(controlValue) < MIN_ADO_BIGINT || parseInt(controlValue) > MAX_ADO_BIGINT) {
						addError(control, "is beyond the number range (" + MIN_ADO_BIGINT + " to " + MAX_ADO_BIGINT + ")");
					}
					break;
				
				case "decimal":
					var decimalCount = 2;
					if (control.getAttribute("decimalPlaces")) {
						decimalCount = control.getAttribute("decimalPlaces");
					}
					
					// check if the value is a valid decimal
					if (controlValue != controlValue.match("[0-9]+") && controlValue != controlValue.match("[0-9]+.[0-9]{1," + decimalCount + "}")) {
						addError(control, "must be a valid decimal value with a maximum of " + decimalCount + " decimal places.");
					}

					break;
					
				case "alphanumeric":
					if (controlValue != controlValue.match("^[a-zA-Z0-9]+$"))
					{
						addError(control, "must be an alpha numeric string with no spaces.");
					}
					break;
				
				case "date":
					if (!validateDate(control)) {
						addError(control, "must be a valid date (dd/MM/yyyy).");
					}
					break;
				
				case "time":
					if (!validateTime(control)) {
						addError(control, "must be a valid time (hh:mm).");
					}
					break;
				case "datetime":
					var strDate = control.value.substr(0,10);
					var strTime = control.value.substr(11,5);
					var isValid = true;
					
					control.value = strDate;
					if (!validateDate(control)) {
						isValid = false;
					}
					// save return from validate
					strDate = control.value;
					control.value = strTime;
					if (!validateTime(control)) {
						isValid = false;
					}
					control.value = strDate + " " + control.value;
					if (!isValid) {
						
						addError(control, "must be a valid date and time (dd/MM/yyyy hh:mm).");
					}
					break;
					
				case "postcode":
					// force upper case, strip out multiple spaces and return to input field
					controlValue = controlValue.toUpperCase();
					while (controlValue.indexOf("  ") != -1) {
						controlValue = controlValue.replace("  ", " ");
					}
					control.value = controlValue;
					
					//check basic format
					//note that some postcodes appear to have an additional alpha character after the 1st numeric portion, eg EC2M 6SX 
					var strMatch = "[A-Z]{1,2}[0-9]{1,2}[A-Z]{0,1} ?[0-9][A-Z]{2}";
					if (controlValue != controlValue.match(strMatch)) {
						addError(control, "is not a valid format");
					}
					else {
						//check valid postcode area
						arrPostCodes = new Array("AB","AL","B","BA","BB","BD","BH","BL","BN","BR","BS","BT","CA","CB","CF","CH","CI","CM","CO","CR","CT","CV","CW","DA","DD","DE","DG","DH","DL","DN","DT","DY","E","EC","EH","EN","EX","FK","FY","G","GL","GU","GY","HA","HD","HG","HP","HR","HU","HX","IG","IOM","IP","IV","JE","KA","KT","KW","KY","L","LA","LD","LE","LL","LN","LS","LU","M","ME","MK","ML","N","NE","NG","NN","NP","NR","NW","OL","OX","PA","PE","PH","PL","PO","PR","RG","RH","RM","S","SA","SE","SG","SK","SL","SM","SN","SO","SP","SR","SS","ST","SW","SY","TA","TD","TF","TN","TQ","TR","TS","TW","UB","W","WA","WC","WD","WF","WN","WR","WS","WV","YO","ZE","XX");
						var tmpPostCode = "";
						for (var k = 0; k < controlValue.length; k++) {
							var oneChar = controlValue.charAt(k);
							if (oneChar >= "A" && oneChar <= "Z") {
								tmpPostCode += oneChar;
							}
							else {
								break;
							}
						}
						var vMatch = false;
						for (var j = 0; j < arrPostCodes.length ; j++) {
							if (arrPostCodes[j] == tmpPostCode) {
								vMatch = true; 
								break;
							}
						}
						if (vMatch != true) {
							addError(control, "does not have a valid prefix");
						}
					}
					
					break;	
					
				case "email":
					if (controlValue.search(/\w+((-\w+)|(\.\w+)|(\_\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]{2,5}/ ) == -1) {
						addError(control, "is not a valid email address");
					}
					break;	

				/*					
				case "range":
					switch (arrParameters.length) {
						case 2:
							if (controlValue < arrParameters[1]) {
								addError(control, "must be greater or equal to " + arrParameters[1] + ".");
							}
							break;
							
						case 3:
							if (parseFloat(controlValue) < parseFloat(arrParameters[1]) || parseFloat(controlValue) > parseFloat(arrParameters[2])) {
								addError(control, "must be between " + arrParameters[1] + " and " + arrParameters[2] + ".");
							}
							break;
							
						default:
							addError(control, "has invalid range parameters.");
							
					}
					break;
				*/
				case "default":
					break;
			
				default:
					addError(control, "has an invalid textBoxStyle parameter - " + control.textBoxStyle + ".");
			}
		}
	}
	// If validation failed - display messageText
	if (messageText != "") {
		showErrors();
		return false;			
	}
	try
	{
		//document.all.pnlMessage.className = "nodisplay";
		document.getElementById("pnlMessage").setAttribute("className","nodisplay");
	}
	catch(e){}
	return true;	
}

function showErrors() {
	window.scrollTo(0, 0);
	messageText = "Please correct the following error(s):<ul>" + messageText + "</ul>";
	//document.all.vsPage.innerHTML = messageText;
	document.getElementById("vsPage").innerHTML = messageText;
	//document.all.vsPage.style.display = "block";
	document.getElementById("vsPage").style.display = "block";
	beep();
}

// add error to message text
function addError(control, errorText) {
	messageText += "<li>" + getControlName(control) + " " + errorText + "</li>";

	// set focus if we haven't already done so
	if (!isFocusSet) {
		isFocusSet = true;
		
		try {
			control.focus();
		}
		catch (e) {}
	}
}

// get the user friendly name from the control
function getControlName(control) {

	if (control.Caption != null)
	{
		return control.Caption;
	}

	if (control.caption != null)
	{
		return control.caption;
	}

	var inputName = control.id;

	try {
		var outputName = inputName;
		
		// Put spaces in between capitalised words and remove lower case prefix
		var objRegExp = /[A-Z][a-z]+/g;
		var arrMatches = outputName.match(objRegExp);
		
		return arrMatches.join(" ");
	}
	catch (e) {
		return "";		
	}
}

//********************************************************************
// Following functions relate to date validation
//********************************************************************
function validateDate(dateControl) {
	//var strDatestyle = "US"; //United States date style
	var strDatestyle = "EU";  //European date style
	var strDate;
	var strDateArray;
	var strDay;
	var strMonth;
	var strYear;
	var intDay;
	var intMonth;
	var intYear;
	var booFound = false;
	var strSeparatorArray = new Array("-"," ","/",".");
	var intElementNr;
	var err = 0;
	var strMonthArray = ("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec").split(",");
	strDate = dateControl.value;
	if (strDate.length < 1) {
		return true;
	}

	for (intElementNr = 0; intElementNr < strSeparatorArray.length; intElementNr++) {
		if (strDate.indexOf(strSeparatorArray[intElementNr]) != -1) {
			strDateArray = strDate.split(strSeparatorArray[intElementNr]);
			if (strDateArray.length != 3) {
				err = 1;
				return false;
			}
			else {
				strDay = strDateArray[0];
				strMonth = strDateArray[1];
				strYear = strDateArray[2];
			}
			booFound = true;
		}
	}
	
	if (booFound == false) {
		if (strDate.length>5) {
			strDay = strDate.substr(0, 2);
			strMonth = strDate.substr(2, 2);
			strYear = strDate.substr(4);
		}
	}
	
	// swap for US style date
	if (strDatestyle == "US") {
		strTemp = strDay;
		strDay = strMonth;
		strMonth = strTemp;
	}
	
	intDay = parseInt(strDay, 10);
	if (isNaN(intDay)) {
		err = 2;
		return false;
	}
	
	intMonth = parseInt(strMonth, 10);
	if (isNaN(intMonth)) {
		for (i = 0;i<12;i++) {
			if (strMonth.toUpperCase() == strMonthArray[i].toUpperCase()) {
				intMonth = i+1;
				strMonth = strMonthArray[i];
				i = 12;
			}
		}
		if (isNaN(intMonth)) {
			err = 3;
			return false;
		}
	}
	
	intYear = parseInt(strYear, 10);
	if (isNaN(intYear)) {
		err = 4;
		return false;
	}
	
	//ensure we have a 4 digit year
	if (strYear.length == 1) {
		strYear = '0' + strYear;
	}
	if (strYear.length == 2) {
		if (intYear < 30) {
			strYear = '20' + strYear;
		}
		else {
			strYear = '19' + strYear;
		}
	}
	intYear = parseInt(strYear, 10);
	if (intYear < 1900 || intYear > 2100) return false;
	
	if (intMonth>12 || intMonth<1) {
		err = 5;
		return false;
	}
	
	if ((intMonth == 1 || intMonth == 3 || intMonth == 5 || intMonth == 7 || intMonth == 8 || intMonth == 10 || intMonth == 12) && (intDay > 31 || intDay < 1)) {
		err = 6;
		return false;
	}
	
	if ((intMonth == 4 || intMonth == 6 || intMonth == 9 || intMonth == 11) && (intDay > 30 || intDay < 1)) {
		err = 7;
		return false;
	}
	
	if (intMonth == 2) {
		if (intDay < 1) {
			err = 8;
			return false;
		}
		if (isLeapYear(intYear) == true) {
			if (intDay > 29) {
				err = 9;
				return false;
			}
		}
		else {
			if (intDay > 28) {
				err = 10;
				return false;
			}
		}
	}
	
	//reformat date as required
	strDay = (intDay < 10) ? '0' + intDay : intDay;
	strMonth = (intMonth < 10) ? '0' + intMonth : intMonth;
	
	if (strDatestyle == "US") {
		//dateControl.value = strMonthArray[intMonth-1] + " " + intDay + " " + strYear;
		dateControl.value = strMonth + "/" + strDay + "/" + strYear;
	}
	else {
		//dateControl.value = intDay + " " + strMonthArray[intMonth-1] + " " + strYear;
		dateControl.value = strDay + "/" + strMonth + "/" + strYear;
	}
	
	return true;
}

function isLeapYear(intYear) {
	if (intYear % 100 == 0) {
		if (intYear % 400 == 0) { 
			return true; 
		}
	}
	else {
		if ((intYear % 4) == 0) { 
			return true; 
		}
	}
	return false;
}

function validateTime(timeControl) {
	var dteNow = new Date();
	var arrTime;
	var iHour;
	var iMinute;

	// Check for delimiter and continue if found
	
	if(timeControl.value.indexOf(":") != -1) {
		// Split date into separate values
		arrTime = timeControl.value.split(":");

		// Get each part
		iHour = arrTime[0];
		iMinute = arrTime[1];

		// Check the time is valid
		if((iHour < 0) || (iHour > 23) || (iMinute < 0) || (iMinute > 59)) {
			return false;
		}
		
	} else {
		return false;
	}
	
	// Check the time is formatted correctly
	if(iHour.length < 2)
	{
		return false;
		//iHour = "0" + iHour;
	}
	if(iMinute.length <2)
	{
		return false;
		//iMinutes = "0" + iMinute;
	}
	//timeControl.value = (iHour < 10 ? "0" + iHour : iHour) + ":" + (iMinute < 10 ? "0" + iMinute : iMinute);
	timeControl.value = iHour + ":" + iMinute;
	return true;
}

//this function is used to match a radio button name to thier span id
//basically means replacing all but the first '_' with ':'s
function genRadioGroupName(spanId){
	var result = null;
	if(spanId != '' && spanId.length > 1){
		result = spanId.replace(/_/g,':');
		result = '_' + result.substring(1, result.length);
	}
	return result;
}
