/*///////////////////////////////////////////////////////
// 
//   version: 1.00
//   author: john burnside
//   date: 5.13.03
//   description: functions for client-side form validation
//
///////////////////////////////////////////////////////*/

var DEBUG = false

/////////////////////////////////////////////////////////
//constants for field types
var FT_TEXT = 0						//validates text values (pretty much accepts anything)
var FT_INTEGER = 1					//validates integer values
var FT_CURRENCY = 2					//validates currency values
var FT_EMAIL = 3					//validates email addresses
var FT_ZIPCODE = 4					//validate zip code
var FT_RADIO = 5					//validate a radio group for a selected value
var FT_SELECTBOX = 6				//validate a drop down list to have a valid option selected
var FT_DATE = 7						//validate a text field containing a date
var FT_CURRENCY_POSITIVE = 8		//validate a currency value, but only allow positive values
var FT_PHONE_NUMBER = 9				//validate a 10-digit phone number
var FT_CHECKBOX = 10				//validates that user selected at least one checkbox from group
var FT_DATETIME = 11				//validate a set of fields containing date and time combination

/////////////////////////////////////////////////////////
//global variables
var aActions = new Array()				//array to hold collections of validation rules
var aErrors = new Array()				//array to hold collection of errors generated during validation


/////////////////////////////////////////////////////////
//functions
/* function: adds error message to list of errors */
function AddErrorMessage(strMessage)
{
	//add message to array of errors
	aErrors[aErrors.length] = strMessage
}

/* function: add a new validation rule to the given collection. */
function AddValidationRule(strAction,strFieldID,strFieldName,iFieldType)
{
	var iIndex

	//get index where item will be inserted, then insert item
	iIndex = aActions[strAction].length
	aActions[strAction][iIndex] = new ValidationRule(strFieldID,strFieldName,iFieldType)
}

/* function: creates new member of collection array to hold a new set of validation rules for the given action */
function AddValidationRuleCollection(strAction)
{
	//create new rule collection
	aActions[strAction] = new Array()
}

/* function: deletes a validation rule collection with the given name */
function DeleteValidationRuleCollection(strAction)
{
	//delete new rule collection
	if (aActions[strAction])
		delete aActions[strAction]
}

/* function: validate the given action with the collection of validation rules that have been created for that action */
function ValidateAction(oForm,strAction,bClearErrors)
{
	var i, strErrors

	//create new array of errors if requested to do so
	if (bClearErrors)
		aErrors = new Array()

	//loop through validation rules for this action
	for(i=0;i<aActions[strAction].length;i++)
		ValidateField(oForm,aActions[strAction][i])
		
	//output error message if errors occurred
	if (aErrors.length > 0)
	{
		strErrors = "Please correct the following errors:\n\n"
	
		//build error string
		for(i=0;i<aErrors.length;i++)
			strErrors += "* " + aErrors[i] + "\n"
			
		//alert user about errors
		alert(strErrors)	
	}
	else
		//submit the valid form
		oForm.submit()
}

/* function: validate the field for the field type given in the validation rule argument */
function ValidateField(oForm,oRule)
{
	//get a reference to the form field to be validated
	var oField = oForm[oRule.FieldID]

	//validate based on rule type
	switch(oRule.FieldType)
	{
		case FT_TEXT:
		{	
			//generate error if field is empty
			if (!(IsValidText(oField.value)))
				AddErrorMessage(oRule.FieldName + " cannot be blank.")
			break
		}
		case FT_INTEGER:
		{	
			//generate error if field is not integer
			if (!(IsValidInteger(oField.value)))
				AddErrorMessage(oRule.FieldName + " must be a positive whole number (no decimals).")
			break
		}
		case FT_CURRENCY:
		{	
			//generate error if field is not valid currency
			if (!(IsValidCurrency(oField.value,true)))
				AddErrorMessage(oRule.FieldName + " must contain a valid decimal value.")
			break
		}
		case FT_EMAIL:
		{	
			//generate error if field is not email
			if (!(IsValidEmail(oField.value)))
				AddErrorMessage(oRule.FieldName + " must contain a valid e-mail address.")
			break
		}
		case FT_ZIPCODE:
		{	
			//generate error if field is not a vaild zip code
			if (!(IsValidZipCode(oField.value)))
				AddErrorMessage(oRule.FieldName + " must contain a valid zip code.")
			break
		}
		case FT_RADIO:
		{	
			//generate error if one radio box in the group was not selected
			if (!(IsValidRadioGroup(oField)))
				AddErrorMessage("Please select an option for " + oRule.FieldName + ".")
			break
		}
		case FT_SELECTBOX:
		{	
			//generate error if an option other than -1 was not selected
			if (!(IsValidSelectBox(oField.value)))
				AddErrorMessage("Please select an option for " + oRule.FieldName + ".")
			break
		}
		case FT_DATE:
		{	
			//generate error if text field does not contain a date
			if (!(IsValidDate(oField.value)))
				AddErrorMessage("Please enter a valid " + oRule.FieldName + ".")
			break
		}
		case FT_CURRENCY_POSITIVE:
		{	
			//generate error if field is not valid currency greater than zero
			if (!(IsValidCurrency(oField.value,false)))
				AddErrorMessage(oRule.FieldName + " must contain a valid decimal value greater than zero.")
			break
		}
		case FT_PHONE_NUMBER:
		{	
			//generate error if field is not valid currency greater than zero
			if (!(IsValidPhoneNumber(oField.value)))
				AddErrorMessage(oRule.FieldName + " must contain a valid 10-digit phone number.")
			break
		}
		case FT_CHECKBOX:
		{	
			//generate error if at no checkboxes were selected
			if (!(IsValidRadioGroup(oField)))
				AddErrorMessage("Please select at least one " + oRule.FieldName + ".")
			break
		}
		case FT_DATETIME:
		{	
			//generate error if at combination of fields is not a valid date
			if (!(IsValidDateTime(oForm,oRule.FieldID)))
				AddErrorMessage("Please enter a valid date and time for " + oRule.FieldName + ".")
			break
		}
		
		default:
			alert("Validating default")
	}
}

/* function: validates a value for a required text field */
function IsValidText(strValue)
{
	var reWhiteSpace = /\s/g		//white space regular expression

	return (strValue.replace(reWhiteSpace,"") != "")
}

/* function: validates a value for a required integer field */
function IsValidInteger(strValue)
{
	var reDigits = /^[1-9][0-9]*$/g		//digits only

	return (strValue.search(reDigits) == 0)
}

/* function: validates a value for a required integer field */
function IsValidCurrency(strValue,bAllowLessThanZero)
{
	var reCurrency
	
	if (bAllowLessThanZero)
		reCurrency = /^[-]?(([0-9]+)|([0-9]*[.][0-9]+))$/g		//currency format
	else
		reCurrency = /^(([0-9]+)|([0-9]*[.][0-9]+))$/g		//currency format, with dollar value greater than zero
		
	return (strValue.search(reCurrency) == 0)
}

/* function: validates a value for a required e-mail field */
function IsValidEmail(strValue)
{
	var reEmail = /^([a-zA-Z0-9_\-])+(\.([a-zA-Z0-9_\-])+)*@((\[(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5])))\.(((([0-1])?([0-9])?[0-9])|(2[0-4][0-9])|(2[0-5][0-5]))\]))|((([a-zA-Z0-9])+(([\-])+([a-zA-Z0-9])+)*\.)+([a-zA-Z])+(([\-])+([a-zA-Z0-9])+)*))$/g		//email format
	
	return (strValue.search(reEmail) == 0)
}

/* function: validates a value for a required zip code field */
function IsValidZipCode(strValue)
{
	var reZipCode = /^(\d{5}(|-\d{4}))$/g		//zip code format
	var reZeroZipCode = /^[0]{5}(-[0]{4})?$/g	//invalid 00000-0000 zip code
	
	return (strValue.search(reZipCode) == 0 && strValue.search(reZeroZipCode) == -1)
}

/* function: validates a radio box group for a checked value */
function IsValidRadioGroup(oGroup)
{	
	var bOptionChecked = false

	//handle the case that there is only one radio box in the group
	if (!oGroup.length)
		bOptionChecked = oGroup.checked
	else
	{
		//make sure there is a checked option
		for (var i=0;i<oGroup.length;i++)
		{
			if (oGroup[i].checked)
				bOptionChecked = true
		}
	}
	
	return (bOptionChecked)
}

/* function: validates a select box to have an option with a value other than -1 selected */
function IsValidSelectBox(strValue)
{	
	return (strValue != "-1")
}

/* function: validates a text field to have a valid date */
function IsValidDate(strValue)
{	
	return (!isNaN(Date.parse(strValue)))
}

/* function: validates a value for a required phone number field */
function IsValidPhoneNumber(strValue)
{
	var reNonDigits = /[^0-9]/g		//white space regular expression

	return (strValue.replace(reNonDigits,"").length == 10)
}

/* function: validates a group of boxes that constitute a date and time value */
function IsValidDateTime(oForm,strFieldName)
{	
	//build the date value from fields
	var strDateValue = oForm[strFieldName + "Date"].value + " " + oForm[strFieldName + "Hour"].value + ":" + oForm[strFieldName + "Minute"].value + " " + oForm[strFieldName + "AMPM"].value
	return ((strDateValue.indexOf("--") == -1) && !isNaN(Date.parse(strDateValue)))
}

/* function: used as ValidationRule object, holds information about field to validate */
function ValidationRule(strFieldID,strFieldName,iFieldType)
{
	this.FieldID = strFieldID
	this.FieldName = strFieldName
	this.FieldType = iFieldType
}

/* function: writes messages if debug mode is on */
function DebugWrite(strMessage)
{
	alert(strMessage)
}

/* function: updates a phone number field with 10 digits to common formatting */
function FormatPhoneNumber(strField)
{
	var reNonDigits = /[^0-9]/g		//white space regular expression
	var strCleanValue = strField.value.replace(reNonDigits,"")
	
	if (strCleanValue.length == 10)
	{
		var strPh1,strPh2,strPh3
		strPh1 = strCleanValue.substr(0,3)
		strPh2 = strCleanValue.substr(3,3)
		strPh3 = strCleanValue.substr(6,4)
		strField.value = "(" + strPh1 + ") " + strPh2 + "-" + strPh3
	}
}