// Universal form validation
function makeArgumentsObject()
{
	return new Object();
}

//Searches the validation array for the datatype.
// If not found the default is 'free text' (string).
function uslGetDataType(validateArray)
{
	var validateField = "";
	var validateFieldName = "";
	var validateFieldValue = "";
	var dataType = "free text";	// default to "free text" (string)
	
	for(k=0; k<validateArray.length; k++)
	{
		validateField = validateArray[k];
		if(validateField)
		{
			//lose the spaces
			validateField = validateField.replace(/\s[]* = []*\s/, "=");
			validateField = uslTrimString(validateField);
			//get the field name and the value;
			validateFieldName = validateField.split("=")[0];
			validateFieldName = uslTrimString(validateFieldName);
			validateFieldValue = validateField.split("=")[1];
			validateFieldValue = uslTrimString(validateFieldValue);
			
			if (validateFieldName == "datatype")
			{
				dataType = validateFieldValue;
				i = validateArray.length;
			}
		}
	}
	return dataType;
}

function uslValidateForm(theForm, verifypassword) {
	
	var reason = "";
	
	var validateString = "";
	var validateInput = "";
	var validateField = "";
	var validateFieldName = "";
	var validateFieldDescription = "";
	var validateFieldValue = "";
	var dataType = "";
	var i = 0;
	var j = 0;
	
	for(i=0; i<theForm.length; i++) {
		//find the hidden fields : these contain the validation strings
		
	
		if (theForm.elements[i].type == "hidden" && theForm.elements[i].name.search("validate_") > -1) {
			validateInput = theForm.elements[i].name.replace("validate_", "");
			validateString = theForm.elements[i].value;
			//get the individual fields from the validate string
			validateArray = validateString.split(";");
			
			//dataType: Really only validate for input elements.
			// The default for all other elements will be 'free text'.
			var dataType = uslGetDataType(validateArray);
	
			//loop through the validateArray
			for(j=0; j<validateArray.length; j++) {
				validateField = validateArray[j];
				if(validateField) {
					//lose the spaces
					validateField = validateField.replace(/\s[]* = []*\s/, "=");
					validateField = uslTrimString(validateField);
					//get the field name and the value;
					validateFieldName = validateField.split("=")[0];
					validateFieldName = uslTrimString(validateFieldName);
					validateFieldValue = validateField.split("=")[1];
					validateFieldValue = uslTrimString(validateFieldValue);
					if(validateFieldName == "fieldname") {
						validateFieldDescription = validateFieldValue;
					}
					else {
						//if the field name and value exist - parse the validation for that field
						var returnReason = uslValidateField(theForm, validateInput, validateFieldDescription, validateFieldName, validateFieldValue, dataType);
						if ((returnReason) && (validateFieldName == "datatype"))
						{
							// data type validate failed so do not validate any further.
							j = validateArray.length;
						}
						reason = reason + returnReason;
					}
				}
			}
		}
	}
	
	if (verifypassword == 1) {
		if (theForm.email.value != theForm.verifyemail.value) reason += "\nThe email address must match";
		if (theForm.pw.value != theForm.verifypw.value) reason += "\nThe passwords must match";
	}
	
	if(reason) {
		alert("The following errors occurred: \n" + reason);
		return false;
	}
	else {
		return true;
	}
}

function uslConvertType(value, dataType)
{
	var changeValue = value;
	switch (dataType)
	{
		case "free text":
			// source and compare value are as is.
			break;
		case "number":
			// Change to number and remove commas.
			if (changeValue != "")
			{
				changeValue = parseFloat(changeValue.replace(/,/g, ""));
				if (isNaN(changeValue))
					throw ("Could not convert value '" + value + "' to a number.");
			}
			break;
		default:
			//Check for date
			var dataTypeValuePart = uslTrimString(dataType.split("(")[0]);
			if (dataTypeValuePart == "date")
			{
				var dateFormat = uslTrimString(dataType.split("(")[1].split(")")[0]);
				//Convert to date.
				var changeValue = new Date();
				if (!uslIsDate(value, dateFormat, changeValue))
				{
					throw ("Could not convert '" + value + "' to a date in the format of '" + dateFormat + "'.");
				}
			}
			break;
	}
	return changeValue;
}

function uslValidateField(theForm, theInput, theName, validateName, validateValue, dataType) {
	var reason = "";
	
	//get the input type
	var theType = theForm[theInput].type;
	if(theForm[theInput][0]) {
		if(theForm[theInput][0].type) theType = theForm[theInput][0].type;
	}
	
	switch(theType) {
		case "checkbox" :
			checkedChecked = false;
			if(theForm[theInput].checked) checkedChecked = true;
			for(iR=0; iR<theForm[theInput].length; iR++) {
				if(theForm[theInput][iR].checked) checkedChecked = true;
			}
			//alert(theForm[theInput].length);
			if(!checkedChecked) reason = theName + " must be checked";
			break;
			
			//if(!theForm[theInput].checked) reason = theName + " must be checked";
			//break;
		case "select-one" :
			if ((theForm[theInput].selectedIndex == -1) || (!theForm[theInput].options[theForm[theInput].selectedIndex].value)) reason = theName + " must be selected from the drop down list";
			break;
		case "select-multiple" :
		
			case "select-multiple" :
				if(!theForm[theInput].options[theForm[theInput].selectedIndex].value) {
					reason = theName + " must be selected from the multi-select list";
				}
			break;
		case "radio" :
			radioChecked = false;
			for(iR=0; iR<theForm[theInput].length; iR++) {
				if(theForm[theInput][iR].checked) radioChecked = true;
			}
			if(!radioChecked) reason = theName + " must be selected";
			break;
		default :
			reason = "";
			break;
	}
	
	if(theType == "text" || theType == "password" || theType == "textarea" || theType == "file") {
		//get the value of the field in question
		var theField = theForm[theInput];
		var theValue = theField.value;
		theValue = theValue.replace(/^\s+/g, '').replace(/\s+$/g, '');
		
		//validate the value with the parameters parsed
		switch(validateName) {
			case "required" :
				switch(validateValue) {
					case "yes" :						
						if((!theValue) || (theValue == '')) reason = ((theName == "") ? theInput : theName) + " cannot be blank";
						break;
					case "no-text" :
						if((!theValue) || (theValue == '')) reason = theName;
						break;
					case "no" :
						//do nothing - not required
						break;
				}
				break;
			case "customvalidation":
				var newFunc = validateValue;
				var args = makeArgumentsObject();
				args.value = theValue;
				args.isValid = true;
				args.errortext = theName;
				args.displayMessage = "";
						
				var funcCall = newFunc + " (theField, args);";
				try
				{
					eval(funcCall);
				}
				catch (exception)
				{
					var exceptionMsg = "";
					if (typeof(exception) == "string")
						exceptionMsg = exception;
					else
						exceptionMsg = exception.message;
					
					alert("Error in custom validation.\n" +
							"Function '" + newFunc + " (sourceField, arguments)' could not be found or has errors.\n"
							+ exceptionMsg);
					reason = theName + " has errors in the custom validation function.";
					break;
				}
				if (args.isValid == false)
				{
					reason = args.displayMessage;
				}
				break;
			case "datatype" :
				switch(validateValue) {
					case "number" :
						if(!uslIsNumber(theValue)) reason = theName + " must be a numeric value";
						break;
					case "email" :
						if(!uslIsEmail(theValue)) reason = theName + " must be a valid email address";
						break;
					case "telephone" :
						if(!uslIsTel(theValue)) reason = theName + " must be a valid telephone number";
						break;
					default:
						//Check for date validation
						var validateValuePart = uslTrimString(validateValue.split("(")[0]);
						if (validateValuePart == "date")
						{
							if (theValue)
							{
								var dateFormat = uslTrimString(validateValue.split("(")[1].split(")")[0]);
								if(!uslIsDate(theValue, dateFormat, null)) reason = theName + " must be a valid date of the format " + dateFormat;
								break;
							}
						}
				}
				break;
			case "compare" :
				var compareType = "";
				var rawCompareValue;
				compareType = uslTrimString(validateValue.split("(")[0]);
				rawCompareValue = uslTrimString(validateValue.split("(")[1].split(")")[0]);

				try
				{				
					var sourceValue = uslConvertType(theValue, dataType);
					compareValue = uslConvertType(rawCompareValue, dataType);
				
					if (sourceValue.toString() != "")
					{
						switch (compareType)
						{
							case "equal":
								if (sourceValue.valueOf() != compareValue.valueOf()) reason = theName + " must be equal to '" + rawCompareValue + "'";
								break;
							case "not equal":
								if (sourceValue.valueOf() == compareValue.valueOf()) reason = theName + " cannot be equal to '" + rawCompareValue + "'";
								break;
							case "greater than":
								if (sourceValue.valueOf() <= compareValue.valueOf()) reason = theName + " must be greater than '" + rawCompareValue + "'";
								break;
							case "greater than equal":
								if (sourceValue.valueOf() < compareValue.valueOf()) reason = theName + " must be greater than or equal to '" + rawCompareValue + "'";
								break;
							case "less than":
								if (sourceValue.valueOf() >= compareValue.valueOf()) reason = theName + " must be less than '" + rawCompareValue + "'";
								break;
							case "less than equal":
								if (sourceValue.valueOf() > compareValue.valueOf()) reason = theName + " must be less than or equal to '" + rawCompareValue + "'";
								break;
							default:
								break;
						}
					}
				}
				catch (e)
				{
					reason = e;
				}
				break;
			case "minvalue" :
				try
				{
					var sourceValue = uslConvertType(theValue, dataType);
					var compareValue = uslConvertType(validateValue, dataType);
					
					if (sourceValue != "")
						if (sourceValue.valueOf() < compareValue.valueOf()) reason = theName + " can only have a minimum value of '" + validateValue + "'";
				}
				catch (e)
				{
					reason = e;
				}
				break;
			case "maxvalue" :
				try
				{
					var sourceValue = uslConvertType(theValue, dataType);
					var compareValue = uslConvertType(validateValue, dataType);
					
					if (sourceValue != "")
						if (sourceValue.valueOf() > compareValue.valueOf()) reason = theName + " can only have a maximum value of '" + validateValue + "'";
				}
				catch (e)
				{
					reason = e;
				}
				break;
			case "regularexpression" :
				if (!doRegExp(theValue, validateValue)) reason = theName + " has failed user defined validation";
				break;
		}
	}
	
	if(reason) reason = "\n" + reason + "   ";
	
	return reason;
}

function uslIsNumber(value) {
	var returnVal = true
	var inputStr = value.toString()
	for (var i = 0; i < inputStr.length; i++)
		{
		var oneChar = inputStr.charAt(i)			
		if ((oneChar < "0" || oneChar > "9") && oneChar != "/" && oneChar != "." && oneChar != "-" && oneChar != ",")
				{
					returnVal = false
				}
		}
	return (returnVal);
}

function uslIsTel(value) {
	var pattern = /\d/;
	if(value) {
		return(pattern.test(value));
	}
	else return true;
}

function doRegExp(strValue, strRegExp) {

  if(strValue) {
	  // are regular expressions supported?
	  var supported = 0;
	  if (window.RegExp) {
	    var tempStr = "a";
	    var tempReg = new RegExp(tempStr);
	    if (tempReg.test(tempStr)) supported = 1;
	  }
	  var result = false;
	  if (!supported) 
	  {
	    alert("Regular Expression are not supported. Validation cannot be performed.")
	    return false;
	  }
	  try
	  {
		if (strRegExp != null)
			var realReg = new RegExp(strRegExp);
			
			result = realReg.test(strValue);
	  }
	  catch (e)
	  {
		alert("Exception caught: your regular expression contains an error.\n" + e.message);
	  }
	  return result;
  }
  else return true;
}

function uslIsEmail(str) {
  if(str) {
	  // are regular expressions supported?
	  var supported = 0;
	  if (window.RegExp) {
	    var tempStr = "a";
	    var tempReg = new RegExp(tempStr);
	    if (tempReg.test(tempStr)) supported = 1;
	  }
	  if (!supported) 
	    return (str.indexOf(".") > 2) && (str.indexOf("@") > 0);
	  var r1 = new RegExp("(@.*@)|(\\.\\.)|(@\\.)|(^\\.)");
	  var r2 = new RegExp("^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");
	  return (!r1.test(str) && r2.test(str));
  }
  else return true;
}

//function uslIsDate(str) {
//	if(str) {
//		dateArray = str.split("/");
//		if(!(dateArray[0] <= 31 && dateArray[0] >= 1)) return false;
//		else if(!(dateArray[1] <= 12 && dateArray[1] >= 1)) return false;
//		else if((!(dateArray[2] <= 40000 && dateArray[2] >= 1960))) return false
//		else return true;
//	}
//	else return true;
//}

function uslTrimString (str) {
  str = this != window? this : str;
  return str.replace(/^\s+/g, '').replace(/\s+$/g, '');
}

function isNumeric(strValue)
{
	var numbers = "1234567890";
	for (var i = 0; i < strValue.length; i++)
	{
		if ( numbers.indexOf ( strValue.charAt (i) ) == -1)
		{
			return false;
		}
	}
	return true;
}

var strMonths = new Array('january','february','march','april','may','june','july','august','september','october','november','december');
var iNumDays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

function uslIsDate(strDate, strFormat, returnDate)
{
	var day;
	var month;
	var year;

	if (strDate == '')
		return false;

	var splitDate = strDate.split('/');

	if (splitDate.length != 3)
		splitDate = strDate.split(' ');

	if (splitDate.length != 3)
		splitDate = strDate.split('-');

	if (splitDate.length != 3)
		splitDate = strDate.split('.');

	if (splitDate.length != 3)
		return false;

	if (strFormat == 'mm/dd/yyyy')
	{
		day = splitDate[1]; month = splitDate[0]; year = splitDate[2];
	}
	else if (strFormat == 'yyyy/mm/dd')
	{
		day = splitDate[2]; month = splitDate[1]; year = splitDate[0];
	}
	else if (strFormat == 'dd/mm/yyyy')
	{
		day = splitDate[0]; month = splitDate[1]; year = splitDate[2];
	}
	else return false;

	if (!isNumeric(day))
		return false;

	if (!isNumeric(year))
		return false;

	if (!isNumeric(month))
	{
		var strCompareMonth = month.toLowerCase();
		for (var i=0; i < 12; i++)
		{
			//Match whole month of the short month (first 3 characters)
			if (strCompareMonth == strMonths[i] || strCompareMonth == strMonths[i].substr(0,3))
			{
				month = i+1;
				i = 13;
			}
		}
	}

	if (!isNumeric(month))
		return false;

	day = parseFloat(day);
	month = parseFloat(month);
	year = parseFloat(year);

	if (month == 2 && (year%400 == 0 || (year%4 == 0 && year%100 != 0)))
		iNumDays[month-1]++;

	if (day < 1 || day > iNumDays[month-1])
		return false;

	if (month < 1 || month > 12)
		return false;

	//Assume 2 digit years are in the year 2000.
	if (year < 100)
		year += 2000;

	if (year < 1000 || year > 10000)
		return false;
		
	//If necessary set the return date.
	if (returnDate != null)
	{
		returnDate.setFullYear (year, month - 1, day);
		returnDate.setHours(0,0,0,0);
	}

	return true;
}