/* **********************************************************************
 * Function:    DaysInMonth
 * Description: Return the number of days in the specified month and year
 * Arguments:   IN     iMonth - the month required
 *              IN     iYear - the year required
 *              RETVAL integer containing the number of days in that month
 */
function DaysInMonth(iMonth, iYear)
{
	switch (iMonth)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			return 31;
			break;
		case 4:
		case 6:
		case 9:
		case 11:
			return 30;
			break;
		case 2:
			if (iYear % 4 == 0 && (iYear % 100 != 0 || iYear % 1000 == 0))
				return 29;
			else
				return 28;
			break;
		default:
			return 0;
	}
}

/* **********************************************************************
 * Function:    isValidDate
 * Description: Decide whether this date (provided as a string) represents
 *              a real date or not
 * Arguments:   IN     sDate - the string required to be tested
 *              RETVAL Boolean saying if it's a valid date
 */
function isValidDate(sDate)
{
	// A date is of the form [0-9]{2}[/-. ][0-9]{2}[/-. ][0-9]{2,4}

	// Make a copy of the input, as a String object
	var sCopyDate = String(sDate);
	// Find out the day part of the date
	var sDay = String(sCopyDate.match(/^[0-9]+[/\-\. ]/));
	if (sDay == "null") return false;
	sDay = sDay.substr(0,sDay.length - 1);
	if (sDay.substr(0,1) == "0")
		var iDay = parseInt(sDay.substr(1));
	else
		var iDay = parseInt(sDay);
	
	if (isNaN(iDay)) return false; // If the day is not a number, this isn't a date
	sCopyDate = sCopyDate.substr(sDay.length + 1);
	var sMonth = String(sCopyDate.match(/^[0-9]+[/\-\. ]/));
	if (sMonth == "null") return false;
	sMonth = sMonth.substr(0,sMonth.length - 1);
	if (sMonth.substr(0,1) == "0")
		var iMonth = parseInt(sMonth.substr(1));
	else
		var iMonth = parseInt(sMonth);
		
	if (isNaN(iMonth)) return false; // If the month is not a number, this isn't a date
	var sYear = sCopyDate.substr(sDay.length + 1);
	if (sYear.substr(0,1) == "0") sYear = sYear.substr(1);
	var iYear = parseInt(sYear);
	if (isNaN(iYear)) return false; // If the year is not a number, this isn't a date
	if (iYear > 0 && iYear < 70) iYear += 2000;
	else if (iYear < 100) iYear += 1900;
	// Check for 3 digit years
	if (iYear > 99 && iYear < 1000)
		return false;
	// Otherwise, see if there's the right number of days here
	if (iDay > DaysInMonth(iMonth, iYear) || iDay <= 0)
		return false;
	else
		return true;
}

/* **********************************************************************
 * Function:    ValidateForm
 * Description: General purpose form validator. Uses expando properties on
 *              the form elements to check for various constraints before
 *              approving the form for submission. Typically this will be
 *              used with onsubmit="return ValidateForm(this)".
 * Arguments:   IN     oForm - the form to be validated
 *              RETVAL Boolean saying if everything is valid
 */
function ValidateForm(oForm)
{
	// Loop through all the elements on the form, testing their values and properties
	var oElements = oForm.elements;
	var iLen = oElements.length;
	for (var i = 0; i < iLen; i++)
	{
		var oElement = oElements[i];
		// Ignore disabled fields
		if (false == oElement.disabled)
		{
			// Check required radio button fields first
			if (oElement.required == "true" && oElement.type == "radio")
			{
				var bFound = false;
				for (var j = 0; j < oForm.elements(oElement.name).length; j++)
				{
					if (oForm.elements(oElement.name)[j].checked == true)
					{
						bFound = true;
						break;
					}
				}
				if (!bFound)
				{
					if (oElement.getAttribute("missingMessage") != null || oElement.getAttribute("message") != null)
					{
						if (oElement.getAttribute("missingMessage") != null)
							alert(oElement.getAttribute("missingMessage"));
						else
							alert(oElement.getAttribute("message"));
					}
					else
						alert("Error: You must select a value for the '" + oElement.name + "' field.");
					try
					{
						oElement.focus();
					}
					catch (e)
					{
						// don't panic!
						e = "";
					}
					finally
					{
						return false;
					}
				}
			}
			// Check maximum length first
			if (parseInt(oElement.maxlength) < new String(oElement.value).length)
			{
				alert("Error: The maximum length for the '" + oElement.name + "' field is " + oElement.maxlength + " characters.");
				try
				{
					oElement.focus();
				}
				catch (e)
				{
					// don't panic!
					e = "";
				}
				finally
				{
					return false;
				}
			}
			// Check regular required fields next
			if (oElement.required == "true" && (oElement.value == "" || (oElement.type == "checkbox" && !oElement.checked)))
			{
				if (oElement.getAttribute("missingMessage") != null || oElement.getAttribute("message") != null)
				{
					if (oElement.getAttribute("missingMessage") != null)
						alert(oElement.getAttribute("missingMessage"));
					else
						alert(oElement.getAttribute("message"));
				}
				else
					alert("Error: You must enter a value for the '" + oElement.name + "' field.");
				try
				{
					oElement.focus();
				}
				catch (e)
				{
					// don't panic!
					e = "";
				}
				finally
				{
					return false;
				}
				return false;
			}
			// Check for a regular expression required
			var sRegExp = oElement.regexp;
			if (sRegExp)
			{
				var sStType = String(sRegExp);
				// Do some quick replacements
				switch (sStType.toLowerCase())
				{
					case "number":
						var sStRegExp = "^[+\\-]?(\\d*(\\.\\d+)|\\d+)$";
						break;
					case "positivenumber":
						var sStRegExp = "^(\\d)*(\\.\\d+)?$";
						break;
					case "integer":
						var sStRegExp = "^[+\\-]?\\d+$"; // "![^0-9+\\-]";
						break;
					case "positiveinteger":
						var sStRegExp = "^\\d*$";
						break;
					case "currency":
						var sStRegExp = "^[+\\-]?(\\d*(\\.\\d{2})|\\d+)$";
						break;
					case "positivecurrency":
						var sStRegExp = "^(\\d*(\\.\\d{2})|\\d+)$";
						break;
					case "date":
						var sStRegExp = "^[0-3]?[0-9][/\\-\\. ][0-1]?[0-9][/\\-\\. ][0-9]{2,4}$";
						break;
					case "email":
						var sStRegExp = "^[^ @]+@[^ \\.]+\\.[^ ]+$";
						break;
					case "lchemail":
						var sStRegExp = "^([^ ]+.[^ ]+@lch\\.com|[^ \\.]+@lch\\.co\\.uk)$";
						break;
					case "url":
						var sStRegExp = "^(http(s)?|ftp)://[^ ]*(/.*)?$";
						break;
					default:
						// Catch real regular expressions
						var sStRegExp = sStType;
						sStType = "unknown";
						break;
				}
				// *********
				// If there's a regular expression, check for it (and required) and if the RegExp begins with !, treat this
				// as a NOT command, and verify its absence
				if (sRegExp && (sStRegExp.substr(0,1) != "!" && !oElement.value.match(new RegExp(sStRegExp)) ||
						sStRegExp.substr(0,1) == "!" && oElement.value.match(new RegExp(sStRegExp.substr(1)))) &&
						!(oElement.value == "" && oElement.required != "true"))
				{
					if (oElement.getAttribute("formatMessage") != null || oElement.getAttribute("message") != null)
					{
						if (oElement.getAttribute("formatMessage") != null)
							alert(oElement.getAttribute("formatMessage"));
						else
							alert(oElement.getAttribute("message"));
					}
					else
						alert("Error: The value you entered for the '" + oElement.name + "' field is not in the required format.");
					try
					{
						oElement.focus();
					}
					catch (e)
					{
						// don't panic!
						e = "";
					}
					finally
					{
						return false;
					}
				}
				// If this is a date check, check for it being a valid date
				if (sStType.toLowerCase() == "date" && !isValidDate(oElement.value) && !(oElement.value == "" && oElement.required != "true"))
				{
					if (oElement.getAttribute("formatMessage") != null || oElement.getAttribute("message") != null)
					{
						if (oElement.getAttribute("formatMessage") != null)
							alert(oElement.getAttribute("formatMessage"));
						else
							alert(oElement.getAttribute("message"));
					}
					else
						alert("Error: The value you entered for the '" + oElement.name + "' field is not a valid date.");
					try
					{
						oElement.focus();
					}
					catch (e)
					{
						// don't panic!
						e = "";
					}
					finally
					{
						return false;
					}
				}
			}
		}
	}
	return true;
}