/* **********************************************************
   FUNCTION: isAfterToday
   PURPOSE:  Validate that a date is after today's date
   INPUTS:	 strDate: Date (in String format) to test
   RETURNS:  True if date is later than today's date;
             False if date is today or earlier.
   ******************************************************** */
function isAfterToday(objField) {
	var strDate = objField.value;
	
	if (! isDate(strDate)) {
		return false;
	}
	
	var dtInput = new Date(strDate);
	var dtNow = new Date();
	dtInput.setHours(0,0,0,0);
	dtNow.setHours(0,0,0,0);

	return (dtInput > dtNow);
}

/* **********************************************************
   FUNCTION: toggleField
   PURPOSE:  Enable or disable a form field, optionally
			 setting the background color if applicable
   INPUTS:	 objField:   Form field to enable/disable
			 bolOn:      Boolean indicating whether
			             field is to be enabled
			 strBgColor: Desired background color of
			             field; optional
   RETURNS:  True
   ******************************************************** */
function toggleField(objField, bolOn, strBgColor) {
	if (bolOn) {
		// turn it on, then set color
		objField.disabled = false;
		if (typeof(strBgColor) != "undefined" && strBgColor.length > 0 && typeof(objField.style) != "undefined") {
			objField.style.backgroundColor = strBgColor;
		}
	}
	else {
		// set color, then turn it off
		if (typeof(strBgColor) != "undefined" && strBgColor.length > 0 && typeof(objField.style) != "undefined") {
			objField.style.backgroundColor = strBgColor;
		}
		objField.disabled = true;
	}
	return true;
}


/* **********************************************************
   FUNCTION: selectedIndexOf
   PURPOSE:  Return single selectedIndex of a radio group,
   			 checkbox group, or select control
   INPUTS:	 objField: Form field to check
   RETURNS:  Int value of first selected index; -1 if none
   NOTES:	 Has array version for multi-select controls, 
   			 selectedIndices(objField)
   			 
   			 Name includes 'Of' at end to avoid clashing
   			 with JavaScript property 'selectedIndex'
   ******************************************************** */
function selectedIndexOf(objField) {
	var k;
	
	if (typeof(objField.selectedIndex) != "undefined") {
		return objField.selectedIndex;
	}
	else {
		for (k = 0; k < objField.length; k++) {
			if (objField[k].checked) {
				return k;
			}
		}
	}
	return -1;
}


/* **********************************************************
   FUNCTION: selectedIndices
   PURPOSE:  Return selected indexes of a checkbox group or
   			 multi-select selection control
   INPUTS:	 objField: Form field to check
   RETURNS:  Array of integers indicating selected indexes
   			 in control or control group; empty array if
   			 none selected
   NOTES:	 Has scalar version for single-select controls
   			 (including radio controls),
   			 selectedIndexOf(objField)
   ******************************************************** */
function selectedIndices(objField) {
	var k;
	var aryRet = new Array();
	
	if (typeof(objField.selectedIndex) != "undefined") {
		// build selected array
		for (k = 0; k < objField.options.length; k++) {
			if (objField.options[k].selected) {
					aryRet[aryRet.length] = k;
			}
		}
	}
	else {
		// build checked array
		for (k = 0; k < objField.length; k++) {
			if (objField[k].checked) {
					aryRet[aryRet.length] = k;
			}
		}
	}
	return aryRet;
}


/* **********************************************************
   FUNCTION: selectedValue
   PURPOSE:  Return value of selected option in a checkbox
   			 group, radio button group or single-select
   			 selection control
   INPUTS:	 objField: Form field to check
   RETURNS:  String, 'value' attribute of selected index 
   			 of control; empty string if no selection
   NOTES:	 Has array version for multi-select controls,
   			 selectedValues(objField)
   ******************************************************** */
function selectedValue(objField) {
	var k;
	var strRet;
	
	if (typeof(objField.selectedIndex) != "undefined") {
		return objField.options[objField.selectedIndex].value;
	}
	else {
		for (k = 0; k < objField.length; k++) {
			if (objField[k].checked) {
				return objField[k].value;
			}
		}
	}
	return "";
}


/* **********************************************************
   FUNCTION: selectedValues
   PURPOSE:  Return values of selected items in a checkbox
   			 group or multi-select selection control
   INPUTS:	 objField: Form field to check
   RETURNS:  Array of strings holding 'value' attributes of
   			 selected indexes of control; empty array if
   			 no selection
   NOTES:	 Has scalar version for single-select controls
   			 (including radio controls)
   ******************************************************** */
function selectedValues(objField) {
	var k;
	var aryRet = new Array();
	
	if (typeof(objField.selectedIndex) != "undefined") {
		for (k = 0; k < objField.options.length; k++) {
			if (objField.options[k].selected) {
				aryRet[aryRet.length] = objField.options[k].value;
			}
		}
	}
	else {
		for (k = 0; k < objField.length; k++) {
			if (objField[k].checked) {
				aryRet[aryRet.length] = objField[k].value;
			}
		}
	}
	return aryRet;
}


/* **********************************************************
   FUNCTION: isBlank
   PURPOSE:  Validate whether a form field is empty or
   			 contains an empty or placeholder string
   INPUTS:	 objField:     Form field to check
   			 strExclude: Optional parameter; Placeholder 
   			 				 text that counts as no entry in 
   			 				 field
   RETURNS:  Boolean value; 'false' indicates an entry
   			 other than whitespace or the excluded value
   			 has been made in field
   NOTES:	 Strings consisting entirely of whitespace are
   			 counted as empty strings
   			 
   			 Intended only for text input and hidden fields
   			 
   			 Matching for strExclude is case-sensitive
   ******************************************************** */
function isBlank(objField, strExclude) {
	if (isNull(objField.value, strExclude)) {
		return true;
	}
	
	var strVal = trim(objField.value);
	if (strVal.length == 0 || strVal == trim(strExclude)) {
		return true;
	}

	return false;
}


/* **********************************************************
   FUNCTION: isNumeric
   PURPOSE:  Determine whether a form field contains only
   			 numeric characters
   INPUTS:	 objField: Form field to check
   RETURNS:  Boolean value
   NOTES:	 Intended only for text input and hidden fields
   ******************************************************** */
function isNumeric(objField) {
	var objReg = /^\d+$/;
	return objReg.test(objField.value);
}


/* **********************************************************
   FUNCTION: isValidZipcode
   PURPOSE:  Determine whether a form field contains a
   			 validly-formed U.S. zip code
   INPUTS:	 objField:  Form field to check
   			 intFormat: Optional parameter; if present, should
   			 			 be either 4, 5 or 9 (other values will
   			 			 be ignored); 4 forces a 4-character
   			 			 (extension) format, 5 forces a 5-character
   			 			 format, 9 forces a 9-character 
   			 			 (zip-plus-4)format; if not supplied, 
   			 			 either 5 or 9 (but not 4) will be considered 
   			 			 valid
   RETURNS:  Boolean value
   NOTES:	 By default allows 5 or 9 character format;
   			 a '-' is allowed but not required in 9-character format
   ******************************************************** */
function isValidZipcode(objField, intFormat) {
	var objReg;
	var intLenAllowed = 0;
	if (typeof(intFormat) == "undefined" || isNaN(intFormat)) {
		intFormat = 0;
	}
	if (intFormat == 4 || intFormat == 5 || intFormat == 9) {
		intLenAllowed = intFormat;
	}

	var strVal = objField.value.toString();
	if (typeof(strVal) == "undefined") {
		strVal = "";
	}
	var intLen = strVal.length;

	if (intLenAllowed == 4) {
		objReg = /^\d{4}$/;
	} else if (intLenAllowed == 5) {
		objReg = /^\d{5}$/;
	} else if (intLenAllowed == 9) {
		objReg = /(^\d{9}$)|(^\d{5}-\d{4}$)/;
	} else {
		objReg = /(^\d{5}$)|(^\d{9}$)|(^\d{5}-d{4}$)/;
	}

	return objReg.test(strVal);
}


/* **********************************************************
   FUNCTION: isValidEmail
   PURPOSE:  Determine whether a form field contains a
   			 well-formed e-mail address
   INPUTS:	 objField: Form field to check
   RETURNS:  Boolean value
   NOTES:	 
   ******************************************************** */
function isValidEmail(objField) {
	var objReg = /^.+\@(\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/;
	var strVal = objField.value.toString();
	return objReg.test(strVal);
}

/* **********************************************************
   FUNCTION: isValidDate
   PURPOSE:  Determine whether a form field contains a
   			 well-formed date
   INPUTS:	 objField:    Form field to check
			 bolZeroPad:  Flag indicating whether month
			              and day should have leading
			              zeros if 1 digit
			 bolYearFour: Flag indicating whether to
			              force a 4-digit year
   RETURNS:  Boolean value
   NOTES:	 
   ******************************************************** */
function isValidDate(objField, bolZeroPad, bolYearFour) {
	var objReg;
	var strVal = objField.value.toString();
	
	if (! isDate(strVal)) {
		return false;
	}
	
	if (bolZeroPad)
	{
		if (bolYearFour)
		{
			// 00/00/0000
			objReg = /^\d{2}\/\d{2}\/\d{4}$/;
		}
		else
		{
			// 00/00/00[00]
			objReg = /^\d{2}\/\d{2}\/(\d{2}|\d{4})$/;
		}
	}
	else
	{
		if (bolYearFour)
		{
			// [0]0/[0]0/0000
			objReg = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
		}
		else
		{
			// [0]0/[0]0/00[00]
			objReg = /^\d{1,2}\/\d{1,2}\/(\d{2}|\d{4})$/;
		}
	}
	
	return objReg.test(strVal);
}


/* **********************************************************
   FUNCTION: compareToRange
   PURPOSE:  Determine whether a form field value is in a 
   			 given range
   INPUTS:	 objField:   Form field to check
   			 varLower: Lower end of range
   			 varUpper: Upper end of range
   RETURNS:  Int:
   			 	 -1 if value is under range
   			 	  0 if value is within range
   			 	 +1 if value is over range
   NOTES:	 Works for numerics, Dates or Strings
   			 
   			 Can replace isAfter() method for Dates
   			 
   			 If value == varLower or value == varUpper,
   			 value is considered to be in range
   			 
   			 String comparisons are case-sensitive
   			 
   			 If comparison cannot be determined,
   			 -1 is returned
   ******************************************************** */
function compareToRange(objField, varLower, varUpper) {
	var varVal = objField.value;
	if (typeof(varVal) == "undefined") {
		return -1;
	}
	else if (isDate(varVal)) {
		varVal = new Date(varVal);
	}
	
	if (varVal < varLower) {
		return -1;
	}
	else if (varVal > varUpper) {
		return 1;
	}
	
	return 0;
}


/* **********************************************************
   FUNCTION: lengthInRange
   PURPOSE:  Determine whether the length of a form field
   			 value is within a given range
   INPUTS:	 objField: Form field to check
   			 intMin:   Minimum allowed length
   			 intMax:   Maximum allowed length
   RETURNS:  Int:
   			 	 -1 if length is under range
   			 	  0 if length is within range
   			 	 +1 if length is over range
   NOTES:	 If length == intMin or length == intMax, length is
   			 considered to be in range
   ******************************************************** */
function lengthInRange(objField, intMin, intMax) {
	var strVal = objField.value.toString();
	
	if (strVal.length < intMin) {
		return -1;
	}
	else if (strVal.length > intMax) {
		return 1;
	}
	
	return 0;
}

/* __________________________________________________________
	
	UTILITY METHODS 
	__________________________________________________________ */


/* **********************************************************
   FUNCTION: isNull
   PURPOSE:  Determine whether an expression is null or 
   			 null-equivalent
   INPUTS:	 varVal:  Expression to be tested
   			 varNull: Additional value to be considered
   			 			 as null
   RETURNS:  Boolean value
   NOTES:	 At minimum, 'undefined', null, and empty string
   			 are considered null
   ******************************************************** */
function isNull(varVal, varNullVal) {
	if (typeof(varNullVal) != "undefined" && varVal == varNullVal) {
		return true;
	}
	
	if (typeof(varVal) == "undefined") {
		return true;
	}
	else if (varVal == null) {
		return true;
	}
	else if (varVal == "") {
		return true;
	}
	
	return false;
}


/* **********************************************************
   FUNCTION: trim
   PURPOSE:  Remove leading/trailing whitespace from a String
   INPUTS:	 strVal: String to be trimmed
   RETURNS:  String with leading/trailing whitespace removed
   NOTES:	 
   ******************************************************** */
function trim(strVal) {
	if (typeof(strVal) != "string" || strVal.length == 0) {
		return "";
	}
	
	return strVal.replace(/(^\s+)|(\s+$)/g, "");
}


/* **********************************************************
   NAME:    isDate
   PURPOSE: Determine whether a given expression is a
				valid date
   INPUTS:	varExpr: expression to test
   RETURNS: Boolean value
   NOTES:	
   ******************************************************** */
function isDate(varExpr) {
	return !(isNaN(new Date(Date.parse(varExpr)).getYear()));
}


/* **********************************************************
   NAME:    doSubmit
   PURPOSE: Set 'action' attribute of a form and submit form
   INPUTS:	strAction: 'action' attribute of form
			objForm:   form to be submitted
   RETURNS: true
   NOTES:	
   ******************************************************** */
function doSubmit(strAction, objForm)
{
	if (strAction != "1") {
		objForm.action.value = strAction;
	}
	objForm.submit();
	return true;
}


/* **********************************************************
   NAME:    alertFocus
   PURPOSE: Alert message, focus on form control
   INPUTS:	strMsg:		String for alert; if empty string or null,
						no alert is generated
			objField:   field to receive focus
			bolReturn:	Boolean value to return; optional;
						default false
   RETURNS: Supplied boolean value or false
   NOTES:	
   ******************************************************** */
function alertFocus(strMsg, objField, bolReturn) {
	if (typeof(bolReturn) == "undefined") {
		bolReturn = false;
	}

	if (! isNull(strMsg)) {
		alert(strMsg);
	}
	
	objField.focus();
	return bolReturn;
}


/* **********************************************************
   NAME:    alertSelect
   PURPOSE: Alert message, select form control
   INPUTS:	strMsg:		String for alert; if empty string or null,
						no alert is generated
			objField:   field to be selected
			bolReturn:	Boolean value to return; optional;
						default false
   RETURNS: Supplied boolean value or false
   NOTES:	
   ******************************************************** */
function alertSelect(strMsg, objField, bolReturn) {
	if (typeof(bolReturn) == "undefined") {
		bolReturn = false;
	}

	if (! isNull(strMsg)) {
		alert(strMsg);
	}
	
	objField.focus();
	objField.select();
	return bolReturn;
}


/* **********************************************************
   NAME:    alertSet
   PURPOSE: Alert message, set value of form control
   INPUTS:	strMsg:		String for alert; if empty string or null,
						no alert is generated
			objField:   Field to be modified
			varVal:		Value for target form control
			bolReturn:	Boolean value to return; optional;
						default false
   RETURNS: Supplied boolean value or false
   NOTES:	
   ******************************************************** */
function alertSet(strMsg, objField, varVal, bolReturn) {
	if (typeof(bolReturn) == "undefined") {
		bolReturn = false;
	}

	if (! isNull(strMsg)) {
		alert(strMsg);
	}
	
	objField.value = varVal;
	return bolReturn;
}


/* **********************************************************
   NAME:    setAmount
   PURPOSE: Set value of a form control to valid integer value
   INPUTS:	strMsg:		String for alert; if empty string or null,
						no alert is generated
			objField:   Field to receive focus
			intLower:	Lower limit of acceptable range
			intUpper:	Upper limit of acceptable range
			intDefault:	Default numeric value for non-integer values
   RETURNS: integer final value of field
   NOTES:	
   ******************************************************** */
function setAmount(strMsg, objField, intLower, intUpper, intDefault) {
	var varAmt = objField.value;
	var reDigit = /^\d+$/;
	var intCompare;
	
	if (! reDigit.test(varAmt) || isNaN(varAmt)) {
		alertSet(strMsg, objField, intDefault);
		return intDefault;
	}

	intCompare = compareToRange(objField, intLower, intUpper);
	if (intCompare < 0) {
		alertSet(strMsg, objField, intLower);
		return iLower;
	} else if (intCompare > 0) {
		alertSet(strMsg, objField, intUpper);
		return intUpper;
	}
	
	return varAmt;
}

/* **********************************************************
   NAME:    inArray
   PURPOSE: Determine whether a given value is in an array,
			and if so return the index of its first occurrence
   INPUTS:	objAry:	array to be searched
			varVal: value to search for
   RETURNS: index of first occurrence of value varVal in
			array objAry, or -1 if not found.
   NOTES:	
   ******************************************************** */
function inArray(objAry, varVal) {
	var k;
	for (k = 0; k < objAry.length; k++) {
		if (objAry[k] == varVal) {
			return k;
		}
	}
	return -1;
}
