var alertMessage = "alertmessage";
var alertMessageText = "Please fill in the required values then re-submit.";
var alertMessageDisplayStyle = "block";
var alertCssClassName = "alert";
var defaultCssClassName = "default";

function validateForm(theForm, elementsList)
{
	var retVal = 0;
	
	// clear alert message...
	clearAlertMessage();

	// if the elementsList is null, check to see if there is an elementslist hidden field.
	// if elementsList is still null, the do a basic validation of, text, select, textarea, and password fields.
	if (elementsList == null)
	{
		if (theForm.elementslist == null)
		{
			for (var i=0; i<theForm.elements.length; i++)
			{
				if (theForm.elements[i].type != null)
				{
					if (theForm.elements[i].type == "text" || theForm.elements[i].type == "select-one" || theForm.elements[i].type == "textarea" || theForm.elements[i].type == "select-multiple" || theForm.elements[i].type == "password")
					{
						if (elementsList == null) 
							elementsList = theForm.elements[i].name;
						else
							elementsList += ";" + theForm.elements[i].name;
					}
				}
			}
		}
		else
		{
			elementsList = theForm.elementslist.value;
		}
	}

	var theElements = elementsList.split(";")
	for (var i=0; i<theElements.length; i++)
	{
		var x = theElements[i];
		if (theElements[i].indexOf(":") > -1)
		{
			if (!validateField(theForm.elements[theElements[i].substring(0, theElements[i].indexOf(":"))], theElements[i].substring(theElements[i].indexOf(":")+1, theElements[i].length)))
				retVal++;
		}
		else
		{
			if (!validateField(theForm.elements[theElements[i]]))
				retVal++;
		}
	}

	if (retVal != 0)
	{
		// set alert message...
		setAlertMessage();
	}

	return retVal == 0;
}

function validateField(theField, args, clearAlertMessageStatus)
{
	if (clearAlertMessageStatus == true)
		clearAlertMessage();
	
	var alertElement = "";
	if (theField.length != null && theField[0].type == "radio")
		alertElement = theField[0].name;
	else
		alertElement = theField.id;
	clearAlertStatus(alertElement);
	
	var retVal = 0;
	var theForm = theField.form;
	if (args != null && args != "")
	{
		var tmpArray = args.split(":");
		switch (tmpArray.length)
		{
			case 3:
				if (tmpArray[1] == "compare")
				{
					// 2nd parameter: required = 1, 3rd parameter specifies datatype, fourth is the field to compare against..
					if (!isValid(getValue(theField), "1", "compare", getValue(theForm.elements[tmpArray[2]])))
						retVal++;
				}
				else
				{
					// 2nd parameter: required = 1 or not required = 0, 3rd parameter specifies datatype, fourth is a custom regex string...
					if (!isValid(getValue(theField), tmpArray[0], tmpArray[1], tmpArray[2]))
						retVal++;
				}
				break;
				
			case 2:
				if (!isValid(getValue(theField), tmpArray[0], tmpArray[1]))
					retVal++;
				break;
				
			case 1:
				if (!isValid(getValue(theField), "1", tmpArray[0]))
					retVal++;
				break;
				
			default:
				if (isEmptyString(getValue(	theField)))
					retVal++;
		}
	}
	else
	{
		if (isEmptyString(getValue(	theField)))
			retVal++;
	}
	
	if (retVal != 0)
	{
		if (theField.length != null && theField[0].type == "radio")
			setAlertStatus(alertElement);
		else
			setAlertStatus(alertElement);
	}

	return retVal == 0;
}

// returns the value of the element depending on input element type...
function getValue(theElement)
{
	var retVal = "";
	switch (theElement.type)
	{
		case "select-one":
			retVal = theElement.options[theElement.selectedIndex].value;
			break;

		case "select-multiple":
			for (var i=0; i<theElement.options.length; i++)
			{
				if (theElement.options[i].selected)
				{
					if (retVal != "") retVal += ",";
						retVal += theElement.options[i].value;
				}
			}
			break;

		case "text":
			retVal = theElement.value;
			break;

		case "hidden":
			retVal = theElement.value;
			break;

		case "password":
			retVal = theElement.value;
			break;

		case "textarea":
			retVal = theElement.value;
			break;

		default:
		if (theElement.length)
		{
			// radio???
			if (theElement[0].type == "radio")
			{
				for (var i=0; i<theElement.length; i++)
				{
					if (theElement[i].checked)
					{
						retVal = theElement[i].value;
						break;
					}
				}
			}
		}
	}
	return retVal;
}

function isValid(stringValue, required, dataType, arg4)
{
	if (required == "0" && isEmptyString(stringValue))
	{
		// it's not required, so empty is ok...
		return true;
	}
	else if (required == "1" && isEmptyString(stringValue))
	{
		// it's required, so empty is NOT ok...
		return false;
	}
	else
	{
		// whether it's required or not, make sure the data is correct...
		switch (dataType)
		{
			case "maxlength":
				return stringValue.length <= parseInt(arg4);
				break;
				
			case "email":
				return isMatch(stringValue, /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/);

			case "emaillist":	// comma separated list of email addresses...
				var pattern = /[\s,]+/g;	// replace all whitespace and/or commas with delimiter '|'...
				var tmpEmailString = stringValue.replace(pattern,"|");
				pattern = /[\|]$/;			// replace delimiter '|' at end of line with nothing...
				tmpEmailString = tmpEmailString.replace(pattern,"");
				var tmpEmailArray = tmpEmailString.split("|");
				var err = 0;
				for (var i=0; i<tmpEmailArray.length; i++)
				{
					if (!isMatch(tmpEmailArray[i], /^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/))
						err++;
				}
				return err == 0;
			
			case "date":
				switch (arg4)
				{
					case "mm-dd-yyyy":
						if (isMatch(stringValue, /^\d{1,2}-\d{1,2}-\d{4}$/))
						{
							var tmpVal = stringValue.split("-");
							return isValidDate(tmpVal[0], tmpVal[1], tmpVal[2]);
						}
						else
						{
							return false;
						}

					case "yyyy-mm-dd":
						if (isMatch(stringValue, /^\d{4}-\d{1,2}-\d{1,2}$/))
						{
							var tmpVal = stringValue.split("-");
							return isValidDate(tmpVal[1], tmpVal[2], tmpVal[0]);
						}
						else
						{
							return false;
						}
					
					default:	// mm/dd/yyyy
						if (isMatch(stringValue, /^\d{1,2}\/\d{1,2}\/\d{4}$/))
						{
							var tmpVal = stringValue.split("/");
							return isValidDate(tmpVal[0], tmpVal[1], tmpVal[2]);
						}
						else
						{
							return false;
						}
				}
	
			case "phone":
				return isMatch(stringValue, /(((((^[(](\d{3})[)][ ]?)|(^\d{3})[- ]))(\d{3})[- ](\d{4}))|(\d{10})|(\d{3}\.\d{3}\.\d{4}))(.){0,13}$/);
	
			case "zip":
				return isMatch(stringValue, /^\d{5}(-\d{4})?$/);

			case "ssn":
				return isMatch(stringValue, /^\d{3}-\d{2}-\d{4}$|^\d{3}\d{2}\d{4}$/);
				
			case "numeric":
				return !isNaN(stringValue);
	
			case "integer":
				alert("TODO: function isValid(stringValue, integer);");
				return false;
				//return !isNaN(parseInt(stringValue)); -- doesn't work...
	
			case "float":
				alert("TODO: function isValid(stringValue, float);");
				return false;
				//return !isNaN(parseFloat(stringValue)); -- doesn't work...
	
			case "currency":
				alert("TODO: function isValid(stringValue, currency);");
				return false;

			case "compare":
				return stringValue == arg4;
			
			case "regexp":
				return isMatch(stringValue, arg4);
		}
	}
}

function isEmptyString(stringValue)
{
	var tmp = "";
	if (stringValue != "")
	{
		for (var i=0; i<stringValue.length; i++)
		{
			if (stringValue.charAt(i) != " ")
				tmp += stringValue.charAt(i);
		}
	}
	return tmp.length == 0;
}

function isMatch(stringValue, regexString)
{
	var regex = new RegExp(regexString);
	var matches = regex.exec(stringValue);
	return (matches != null && stringValue == matches[0]);
}

function isValidEmail(stringValue)
{
	if (isEmptyString(stringValue))
			return false;
	var regex = new RegExp(/^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/);
	var matches = regex.exec(stringValue);
	return (matches != null && stringValue == matches[0]);
}

function isValidDate(month, day, year)
{
	if (!(parseInt(month, 10) > 0 && parseInt(month, 10) < 13))
		return false;
	else if (!(parseInt(day, 10) > 0 && parseInt(day, 10) < getDays(parseInt(month, 10), parseInt(year, 10))+1))
		return false;
	else if (!(parseInt(year, 10) > 1899 && parseInt(year, 10) < 2026))
		return false;
	else
		return true;
}

function getDays(m, y)
{
	var daysInMonth = new Array(12);	// makeArray(12);
	daysInMonth[0] = 31;
	daysInMonth[1] = februaryDays(y);
	daysInMonth[2] = 31;
	daysInMonth[3] = 30;
	daysInMonth[4] = 31;
	daysInMonth[5] = 30;
	daysInMonth[6] = 31;
	daysInMonth[7] = 31;
	daysInMonth[8] = 30;
	daysInMonth[9] = 31;
	daysInMonth[10] = 30;
	daysInMonth[11] = 31;
	
	return daysInMonth[parseInt(m) -1];
}

function februaryDays(year)
{   
	// February has 29 days in any year evenly divisible by four, EXCEPT for centurial years which are not also divisible by 400.
	return (((year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28);
}

function setAlertStatus(elementId)
{
	// find any element intended to be an alert notification by looking for the 'alert_' prefix + element id, otherwise use the element itself...
	if (document.getElementById("alert_" + elementId))
	{
		document.getElementById("alert_" + elementId).className = alertCssClassName;
	}
	else
	{
		if (document.getElementById(elementId) != null)
			document.getElementById(elementId).className = alertCssClassName;
	}
}

function clearAlertStatus(elementId)
{
	// clear the label or element...
	if (document.getElementById("alert_" + elementId) != null)
	{
		if (document.getElementById("alert_" + elementId).className == alertCssClassName)
			document.getElementById("alert_" + elementId).className = defaultCssClassName;
	}
	else if (document.getElementById(elementId) != null)
	{
		if (document.getElementById(elementId).className == alertCssClassName)
			document.getElementById(elementId).className = defaultCssClassName;
	}
}

function setAlertMessage()
{
	// set alert message...
	if (document.getElementById(alertMessage) != null)
	{
		if (isEmptyString(document.getElementById(alertMessage).innerHTML))
		{
			document.getElementById(alertMessage).innerHTML = alertMessageText;
		}
		document.getElementById(alertMessage).className = alertCssClassName;
		document.getElementById(alertMessage).style.display = alertMessageDisplayStyle;
	}
	else
	{
		alert(alertMessageText);
	}
}

function clearAlertMessage()
{
	// clear alert message...
	if (document.getElementById(alertMessage) != null)
	{
		if (document.getElementById(alertMessage).style.display == alertMessageDisplayStyle)
			document.getElementById(alertMessage).style.display = "none";
	}
}