///////////////////////////////////////////////////////////////////////////////
// MAIN VALIDATE FUNCTION /////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

function validate(frm) {

	var strMessages = "";
	var objFocusField;

	// Do validation fields exist?
	if(!frm.v_fields || !frm.v_errors) {
		alert("Validation fields must be specified!");
		return false;
	}
	
	// Create field/error lists
	var aryFieldList = frm.v_fields.value.split("|");
	var aryErrorList = frm.v_errors.value.split("|");
	
	// Are field/error lists the same length?
	if(aryFieldList.length != aryErrorList.length) {
		alert("Validation and error message lists must be the same length!");
		return false;
	}
	
	// Validate each field
	for(var ctrField = 0;ctrField < aryFieldList.length;ctrField++) {
		
		// Separate validations and field
		var strValidations = aryFieldList[ctrField].split("_")[0];
		var strFieldName = aryFieldList[ctrField].split("_")[1];
		var strFieldError = aryErrorList[ctrField];
		
		// Validate each validation
		for(var ctrValidation = 0;ctrValidation < strValidations.length;ctrValidation++) {
			var strValidation = strValidations.substr(ctrValidation,1);
			var intErrorCount = 0;
			switch(strValidation) {
				case 'r': intErrorCount += r(frm,strFieldName,strValidations); break;
				case 'e': intErrorCount += e(frm,strFieldName,strValidations); break;
				case 'd': intErrorCount += d(frm,strFieldName,strValidations); break;
				case 's': intErrorCount += s(frm,strFieldName,strValidations); break;
				case 'z': intErrorCount += z(frm,strFieldName,strValidations); break;
				case 'c': intErrorCount += c(frm,strFieldName,strValidations); break;
				case 'p': intErrorCount += p(frm,strFieldName,strValidations); break;
				case 'i': intErrorCount += w(frm,strFieldName,strValidations); break;
				case 'n': intErrorCount += n(frm,strFieldName,strValidations); break;
				case 't': intErrorCount += t(frm,strFieldName,strValidations); break;
				case 'u': intErrorCount += u(frm,strFieldName,strValidations); break;
				case 'f': intErrorCount += f(frm,strFieldName,strValidations); break;
				case 'a': intErrorCount += a(frm,strFieldName,strValidations); break;
				case 'l': break;
				default : alert("No validation for '" + strValidation + "'!"); break;
			}
			
			// Set the error message
			if(intErrorCount > 0)
				strMessages = strMessages + strFieldError + "\n";
				
			// Set the focus field after first error
			if(strMessages != "" && !objFocusField) {
				if(eval("frm." + strFieldName)) {
					var objField = eval("frm." + strFieldName);
					if(objField.focus)
						objFocusField = objField;
				}
			}
		}
	}
	
	// Alert error messages
	if(strMessages != "") {
		// Focusing causes some XUL issue with FireFox, grr
		//if(objFocusField.focus) 
			//objFocusField.focus();
		alert("Please check the following:\n\n" + strMessages);
		return false;
	}
	else
		return true;
}

///////////////////////////////////////////////////////////////////////////////
// REQUIRED ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function r(frm,field,validations) {
	var intErrors = 0;
	
	// "Normal" Validation
	if(validations.search("f") < 0 && validations.search("a") < 0 && eval("frm." + field)) {
		var objField = eval("frm." + field);

		// Text/Hidden/Textarea
		if((objField.type && (objField.type == "text" || objField.type == "hidden" || objField.type == "password")) || objField.rows) {
			intErrors = (objField.value == "") ? 1 : 0;
		}
		
		// Select
		else if(objField.options) {
			var blnSelected = false;
			for(var i=0;i<objField.options.length;i++) {
				if(objField.options[i].selected == true && objField.options[i].value != "")
					blnSelected = true;
			}
			intErrors = (blnSelected == false) ? 1 : 0;
		}
		
		// Checkboxes/Radio Buttons
		else if(objField.length) {
			var blnChecked = false;
			for(var i=0;i<objField.length;i++) {
				if(objField[i].checked == true)
					blnChecked = true;
			}
			intErrors = (blnChecked == false) ? 1 : 0;
		}
		
		// Single Checkbox/Radio Button
		else if(objField.type && (objField.type == "checkbox" || objField.type == "radio")) {
			intErrors = (objField.checked == false) ? 1 : 0;
		}
	}
	
	// "Special" Validation
	else {
		// File
		if(validations.search("f") > 0) {
			var objNew = eval("frm.new" + field);
			if(eval("frm.current" + field)) {
				var objCurrent = eval("frm.current" + field);
				if(eval("frm.delete" + field)) {
					var objDelete = eval("frm.delete" + field);
					if(objNew.value == "" && objDelete.checked == true)
						intErrors++;
				}
			}
			else {
				if(objNew.value == "")
					intErrors++;
			}
		}
		
		// Address
		else if(validations.search("a") > 0) {
			var objCity = eval("frm.city");
			var objState = eval("frm.statecode");
			var objPostalCode = eval("frm.postalcode");
			var objCountry = eval("frm.countrycode");
			if(objCountry.options && objCity.value && objState.value && objPostalCode.value) {
				if(objCountry.options[objCountry.selectedIndex].value == "US" &&
				  (objCity.value == "" || objState.value == "" || objPostalCode.value == ""))
				  	intErrors++;
				else if(objCountry.options[objCountry.selectedIndex].value == "CA" &&
				  (objCity.value == "" || objState.value == "" || objPostalCode.value == ""))
				  	intErrors++;
				else if(objCity.value == "" || objCountry.options[objCountry.selectedIndex].value == "")
					intErrors++;
			}
		}
	}
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// EMAIL //////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function e(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^[A-Za-z0-9]+[A-Za-z0-9\.\_\-]*@[A-Za-z0-9]+[A-Za-z0-9\.\_\-]*\.[A-Za-z]{2,4}$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// DATE ///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function d(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^((0?[1-9])|(1[0-2]))\/((0?[1-9])|([1-2][0-9])|(3[0-1]))\/(18|19|20)[0-9][0-9]$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// SSN ////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function s(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^[0-9A-Z]{3,3}\-[0-9A-Z]{2,2}\-[0-9A-Z]{4,4}$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Zip Code ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function z(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^((\d{5,5})|(\d{5,5}\-\d{4,4})|(([A-Za-z]){1}\d{1}([A-Za-z]){1}\s\d{1}([A-Za-z]){1}\d{1})){1}$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Credit Card ////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function c(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	
	if(objField.value != "") {
		// *cracks knuckles*:
		var ccNum = objField.value;
		var ccNumRev = "";
		var strLuhnNum = "";
		var intLuhnTotal = 0;
		var intLen = -1;
		var intCtr = 1;
		var blCC = false;
		
		for(var i = ccNum.length - 1;i >= 0;i--) {
	       ccNumRev += ccNum.charAt(i);
		}
		ccNum = ccNumRev.replace(/[^0-9]/g,"");
		intLen = ccNum.length;
		
		// All Credit Card Numbers' lengths are between 13 and 16
		if(intLen >= 13 && intLen <= 16) {
			for(var intCtr = 1;intCtr <= intLen;intCtr++) {
				if((intCtr % 2) == 0)
					strLuhnNum = strLuhnNum.toString() + (ccNum.charAt(intCtr-1) * 2).toString();
				else
					strLuhnNum = strLuhnNum.toString() + ccNum.charAt(intCtr-1);
			}
			// Add them all
			intLen = strLuhnNum.length;
			for(var intCtr = 1;intCtr <= intLen;intCtr++) {
				intLuhnTotal = intLuhnTotal + parseInt(strLuhnNum.charAt(intCtr-1));
			}
		}
		if(intLuhnTotal == 0 || (intLuhnTotal % 10) > 0)
			intErrors++;
	}
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Password ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function p(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var objField2 = eval("frm." + field + "_2");
	
	if(objField && objField.value && objField.value != objField2.value)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Integer ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function w(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	objField.value = objField.value.replace(/[,]/g,"");
	var strREReqs = /^\-?[0-9]*$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Number /////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function n(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	objField.value = objField.value.replace(/[,]/g,"");
	var strREReqs = /^\-?[0-9]*\.?[0-9]*$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Phone Number ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function t(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^[0-9]{1,2}-[0-9]{3,3}\-[0-9]{3,3}\-[0-9]{4,4}$/;
	var strREReqs2 = /^[0-9]{3,3}\-[0-9]{3,3}\-[0-9]{4,4}$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1 && objField.value.search(strREReqs2) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// Username ///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function u(frm,field,validations) {
	var intErrors = 0;
	var objField = eval("frm." + field);
	var strREReqs = /^[a-zA-Z0-9\.]+$/;
	if(objField && objField.value && objField.value != "" && objField.value.search(strREReqs) == -1)
		intErrors++;
	return intErrors;
}

///////////////////////////////////////////////////////////////////////////////
// File ///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function f(frm,field,validations) {
	return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Address ////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
function a(frm,field,validations) {
	return 0;
}