/*
Global variables
Change Log
06/12/07. Corrected incorrect setting in UpdateValidity.
07/31/09. Removed UpdateValidity and updateValidityStyle.
*/
var sWebURL = location.href.replace(/(.*\/)(wapadmin1|wapadmin2|wapadmin3|wapdaemon|wapcustomer).*/i, "$1"); // Web URL
var sSubWebURL = sWebURL + RegExp.$2 + "/";

function CheckAll(oForm, aNames, bCheck) {
// This function checks (if bCheck) or unchecks all checkboxes whose names are in aNames in oForm.

var i, j;

for (i = 0; i < aNames.length; i++) {
	if (oForm[aNames[i]].length) {
		for (j = 0; j < oForm[aNames[i]].length; j++) {
			oForm[aNames[i]][j].checked = bCheck;
		}
	} else {
		oForm[aNames[i]].checked = bCheck;
	}
}

return true;

}

function CheckSome(oForm, sName, aValues, bCheck) {
// This function checks (if bCheck) or unchecks all checkboxes named sName with value in aValues in oForm.

var i, j;

if (oForm[sName].length) {
	for (i = 0; i < oForm[sName].length; i++) {
		for (j = 0; j < aValues.length; j++) {	
			if (oForm[sName][i].value == aValues[j]) {
				oForm[sName][i].checked = bCheck;
			}
		}
	}
} else {
	for (j = 0; j < aValues.length; j++) {	
		if (oForm[sName].value == aValues[j]) {
			oForm[sName].checked = bCheck;
		}
	}
}

return true;

}

function SelectSome(oForm, sName, aValues, bSelect) {
// This function selects (if bSelect) or deselects all options in the select element named sName with value in aValues in oForm.

var i, j;
if (oForm[sName].length) {
	for (i = 0; i < oForm[sName].length; i++) {
		for (j = 0; j < aValues.length; j++) {	
			if (oForm[sName][i].value == aValues[j]) {
				oForm[sName][i].selected = bSelect;
			}
		}
	}
} else {
	for (j = 0; j < aValues.length; j++) {	
		if (oForm[sName].value == aValues[j]) {
			oForm[sName].selected = bSelect;
		}
	}
}

return true;

}

function IsInput(oForm) {
// This function determines if any HTML input elements have data.
// This is useful in determining whether the user has entered anything into a form.

var i;
for (i = 0; i < oForm.elements.length; i++) {
	if (oForm.elements[i].type == "text" && oForm.elements[i].value != "") {
		return true;
	} else if (oForm.elements[i].type == "select-one") {
		if (oForm.elements[i].options[0].value == "") {
			if (oForm.elements[i].selectedIndex > 0) {
				return true;
			}
		} else {
			if (oForm.elements[i].selectedIndex >= 0) {
				return true;
			}
		}
	}
}

alert("Please enter some selection criteria.");

return false;

}

function IsChecked(oForm, sName, sMessage) {
// This function determines if any checkboxes named sName in oForm are checked.
// If not, it issues an alert with sMessage.
// If sName is null, all checkboxes are checked.

var i;

for (i = 0; i < oForm.elements.length; i++) {
	if (oForm.elements[i].type == "checkbox" && oForm.elements[i].checked && 
		(sName == "" || sName == oForm.elements[i].name)) {
		return true;
	}
}

alert(sMessage);

return false;

}

function GetRadioValue(oRadio) {
// This function returns the currently checked value of a radio button group.
// If no radio button in the group is checked, the function returns null.

var i;

for (i = 0; i < oRadio.length; i++) {
	if (oRadio[i].checked) return oRadio[i].value;
}
return null;
}

function IsUniquelyChecked(oElement, sValue, sMessage) {
// This function determines if any other checkboxes with the same name as this one and
// value sValue are checked.
// If so, it issues an alert with sMessage.

var oForm = oElement.form;
var i;
var iCount = 0;

if (oElement.checked) {
	for (i = 0; i < oForm.elements.length; i++) {
		if (oForm.elements[i].type == "checkbox" && oForm.elements[i].checked && 
			(oForm.elements[i].name == oElement.name && oForm.elements[i].value.indexOf(sValue) == 0)) {
			if (++iCount > 1) {
				alert(sMessage);
				return false;
			}
		}
	}
}

return true;

}
/*
The aV array is used for validating form elements. Each aV entry is an array with the following structure:
	0:	form element name
	1:	display name (for user messages)
	2:	array containing a list of valid values
	3:	array containing the minimum and maximum numeric values followed by their display counterparts
	4:	array containing the minimum and maximum number of characters (-1 means no constraint)
	5:  boolean indicating whether this form element should be parsed as a date: mm/dd/[yy]yy
	6:  boolean indicating whether a real number (with decimal point) may be allowed for this form element
*/
var iFirstBillMonthOfYear = 0;
var i = 0;
var aV = new Array();
aV[i++] = new Array("AccountName", "Account Name", new Array(), new Array(), new Array(1, 255), false, false);
aV[i++] = new Array("AccountNumber", "Account Number", new Array(), new Array(), new Array(6, 6), false, false);
aV[i++] = new Array("accountnumber", "Account Number", new Array(), new Array(), new Array(6, 6), false, false);
aV[i++] = new Array("AccountPath", "Account Path for UBS", new Array(), new Array(), new Array(5, -1), false, false);
aV[i++] = new Array("AcctWithNegativeConsSummaryRecipients", "Account with Negative Consumption Alert Summary Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("AeratorsInstalled", "Number of Aerators Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("AFOID", "Scenario Name", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("AllocationMasterPathName", "Allocation Master PathName", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("AuditDate", "Audit Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("BegReadDate", "Beginning Consumption Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("BillDate", "Bill Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("CIMISBaseWaitInterval", "CIMIS Base Wait Interval", new Array(), new Array(1, 20, "1", "20"), new Array(1, 2), false, false);
aV[i++] = new Array("CIMISDataAlertRecipients", "CIMIS Data Alert Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("CIMISDate", "CIMIS Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("CIMISRetryCount", "CIMIS Retry Count", new Array(), new Array(1, 10, "1", "10"), new Array(1, 2), false, false);
aV[i++] = new Array("CIMISStationNameETo", "CIMIS Station Name for ETo Values", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("CIMISStationNamePrecip", "CIMIS Station Name for Precip Values", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("CIMISUserName", "CIMIS Username", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("CIMISUserPassword", "CIMIS Password", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("ClosedAcctWithConsSummaryRecipients", "Closed Account with Consumption Alert Summary Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("CoeffDisplayDecimalPlaces", "Decimal Places to Display for Coefficient", new Array(), new Array(0, 6, "0", "6"), new Array(-1, -1), false, false);
aV[i++] = new Array("CoeffDisplayMaxCharacters", "Number of Characters to Display for Coefficient", new Array(), new Array(1, 10, "1", "10"), new Array(-1, -1), false, false);
aV[i++] = new Array("ConstantAbbrev", "Water Use Constant Abbrev", new Array(), new Array(), new Array(1, 20), false, false);
aV[i++] = new Array("ConstantDesc", "Water Use Constant Description", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("ConstantDisplayDecimalPlaces", "Decimal Places to Display", new Array(), new Array(0, 6, "0", "6"), new Array(1, 1), false, false);
aV[i++] = new Array("ConstantDisplayMaxCharacters", "Number of Characters to Display for Constant", new Array(), new Array(1, 10, "1", "10"), new Array(1, 2), false, false);
aV[i++] = new Array("ConstantName", "Water Use Constant Name", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("ConstantNumericValue", "Constant Numeric Value", new Array(), new Array(-1000000, 1000000, "-1,000,000", "1,000,000"), new Array(1, 20), false, true); // 5/25/09 Added
aV[i++] = new Array("DaemonUserName", "Username For Daemon Processing", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("DaemonUserPassword", "Password For Daemon Processing", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("DatabaseCommandTimeout", "Database Command Timeout", new Array(), new Array(0, 1200, "0", "1,200"), new Array(1, 5), false, false);
aV[i++] = new Array("DatabaseName", "Database Name or Initial Catalog", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("DatabaseServer", "SQL Server or Datasource Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("DatabaseValidityAlertRecipients", "Database Validity Alert Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("Date", "Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("DeliveryDate", "Delivery Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("DefaultAFVAlertRecipients", "Default Budget Factor Value Alert Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("DefaultAFVAlertWUTs", "Default Budget Factor Value Water Use Types", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("DefaultSystemMessage", "Default System Message", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("EffectiveDate", "Effective Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("EmailList", "Email List", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("EmailListForApplys", "Email List for Applys", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("EmailListForUpdatesOrRejects", "Email List for Updates", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("EmailRecipient", "Email Recipient", new Array(), new Array(), new Array(5, 100), false, false);
aV[i++] = new Array("EndReadDate", "Ending Consumption Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("FactorAbbrev", "Water Use Factor Abbrev", new Array(), new Array(), new Array(1, 20), false, false);
aV[i++] = new Array("FactorCoefficientValue", "Initial Coefficient Value", new Array(), new Array(-1000000, 1000000, "-1,000,000", "1,000,000"), new Array(1, 20), false, true); // 5/25/09 Added
aV[i++] = new Array("FactorDefaultValue", "Initial Default Value", new Array(), new Array(-1000000, 1000000, "-1,000,000", "1,000,000"), new Array(1, 20), false, true); // 5/25/09 Added
aV[i++] = new Array("FactorDesc", "Water Use Factor Description", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("FactorName", "Water Use Factor Name", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("FromDate", "From Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("holdersname", "Account Name", new Array(), new Array(), new Array(1, 255), false, false);
aV[i++] = new Array("HoseShutoffValvesInstalled", "Number of Hose Shutoff Valves Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("HoseSprayNozzlesInstalled", "Number of Hose Spray Nozzles Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("HoseTimersInstalled", "Number of Hose Timers Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("HostName", "Name of UBS Host", new Array(), new Array(), new Array(5, -1), false, false);
aV[i++] = new Array("HWR", "Hot Water Recirculating System", new Array(), new Array(), new Array(1, 250), false, false);
aV[i++] = new Array("HWRBrand", "Hot Water Recirculating System Brand", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("HWRModel", "Hot Water Recirculating System Model", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("HWRVersion", "Hot Water Recirculating System Version", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("InputArgCount", "Number of Input Arguments", new Array(), new Array(0, 9, "0", "9"), new Array(1, -1), false, false);
aV[i++] = new Array("IrrigationTimersInstalled", "Number of Irrigation Timers Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("LeakAlertSummaryRecipients", "Leak Alert Summary Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("MaxPendingTransactions", "Maximum Number of Pending Transactions Allowed", new Array(), new Array(1, 99, "1", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("MaxRecordsPerPage", "Maximum Report Lines Per Printed Page", new Array(), new Array(1, 999, "1", "999"), new Array(1, 3), false, false);
aV[i++] = new Array("MaxResultRecords", "Maximum Result Records", new Array(), new Array(1, 999999999, "1", "999,999,999"), new Array(1, 11), false, false);
aV[i++] = new Array("MaxResults", "Maximum Results Rows", new Array(), new Array(1, 999999, "1", "999,999"), new Array(1, 7), false, false);
aV[i++] = new Array("MessageTemplateBody", "Message Body", new Array(), new Array(), new Array(1, 2000), false, false);
aV[i++] = new Array("MessageTemplateName", "Template Name", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("MessageTemplateSubject", "Message Subject", new Array(), new Array(), new Array(1, 250), false, false);
aV[i++] = new Array("Multiplicity", "Number of Units", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("NegativeConsumptionAlertThreshold", "Negative Consumption Alert Threshold", new Array(), new Array(-10000, 0, "-10,000", "0"), new Array(-1, -1), false, true);
aV[i++] = new Array("NIRInvalidDataThreshold", "NIR Invalid Data Threshold", new Array(), new Array(0, 1000, "0", "1,000"), new Array(1, 5), false, false);
aV[i++] = new Array("OriginalVolume", "Original Volume", new Array(), new Array(0, 99, "0", "99"), new Array(-1, -1), false, true);
aV[i++] = new Array("OutputArgCount", "Number of Output Arguments", new Array(), new Array(0, 9, "0", "9"), new Array(1, -1), false, false);
aV[i++] = new Array("QueryName1", "Query Name", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("QueryName2", "Query Name", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("RebateAmount", "Rebate Amount", new Array(), new Array(0, 999, "0", "999"), new Array(-1, -1), false, true);
aV[i++] = new Array("RebateDate", "Rebate Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("ReplacementDate", "Replacement Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("Savings", "Savings", new Array(), new Array(0, 99, "0", "99"), new Array(-1, -1), false, true);
aV[i++] = new Array("ScenarioDesc", "Scenario Description", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("ScenarioName", "Scenario Name", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("ScriptTimeout", "Script Timeout", new Array(), new Array(1, 9999, "1", "9,999"), new Array(1, 5), false, false); // 2/24/2010 Increased max from 999 to 9999
aV[i++] = new Array("SensusDatabaseName", "Sensus Database Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SensusDatabaseServer", "Sensus SQL Server Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SensusPassword", "Sensus Password", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SensusUsername", "Sensus Username", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SessionTimeout", "Session Timeout", new Array(), new Array(1, 99, "1", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("ShowerHeadsInstalled", "Number of Shower Heads Installed", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("SiteID", "Site ID", new Array(), new Array(0, 999999, "000000", "999999"), new Array(6, 6), false, false);
aV[i++] = new Array("SMTPHost", "SMTP Host Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SMTPSender", "SMTP Sender Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SMTPUserName", "SMTP Username", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SMTPUserPassword", "SMTP Password", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("Subroutine", "Name of Subroutine to Call", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("SuperAdministrators", "Logon Names of SuperAdministrators", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("TemplatesSubdirectory", "Chart Templates Subdirectory", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("WaterUseTypeAbbrev", "Water Use Type Abbrev", new Array(), new Array(), new Array(1, 20), false, false);
aV[i++] = new Array("WaterUseTypeName", "Water Use Type Name", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("TechnicianName", "Technician Name", new Array(), new Array(), new Array(1, 255), false, false);
aV[i++] = new Array("ToDate", "To Date", new Array(), new Array(), new Array(-1, -1), true, false);
aV[i++] = new Array("Toilet", "Toilet", new Array(), new Array(), new Array(1, 250), false, false);
aV[i++] = new Array("ToiletBrand", "Toilet Brand", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("ToiletModel", "Toilet Model", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("ToiletType", "Toilet Type", new Array(), new Array(), new Array(1, 255), false, false);
aV[i++] = new Array("ToiletVersion", "Toilet Version", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("ToiletVolume", "Toilet Volume", new Array(), new Array(0, 99, "0", "99"), new Array(-1, -1), false, true);
aV[i++] = new Array("ToiletVolumes", "Toilet Volumes", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("TopNumber", "Top Number", new Array(), new Array(0, 100000, "0", "100,000"), new Array(-1, -1), false, false);
aV[i++] = new Array("TopPercent", "Top Percent", new Array(), new Array(0, 100, "0", "100"), new Array(-1, -1), false, false);
aV[i++] = new Array("UsageAlertThresholdExcess", "Usage Alert Threshold Excess", new Array(), new Array(0, 10000, "0", "10,000"), new Array(-1, -1), false, false);
aV[i++] = new Array("UsageAlertThresholdPercent", "Usage Alert Threshold Percent", new Array(), new Array(0, 10000, "0", "10,000"), new Array(-1, -1), false, false);
aV[i++] = new Array("UsageAlertExamFrequency", "Usage Alert Exam Frequency", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("UsageReportExamFrequency", "Usage Report Exam Frequency", new Array(), new Array(0, 99, "0", "99"), new Array(1, 2), false, false);
aV[i++] = new Array("UsageAlertSummaryRecipients", "Usage Alert Summary Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("UserDocumentsPath", "Path to User Documents Directory", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("UserName", "User Name for UBS", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("UserPassword", "User Password for UBS", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("U2AccountPath", "UBS Account Path", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("U2HostName", "UBS Host Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("U2UserName", "UniObjects User Name", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("U2UserPassword", "UniObjects User Password", new Array(), new Array(), new Array(1, -1), false, false);
aV[i++] = new Array("ValueDisplayDecimalPlaces", "Decimal Places to Display for Value", new Array(), new Array(0, 6, "0", "6"), new Array(-1, -1), false, false);
aV[i++] = new Array("ValueDisplayMaxCharacters", "Number of Characters to Display for Value", new Array(), new Array(1, 100, "1", "100"), new Array(-1, -1), false, false);
aV[i++] = new Array("WAPFailureAlertRecipients", "WAP Failure Alert Recipients", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("Washer", "Washer", new Array(), new Array(), new Array(1, 250), false, false);
aV[i++] = new Array("WasherBrand", "Washer Brand", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("WasherModel", "Washer Model", new Array(), new Array(), new Array(1, 100), false, false);
aV[i++] = new Array("WasherVersion", "Washer Version", new Array(), new Array(), new Array(1, 50), false, false);
aV[i++] = new Array("WaterFactor", "Water Factor", new Array(), new Array(0, 99, "0", "99"), new Array(-1, -1), false, true);
aV[i++] = new Array("WaterUseType", "Water Use Type", new Array(), new Array(), new Array(-1, -1), false, false);
aV[i++] = new Array("WUTID", "Water Use Type", new Array(), new Array(), new Array(-1, -1), false, false);

var bSomethingChanged = false;

function isValidNumber(oElement, sDisplayName, bRequired, bIgnoreCommas, iMin, iMax) {
// This function validates that oElement is numeric.
// The optional argument bRequired indicates whether oElement can have a null value. It defaults to true.
// The optional argument bIgnoreCommas indicates whether to ignore (i.e. allow) commas. It defaults to false.
// The optional argument iMin represents the lowest acceptable value.
// The optional argument iMax represents the highest acceptable value.

// Set up defaults
if (bRequired != false && bRequired != true) bRequired = true;
if (bIgnoreCommas != false && bIgnoreCommas != true) bIgnoreCommas = false;

if (!bRequired && oElement.value.length == 0) return true;
if (!isNumeric(bIgnoreCommas ? oElement.value.replace(/,/g, "") : oElement.value)) {
	alert("Please enter a valid number for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
}
if (!isNaN(iMin) && oElement.value - iMin < 0) {
	alert("Please enter a valid number >= " + iMin + " for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
}
if (!isNaN(iMax) && iMax - oElement.value > 0) {
	alert("Please enter a valid number <= " + iMax + " for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
}
return true;
}

function IsValidDate(oElement, sDisplayName, bRequired) {
// Return true if oElement.value is a valid date in the form mm/dd/yy.
// If not, and sDisplayName is not empty, issue an alert using sDisplayName.
// The optional argument bRequired indicates whether oElement can have a null value. It defaults to true.

if (arguments.count == 2) bRequired = true;

if (!bRequired && oElement.value.length == 0) return true;

if (!IsValidDateValue(oElement.value)) {
	if (sDisplayName != "") alert("Please enter a date in the format mm/dd/yy for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
}

return true;

}

function IsValidDateValue(sValue) {
// Return true if sValue is a valid date in the form mm/dd/yy.

var d = new Array(0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

if (sValue.search(/^(\d+)\/(\d+)\/(\d+)$/) != 0) {
	return false;
} else if (RegExp.$1 < 1 || RegExp.$1 > 12 || RegExp.$2 < 1 || RegExp.$2 > d[RegExp.$1] || RegExp.$3.length < 2 || RegExp.$3.length == 3 || RegExp.$3.length > 4) { // 1/26/09 Added validation of year
	return false;
}
if ((RegExp.$3.length == 2 && RegExp.$3 > 78) || (RegExp.$3.length == 4 && RegExp.$3 > 2078)) { // 10/27/09 SQL Server cannot handle smalldatetime values > 6/6/2079 so we restrict dates to <= 12/31/2079
	return false;
}

return true;

}

function IsValidDateTime(oElement, sDisplayName, bRequired) {
// Return true if oElement.value is a valid date or datetime in the form mm/dd/yy or mm/dd/yy hh:mm {am|pm}.
// If not, and sDisplayName is not empty, issue an alert using sDisplayName.
// The optional argument bRequired indicates whether oElement can have a null value. It defaults to true.

if (arguments.count == 2) bRequired = true;

if (!bRequired && oElement.value.length == 0) return true;

if (IsValidDateValue(oElement.value)) return true;

var iResult = oElement.value.search(/^(\d+\/\d+\/\d+).+(\d+):(\d+).+(am|pm)$/);
var iDate = RegExp.$1;
var iHour = RegExp.$2;
var iSecond = RegExp.$3;

if (iResult != 0) {
	if (sDisplayName != "") alert("Please enter a date or date-time in the format mm/dd/yy or mm/dd/yy hh:mm {am or pm} for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
} else if (!IsValidDateValue(iDate)) {
	if (sDisplayName != "") alert("Please enter a date or date-time in the format mm/dd/yy or mm/dd/yy hh:mm {am or pm} for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
} else if (iHour < 0 || iHour > 23 || iSecond < 0 || iSecond > 59) {
	if (sDisplayName != "") alert("Please enter a date or date-time in the format mm/dd/yy or mm/dd/yy hh:mm {am or pm} for " + sDisplayName + ".");
	oElement.value = "";
	oElement.focus();
	return false;
}

return true;

}

function IsValid(oElement, bRequired) {
// This function validates the oElement element in a form.
// The bRequired argument is optional and defaults to false. It indicates whether a value for oElement is required.
// Select elements are always valid unless their value is empty and bRequired = true.

var i, j;

if (arguments.length == 1) {
	bRequired = false;
}

if (oElement.type.indexOf("select") == 0 && ! bRequired) return true;

for (i = 0; i < aV.length; i++) {
	if (aV[i][0] == oElement.name) break;
}
if (i == aV.length) {
	alert("The " + oElement.name + " form element has no corresponding validator.");
	oElement.value = "";
	oElement.focus();
	return false;
}

if (oElement.type.indexOf("select") == 0) {
	if (oElement.selectedIndex < 0) { // nothing is selected
		alert("Please select a non-blank value for " + aV[i][1] + ".");
		oElement.focus();
		return false;
	} else if (oElement.options[oElement.selectedIndex].value == "") {
		alert("Please select a non-blank value for " + aV[i][1] + ".");
		oElement.focus();
		return false;
	} else {
		return true;
	}
}

if (oElement.value.length == 0 && ! bRequired) {
	return true;
}
if (aV[i][2].length > 0) {
	for (j = 0; j < aV[i][2].length; j++) {
		if (aV[i][2][j] == oElement.value) break;
	}
	if (j == aV[i][2].length) {
		alert("Please enter a value from {" + aV[i][2].join(", ") + "} for " + aV[i][1] + ".");
		oElement.value = "";
		oElement.focus();
		return false;
	}
}

if (aV[i][3].length > 0) {
	if (oElement.value.slice(0, 1) == ",") { // Leading comma
		alert("Please enter a number between " + aV[i][3][2] + " and " + aV[i][3][3] + " for " + aV[i][1] + ".");
		oElement.value = "";
		oElement.focus();
		return false;
	}
	var sValue = oElement.value.replace(/,/g, ""); // Remove any commas
	sValue = sValue.replace(/^0+/, ""); // Remove leading zeroes
	if (aV[i][6]) { // Is floating point allowed?
		if (sValue.indexOf(".") >= 0) { // 5/22/09 Is there a decimal point?
			sValue = sValue.replace(/0*$/, ""); // Remove trailing zeroes following the decimal point from floating point numbers
			sValue = sValue.replace(/\.$/, ""); // Remove trailing decimal point if any
			if (sValue.indexOf(".") == 0) sValue = "0" + sValue; // 5/22/09 A leading zero is required for parseFloat
		}
	}
	if (sValue == "" && oElement.value != "") sValue = "0"; // If its value is 0 and it was specified, set it to 0 rather than empty
	var sParsed = (aV[i][6] ? parseFloat(sValue).toString() : parseInt(sValue).toString());
	if (sParsed + "" != sValue + "" || aV[i][3][0] > sValue || aV[i][3][1] < sValue) {
		alert("Please enter a number between " + aV[i][3][2] + " and " + aV[i][3][3] + " for " + aV[i][1] + ".");
		oElement.value = "";
		oElement.focus();
		return false;
	}
}

if (aV[i][4][0] != -1) {
	if (aV[i][4][0] > oElement.value.length) {
		if (aV[i][4][1] == aV[i][4][0]) {
			alert("Please enter " + aV[i][4][0] + " character" + (aV[i][4][0] > 1 ? "s" : "") + " for " + aV[i][1] + ".");
		} else {
			alert("Please enter at least " + aV[i][4][0] + " character" + (aV[i][4][0] > 1 ? "s" : "") + " for " + aV[i][1] + ".");
		}
		oElement.value = "";
		oElement.focus();
		return false;
	}
}
if (aV[i][4][1] != -1) {
	if (aV[i][4][1] < oElement.value.length) {
		alert("Please enter at most " + aV[i][4][1] + " character" + (aV[i][4][1] > 1 ? "s" : "") + " for " + aV[i][1] + ".");
		oElement.value = "";
		oElement.focus();
		return false;
	}
}

if (aV[i][5]) { // parse for mm/dd/[yy]yy with sensible values for dd (always allow 29 for Feb)
	if (!IsValidDate(oElement, aV[i][1], true)) return false;
}

if (oElement.name == "FirstBillMonthOfYear") {
	iFirstBillMonthOfYear = oElement.value;
	for (j = 0; j < aV.length; j++) {
		if (aV[j][0] == "FirstBillDayOfYear") {
			aV[j][3][1] = (iFirstBillMonthOfYear == 1 ? 31 : 29);
			aV[j][3][3] = (iFirstBillMonthOfYear == 1 ? "31" : "29");
			break;
		}
	}
}

if (oElement.name == "EmailList") {
	var aRecipients;
	if (oElement.value.length > 0) {
		aRecipients = oElement.value.split(", ");
		for (j = 0; j < aRecipients.length; j++) {
			if (aRecipients[j].length > 0) {
				if (aRecipients[j].indexOf(",") >= 0 || aRecipients[j].indexOf(" ") >= 0 || aRecipients[j].indexOf("@") < 0) {
					alert("Please enter 0 or more email addresses separated by ', '.");
					oElement.value = "";
					oElement.focus();
					return false;
				}
			}
		}
	}
}

bSomethingChanged = true;

return true;

}

function AreValid(oForm, sCheckboxElementName) {
// This function validates every element of the oForm form that has an IsValid onChange event handler.
// The sCheckboxElementName argument is optional and defaults to "".
// If sCheckboxElementName is specified, it contains the name of a checkbox element that precedes any
// given element on the form, and which must be checked in order to proceed with the validation of the given element.

var i;
var bChecked = true;

if (arguments.length == 1) sCheckboxElementName = "";
for (i = 0; i < oForm.elements.length; i++) {
	if (oForm.elements[i].type == "checkbox" && oForm.elements[i].name == sCheckboxElementName) {
		bChecked = oForm.elements[i].checked;
	}
	if (oForm.elements[i].onchange != undefined) {
		if (oForm.elements[i].onchange.toString().search(/\bIsValid\s*\(\s*this\s*,\s*(false|true)\s*\)/i) >= 0 && bChecked) {
			if (!IsValid(oForm.elements[i], RegExp.$1 == "true")) return false;
		}
	}
}

return true;

}

function SomethingChanged(sMessage) {
// This function issues an alert message if nothing changed on a form, and returns false.

if (bSomethingChanged) {
	return true;
} else {
	alert(sMessage);
	return false;
}

}
function toUpper(myInput) {
myInput.value = myInput.value.toUpperCase();
return true;
}

function resetForms() {
// This function resets all forms in the document.
for (var i=0; i < document.forms.length; i++) {
	document.forms[i].reset();
}
}

function printAndProceed(iRecordCount, iLastRecord, iNextPageNumber, sFormName) {
// This function prints the current page and then, if there are more records to print,
// executes itself again to generate the next page. If there are no more records, it closes the window.
if (iRecordCount > 0) {
	window.print();
} else {
	alert("The data for your report is no longer available. Please re-execute the report.");
}
if (iLastRecord < iRecordCount) {
	eval("setTimeout('document.' + sFormName + '.submit()', 1000)");
} else {
	history.go(- --iNextPageNumber);
}
}

function plural(i, sSingular, sPlural) {
/*
If i == 1 then return sSingular, else sPlural.
sPlural is an optional argument. If not specified, sSingular + "s" is returned instead.
*/
if (arguments.length < 3) sPlural = sSingular + "s";

return (i == 1 ? sSingular : sPlural);
}

function SP(iSiteID, iWaterUseType, dDateClosed) {
// Submit the SP form using iSiteID, iWaterUseType.
// 6/12/09 Added optional parameter dDateClosed.
document.SP.SiteID.value = iSiteID;
document.SP.WaterUseType.value = iWaterUseType;
if (arguments.count == 3) {
	if (dDateClosed != "") {
		document.SP.SubSiteStatus.value = "Closed";
	} else {
		document.SP.SubSiteStatus.value = "Open";
	}
}
document.SP.submit();
}

function toggle(sID, iOrder) {
// This function expands or collapses subtext, modifying the +/- icon accordingly.
// It also manages the WAP_Topics cookie to keep track of all items that are expanded.
// It is assumed that the inline frame that is used for this is named "expanded" and that
// the function within that frame that finds the expanded text is named "expandedText".
// 7/12/09 The optional iOrder argument indicates whether to add this topic to the beginning or the ending of the WAP_Topics cookie string.
// This is required because 2nd-order topics cannot be found unless their 1st-order counterparts are expanded.
if (arguments.length == 1) iOrder = 0; // Default
var sThisCookieValue = sID; // Includes the leading # character
sID = sID.slice(1);
var oID = gmobj(sID);
var sTopics = getCookie("WAP_Topics");
var oRegExp = new RegExp(sThisCookieValue + "\\|", "i");
if (oID == null) {
	if (iOrder == 1) alert("Cant find " + sID); // 7/12/09 Check for existence only if 1st-order topic.
	return false;
}
var sCurr = oID.innerHTML;
var oExpandedID;

if (sCurr == "") {
	oID.innerHTML = window.top.expanded.expandedText(sID);
	eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_expanded.gif'");
	if (sTopics.indexOf(sThisCookieValue + "\|") < 0) {
		if (iOrder == 1) {
			expandAllTopicsInCookie(); // Expand all topics to catch the 2nd-order ones subordinate to this one.
			setCookie("WAP_Topics", sThisCookieValue + "\|" + sTopics);
		} else {
			setCookie("WAP_Topics", sTopics + sThisCookieValue + "\|");
		}
	}
} else {
	oID.innerHTML = "";
	eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_collapsed.gif'");
	setCookie("WAP_Topics", sTopics.replace(oRegExp, ""));
}
return false;
}

function expandAllTopicsInCookie() {
// Expand all topics as represented in the WAP_Topics cookie.
// Each topic is represented as #xxx|. There is a trailing | delimiter.
var sTopics = getCookie("WAP_Topics");
var aTopics = sTopics.split("\|");
var sID, oID;
for (var i = 0; i < aTopics.length; i++) {
	sID = aTopics[i].slice(1);
	oID = gmobj(sID);
	if (oID != null) {
		oID.innerHTML = window.top.expanded.expandedText(sID);
		eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_expanded.gif'");
	}
}
}

function expandAllTopics() {
/*
Expand all topics in this document and update the WAP_Topics cookie value.
We do this by following these steps:
1. ContractAllTopics.
2. Expand all links (hash) values, adding them to the cookie.
3. Expand all links (hash) values again in order to catch the 2nd-order topics, adding them to the cookie.
*/
var sID, oID, i, aLinks;
contractAllTopics();
aLinks = document.links;
for (i = 0; i < document.links.length; i++) {
	if (document.links[i].hash.length > 0) {
		sID = document.links[i].hash.slice(1);
		oID = gmobj(sID);
		if (oID != null) {
			oID.innerHTML = window.top.expanded.expandedText(sID);
			eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_expanded.gif'");
			setCookie("WAP_Topics", getCookie("WAP_Topics") + document.links[i].hash + "\|");
		}
	}
}
for (i = 0; i < document.links.length; i++) {
	if (document.links[i].hash.length > 0) {
		if (searchArray(aLinks, document.links[i]) < 0) {
			sID = document.links[i].hash.slice(1);
			oID = gmobj(sID);
			if (oID != null) {
				oID.innerHTML = window.top.expanded.expandedText(sID);
				eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_expanded.gif'");
				setCookie("WAP_Topics", getCookie("WAP_Topics") + document.links[i].hash + "\|");
			}
		}
	}
}
}

function contractAllTopics() {
/*
Contract all topics in this document and clear the WAP_Topics cookie value.
*/
var sID, oID, i;
for (i = 0; i < document.links.length; i++) {
	if (document.links[i].hash.length > 0) {
		//alert("Encountered hash " + document.links[i].hash);
		sID = document.links[i].hash.slice(1);
		oID = gmobj(sID);
		if (oID != null) {
			//alert("Contracting " + document.links[i].hash);
			oID.innerHTML = "";
			eval("document.images." + sID + "_img.src = '" + sWebURL + "images/toc_collapsed.gif'");
		}
	}
}
setCookie("WAP_Topics", "");
}

function isNumeric(s) {
// Return true if s is numeric, else false.
// s will test numeric if it is a positive or negative integer or floating point number without commas.
// The null string tests false.

s = s.replace(/\s/g, "!"); // 4/2/2009 Replace whitespace because it tests numeric!!!
return (s-0==s&&s.length>0);
}

function detectPageRefresh(oForm) {
// This routine bumps the Interaction element every time the form is submitted.
// This is used to determine whether the page was actually submitted or merely refreshed.
// Note that this routine always returns true, i.e. it will not prevent the submission of a form. It is during postback that execution of a refreshed page is suppressed.
// Implemented 7/10/09.
if (oForm.Interaction.value == "") {
	oForm.Interaction.value = 1;
} else {
	oForm.Interaction.value = parseInt(oForm.Interaction.value) + 1;
}
return true;
}
function getCookie(sName) {
// This function returns the value of the cookie corresponding to case-insensitive sName.

var cookie = document.cookie;
if (eval("cookie.search(/(^|;\\s*)" + encode(sName) + "=([^;]*)/i)") >=0) {
   return decode(RegExp.$2);
}
return "";

}

function setCookie(sName, sValue) {
// This function sets the cookie named sName to sValue.
// The 3rd optional argument contains the Expires attribute.

document.cookie = encode(sName) + "=" + encode(sValue) + "; path=/" +
	(arguments.length == 3 ? "; expires=" + arguments[2] : "");
}

function encode(s) {
// This function behaves like the IIS Server.URLEncode.
var aIn =  new Array("%",   "`",   "~",   "!",   "@",   "#",   "$",   "^",   "&",   "*",   "(",   ")",   "_",   "+",   "-",   "=",   "[",   "]",   "\\",   "{",   "}",   "|",   ";",   "'",   ":",   "\"",   ",",   ".",   "/",   "<",   ">",   "?",   "\f",   " ");
var aOut = new Array("\\f", "%60", "%7E", "%21", "%40", "%23", "%24", "%5E", "%26", "%2A", "%28", "%29", "%5F", "%2B", "%2D", "%3D", "%5B", "%5D", "%5C",  "%7B", "%7D", "%7C", "%3B", "%27", "%3A", "%22",  "%2C", "%2E", "%2F", "%3C", "%3E", "%3F", "%25", "+");
var i;

s = s + ""; // Convert to string
for (i = 0; i < aIn.length; i++) {
	eval("s = s.replace(/\\" + aIn[i] + "/g, \"" + aOut[i] + "\")");
}
return s;
}

function decode(s) {
// This function behaves like the IIS Server.URLDecode would behave, if there were one.

var aIn =  new Array("%60", "%7E", "%21", "%40", "%23", "%24", "%5E", "%26", "%2A", "%28", "%29", "%5F", "%2B", "%2D", "%3D", "%5B", "%5D", "%5C",  "%7B", "%7D", "%7C", "%3B", "%27", "%3A", "%22",  "%2C", "%2E", "%2F", "%3C", "%3E", "%3F", "%25", "\\+");
var aOut = new Array("`",   "~",   "!",   "@",   "#",   "$",   "^",   "&",   "*",   "(",   ")",   "_",   "+",   "-",   "=",   "[",   "]",   "\\\\", "{",   "}",   "|",   ";",   "'",   ":",   "\\\"", ",",   ".",   "/",   "<",   ">",   "?",   "%",   " ");
var i;

s = s + ""; // Convert to string
for (i = 0; i < aIn.length; i++) {
	eval("s = s.replace(/" + aIn[i] + "/g, \"" + aOut[i] + "\")");
}
return s;
}

function searchArray(a, s) {
// This function searches the a array for an entry matching s.
// It returns the 0-relative index of s, or -1 if no entries match.

var i;

for (i = 0; i < a.length; i++) {
	if (a[i] == s) return i;
}
return -1;
}

function submitFormWithAction(sForm, sAction) {
// 3/10/2010 Wrote original version.
// Submit the form named sForm using action sAction.
// No value is returned.
document.forms[sForm].action = sAction;
document.forms[sForm].submit();
}

function adjustRunLength(oElement, sFromDateSpan) {
// Adjust the values and appearance in the form to correspond to the RunLength value.
if (oElement.value == 31 || oElement.value == 62) {
	oElement.form.ViewUnits.value = 'Days';
	setDateVisibility(oElement.form, sFromDateSpan, true);
} else if (oElement.value == 4 || oElement.value == 8) {
	oElement.form.ViewUnits.value = 'Weeks';
	setDateVisibility(oElement.form, sFromDateSpan, true);
} else {
	oElement.form.ViewUnits.value = '';
	setDateVisibility(oElement.form, sFromDateSpan, false);
}
}
function setDateVisibility(oForm, sFromDateSpan, bFromDateVisible) {
// Set the visibility of some form elements.
if (bFromDateVisible) { // If the FromDate is visible, the Cumulative checkbox is always visible too
	if (oForm.FromDate.value == "1/1/01") oForm.FromDate.value = "";
	gmobj(sFromDateSpan).style.visibility = (bFromDateVisible ? 'visible' : 'hidden');
	//gmobj(sCumulative).style.visibility = 'visible';
} else {
	oForm.FromDate.value = "1/1/01";
	gmobj(sFromDateSpan).style.visibility = (bFromDateVisible ? 'visible' : 'hidden');
}
}

