var VM_objFirstErrorElement ; // holds reference to invalid element, for focus method ;
var VM_strCustomError = "invalid data"; // used by custom validation functions ;

function VM_isValidByRegExp(strTestValue, strRegExp)
{
	var blnReturn = true;
	var x ;
	eval( "x=strTestValue.search(" + strRegExp + ");" ); // e.g. x=strTextValue.search(/(\w+)/i);
	if (x == -1)
	{
		blnReturn = false;
	}
	return blnReturn;
}

function VM_isSSN(strValue) 
{
	var blnReturn;
	var regPattern = /^\s*\d{3}\-?\d{2}\-?\d{4}\s*$/ ; // " NNN-NN-NNNN " (spaces and dashes optional) ;
	blnReturn = regPattern.test(strValue);
	return blnReturn;
}

function VM_isDecimal(strValue) 
{
	var blnReturn = true;
	var regPattern = /^\d*\.?\d*$/;
	blnReturn = regPattern.test(strValue);
	return blnReturn;
}

function VM_isInteger(strNumber) {
	var blnReturn = true;
	if (strNumber.search(/\D/g) >= 0) { // if a non-digit is in string... ;
		blnReturn = false;
	}
	return blnReturn;
}

function VM_isDate(strInput) 
{
	// require the format "mm/dd/yyyy" ;
	var objDate ;
	var intMonth ;
	var expPattern = /^(\d{6})|(\d{8})|(((12|11|10|[1-9])|(0\d))(\/|\-)(31|30|([12]\d)|(0?[1-9]))\7(19|20)?(\d{2}))$/i ; 
	// Test for Landstar-required date format... ;
	if ( !expPattern.test(strInput) ) 
	{
		return false;
	}
	// If all digits, add slashes to support Date.parse() ... ;
	expPattern = /^\d{6}|\d{8}$/i ; 
	if ( expPattern.test(strInput) ) 
	{
		strInput = strInput.substring(0, 2) + "/" + strInput.substring(2, 4) + "/" + strInput.substring(4) ;
	}
	// If dashes, change to slashes... ;
	if (strInput.indexOf("-") != -1)
	{
		strInput = strInput.replace(/-/g, "/") ;
	}
	// Test for actual calendar dates (e.g. not 2/30/1976 nor 2/29/1977) ;
	if ( isNaN(Date.parse(strInput)) ) 
	{
		return false ;
	} 
	else 
	{ 
		objDate = new Date(strInput); 
		if ( objDate.getMonth()+1 != parseInt(strInput.substring(0, strInput.indexOf("/")), 10) ) 
		{
			return false ;
		}
	}
	return true;
} // end function VM_isDate ;

function VM_isTime(strInput) 
{
	var expPattern;
	if ( (strInput.toLowerCase().indexOf("a") != -1) || (strInput.toLowerCase().indexOf("p") != -1) ) 
	{
		expPattern = /^((12|11|10)|((0)?\d)):[0-5][0-9]\s?(am|pm|a.m.|p.m.)$/i ; 
	} 
	else 
	{
		expPattern = /^((12|11|10|\d)|((0)?\d))(:)?[0-5][0-9]$/;
	}
	if (expPattern.test(strInput)) 
	{
		return true;
	} 
	else 
	{
		return VM_is24HrTime(strInput); // is it military time? ;
	}
} // end function VM_isTime ;

function VM_is24HrTime(strInput) 
{
	var expPattern = /^((2[0-3])|(1[0-9])|((0)?\d))(:)?[0-5][0-9]$/ ;
	return expPattern.test(strInput);
}

function VM_isZip(strValue)
{   // follows validation rule from SV4, with improved regexp ;
	var blnReturn = true;
	var regPattern;
	regPattern = /^[A-Za-z0-9][A-Za-z0-9 -]{4,}$/ ; 
	if ( !regPattern.test(strValue) ) {
		blnReturn = false;
	}
	return blnReturn;
}

function VM_isURL(strValue)
{   // the regular expression in this function was adapted from SV4 code ;
	// updated the regular expression to accept website name like www.landstar.com/rlov/abc instead 
	// of just www.landstar.com
	var blnReturn = true;
	var regPattern;
	// regPattern = /^((http|HTTP):\/\/)?[A-Za-z0-9]+(-[A-Za-z0-9]+)*(\.[A-Za-z0-9]+(-[A-Za-z0-9]+)*)*\.[A-Za-z]{2,3}(\/[A-Za-z0-9]+(-[A-Za-z0-9]+)*)?(\/[A-Za-z0-9]+(-[A-Za-z0-9]+)*)?$/ ; 
	// from Visual Studio.NET -- regPattern = ((http|HTTP):\/\/)?([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)? ;
	regPattern = /^((http|HTTP):\/\/)?([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?$/ ; // TEST THIS !
	if ( !regPattern.test(strValue) ) {
		blnReturn = false;
	}
	return blnReturn;
}

function VM_checkPhone(strNumber, aryErrors, strComment, strName, strOneOrMany, e, blnAllow800, blnAllow900, blnRequire800) {
	var strTollFree = "|800|888|877|866|"; // list of acceptable toll-free area codes ;
	var regPattern;
	var strArea;
	var blnReturn = true;
	var strProblem = "";
	var strCommentDefault = "";
	if (arguments.length < 8 || blnAllow800 == null) {
		blnAllow800 = false; // default value for optional argument; 
	}
	if (arguments.length < 9 || blnAllow900 == null) {
		blnAllow900 = false; // default value for optional argument;
	}
	if (arguments.length < 10 || blnRequire800 == null) {
		blnRequire800 = false; // default value for optional argument;
	}
	regPattern = /^\(?\d{3}\)? ?-? ?\d{3} ?-? ?\d{4}$/ ; // e.g. 904-555-1212 or (904)555-1212 or 9045551212 ;
	if ( !regPattern.test(strNumber) ) {
		blnReturn = false;
		strProblem = "invalid";
	} 
	strArea = VM_getDigits(strNumber).substring(0, 3); 
	if (!blnAllow800) { 
		if (strTollFree.indexOf("|"+strArea+"|") != -1) {
			blnReturn = false;
			strProblem += "|800|"; // "must not be a toll-free number";
		}
	}
	if (!blnAllow900) {
		if (strArea == "900") {
			blnReturn = false;
			strProblem += "|900|"; // "'900' phone numbers are not allowed";
		}
	}
	if (blnRequire800) {
		if (strTollFree.indexOf("|"+strArea+"|") == -1) {
			blnReturn = false;
			strProblem += "|no8xx|"; // "must be a toll-free number";
		}
	}
	if (!blnReturn) { // register error -- indicate reason for failure ;
		if (strProblem.indexOf("invalid") != -1) {
			strCommentDefault = "must be a 10-digit telephone number" ; 
			if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
			{
				return false ; // error was presented to user, not added to array... end validation;
			} 			
		}
		if (strProblem.indexOf("800") != -1) {
			strCommentDefault = "toll-free phone numbers are not allowed" ; 
			if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
			{
				return false ;
			} 			
		}
		if (strProblem.indexOf("900") != -1) {
			strCommentDefault = "'900' phone numbers are not allowed" ; 
			if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
			{
				return false ;
			} 			
		}
		if (strProblem.indexOf("no8xx") != -1) {
			strCommentDefault = "must be a toll-free number" ; 
			if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
			{
				return false ;
			} 			
		}
 	}
	return true; // indicates that errors were handled (added to array), if any... ;
} // end function VM_checkPhone ;

function VM_checkEmail(strValue, aryErrors, strComment, strName, strOneOrMany, e)
{   // the validation portions of this function were adapted from SV4 code ;
	var blnReturn = true;
	var Pos1;
	var strCommentDefault= "";
	// check for multiple addresses...
	if (strValue.length > 0) {
		Pos1 = strValue.indexOf("@");
		if (Pos1 > 0) {
			Pos1 = strValue.indexOf("@", Pos1 + 1);
			if (Pos1 > 0) {
				// register the error, if any... ;
				strCommentDefault = "enter only one e-Mail address in this field"; 
				if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) {
					return false ; // error was presented to user, not added to array... end validation;
				} 			
			}	
		}
	}
	// check the format...
	if (strValue.length > 0) {
		// Pos1 = strValue.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z]{2,4}$/);
		// from Visual Studio.NET -- \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
		Pos1 = strValue.search(/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/);
		if (Pos1 < 0) {
			// register the error, if any... ;
			strCommentDefault = "must be a valid e-mail address (e.g. a@b.com)" ; 
			if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) {
				return false ; // error was presented to user, not added to array... end validation;
			}
		}
	}
	return blnReturn;
}

function VM_getDigits(strValue) 
{ // returns only the digit characters from a string;
	strValue = strValue.replace(/\D/g, ""); 
	return strValue;
}

function VM_showError(e, strName, strError) 
{
	alert("INVALID DATA\n\nPlease correct the following invalid data:\n\n -- " + strName + ": " + strError);
	e.focus();
	e.select();
}

function VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault) 
{
	var blnReturn = false;
	if (arguments.length > 5) 
	{	// use default commment, if supplied, and if primary comment is empty ;
		strComment = (strComment.length > 0) ? strComment : strCommentDefault ;
	}
	if ( (arguments.length < 5) || (strOneOrMany == "many") ) 
	{
		aryErrors["element"][aryErrors["element"].length] = strName;
		aryErrors["problem"][aryErrors["problem"].length] = strComment;
		blnReturn = true;
	} 
	else 
	{
		VM_showError(e, strName, strComment);
		blnReturn = false;
	}
	if (VM_objFirstErrorElement == "empty")
	{
		VM_objFirstErrorElement = e ;
	}
	return blnReturn;
} // end function VM_addError ;

function validateMain(strOneOrMany, strPreferredErrorMessage)
{
	var strErrorMessageHeadline ;
	var f ;
	var e ;
	var strS ;
	var strEType ;
	var strType ;
	var intSize ;
	var intMin ;
	var intMax ;
	var strName ;
	var strComment ;
	var strCommentDefault ;
	var strCommentFinal ;
	var strRegExp ;
	var strFunction ; // custom function name ;
	var blnFunction ; // result from custom function ;
	var blnAllow800s = false ;
	var blnAllow900s = false ;
	var blnRequire800s = false ;
	var blnSelectRequired = false;
	var blnSelectNotFirst = false;
	var strRequired = "";
	var aryErrors = new Array();
		aryErrors["element"] = new Array();
		aryErrors["problem"] = new Array(); 
	var strErrors = "" ;
	VM_objFirstErrorElement = "empty" ;
	// Default value to decide whether to respond to errors individually or as a group... ;
	if ( !strOneOrMany || (strOneOrMany.length == 0) || (strOneOrMany.toLowerCase() == "one") ) 
	{ 
		strOneOrMany = "one" ;
	} else {
		strOneOrMany = "many" ;
	}
	// Loop through all forms... ;
	for (var i = 0; i < document.forms.length; i++) 
	{
		f = document.forms[i];
		// Loop through all elements in each form... ;
		for (var j = 0; j < f.elements.length; j++) 
		{	// Check each element... ;
			e = f.elements[j];

			// get properties that apply to multiple types... ;
			strEType = e.type;
			strName = "";
			strType = "";
			strComment = "";
			if (e.valName) 
			{
				strName = e.valName ; 
			}
			if (e.valType) 
			{
				strType = e.valType.toLowerCase() ; 
			}
			if (e.valComment) 
			{
				strComment = e.valComment ; 
			}
			
			// deal with select lists... ;
			if (strEType == "select-one" || strEType == "select-multiple") 
			{
				strRequired = (e.valRequired) ? e.valRequired.toLowerCase() : null ;
				if (strRequired) {
					blnSelectRequired = (strRequired == "true") ? true : false ; 
					blnSelectNotFirst = (strRequired == "notfirstoption") ? true : false ; 
				} 
				if ( (blnSelectRequired && (e.selectedIndex == -1)) || (blnSelectNotFirst && (e.selectedIndex < 1)) ) 
				{	
						strCommentDefault = "a selection is required" ; 
						if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
						{
							return false ;
						}
				}
			}

			// Carry out various checks for text fields... ;
			if (strEType == "text" || strEType == "textarea") 
			{			
				strValue = e.value;
				intSize = 0;
				intMin	= 0;
				intMax	= 0;
				strRegExp = "";
				if (e.valSize) 
				{
					intSize = parseInt(e.valSize, 10) ; 
				}
				if (e.valMin) 
				{
					intMin = parseFloat(e.valMin) ; // have to parse so that 999 < 1000 ;
				}
				if (e.valMax) 
				{
					intMax = parseFloat(e.valMax) ; 
				}
				if (e.valRegExp)
				{
					strRegExp = e.valRegExp ;
				}
				if (e.valFunction) 
				{
					strFunction = e.valFunction ; 
				}
				if (e.valAllow800s)
				{
					blnAllow800s = (e.valAllow800s != "false") ? true : false ; 
					blnRequire800s = (e.valAllow800s == "required") ? true : false ; 
				}
				if (e.valAllow900s)
				{
					blnAllow900s = (e.valAllow900s != "false") ? true : false ;
				}
				if (strValue.length == 0 ) 
				{
					if (e.valRequired && e.valRequired != "false")
					{
						strCommentDefault = "a value is required" ; 
						strCommentFinal = (strComment.length > 0) ? strComment : strCommentDefault ;
						if (!VM_addError(aryErrors, strName, strCommentFinal, strOneOrMany, e)) 
						{
							return false ; // error was presented to user, not added to array... end validation;
						}
					}
				}
				else // strValue.length != 0 ;
				{
					switch(strType) 
					{
					case "function": 
						blnFunction = eval(strFunction + "(e)"); // pass element to custom function ;
						if (!blnFunction) 
						{
							strCommentDefault = VM_strCustomError // "must pass custom validation function" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ; // error was presented to user, not added to array... end validation;
							}
						}
						break;
					case "regexp": 
						if (!VM_isValidByRegExp(strValue, strRegExp))
						{ 
							strCommentDefault = "must have the correct pattern of characters" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "email": 
						if (!VM_checkEmail(strValue, aryErrors, strComment, strName, strOneOrMany, e)) 
						{
							return false ; // VM_checkEmail handles error registration internally;
						}
						break;
					case "phone": 
						if (!VM_checkPhone(strValue, aryErrors, strComment, strName, strOneOrMany, e, blnAllow800s, blnAllow900s, blnRequire800s)) 
						{ 
							return false; // VM_checkPhone handles error registration internally;
						}
						break;
					case "zip": 
						if (!VM_isZip(strValue)) 
						{
							strCommentDefault = "must be a valid code of at least 5 characters (e.g. 32224)" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "url": 
						if (!VM_isURL(strValue)) 
						{
							strCommentDefault = "must be a valid web site address (e.g. www.internic.com)" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "ssn": 
						if (!VM_isSSN(strValue)) 
						{
							strCommentDefault = "must be a valid Social Security Number (e.g. 123-45-6789)" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "date": 
						if (!VM_isDate(strValue)) 
						{
							strCommentDefault = "must be a valid date in the format mm/dd/yyyy" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "time":
						if (!VM_isTime(strValue)) 
						{
							strCommentDefault = "must be a time in military format (hhmm)" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "number":
						if (!VM_isDecimal(strValue)) 
						{
							strCommentDefault = "must be a number" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMin > 0 && strValue < intMin) 
						{
							strCommentDefault = "minimum value of "+intMin+" required" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMax > 0 && strValue > intMax) 
						{
							strCommentDefault = "maximum value of "+intMax+" allowed" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "integer":
						if (!VM_isInteger(strValue))
						{   
							strCommentDefault = "must be an integer" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMin > 0 && strValue < intMin) 
						{
							strCommentDefault = "minimum value of "+intMin+" required" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMax > 0 && strValue > intMax) 
						{
							strCommentDefault = "maximum value of "+intMax+" allowed" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					case "string":
						if (intSize > 0 && strValue.length > intSize) 
						{
							strCommentDefault = "only "+intSize+" characters allowed" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMin > 0 && strValue.length < intMin) 
						{
							strCommentDefault = "at least "+intMin+" characters required" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						if (intMax > 0 && strValue.length > intMax) 
						{
							strCommentDefault = "a maximum of "+intMax+" characters allowed" ; 
							if (!VM_addError(aryErrors, strName, strComment, strOneOrMany, e, strCommentDefault)) 
							{
								return false ;
							}
						}
						break;
					default:
						// no recognized type specified... do nothing;
						break;
					} // end switch(strType) ;
				} // end if...else (empty value) ;
			} // end if (text or textarea) ;
		} // end for (each element) ;
	} // end for (each form) ;
	// Build and display error message... ;
	if (aryErrors["element"].length > 0) 
	{
		for (var k = 0; k < aryErrors["element"].length; k++) 
		{
			strErrors += " -- " + aryErrors["element"][k] + ": " + aryErrors["problem"][k] + "\n"
		}
		strS = (aryErrors["element"].length > 1) ? "s" : "" ;
		strErrorMessageHeadline = "Please correct the data in the following field"+strS+":\n\n" ; // for alert message at end ;
		if (strPreferredErrorMessage) 
		{
			strErrorMessageHeadline = strPreferredErrorMessage + "\n\n" ;
		}
		VM_objFirstErrorElement.focus();
		VM_objFirstErrorElement.select();
		alert(strErrorMessageHeadline + strErrors);
		VM_objFirstErrorElement = null;
		return false;
	} // end if
	return true;
} // end function validateMain();
