/*
 *	General form validation class 
 *  Note: Phone field is automatically concatenated from phone1, phone2, and phone3.
 *	
 *	Usage Example:
 *	var valConfig = [
 *		{ fld:'email', lbl:'Email address', req:[{cmd:'required'},{cmd:'email'}] },
 *		{ fld:'pass', lbl:'Password', req:[{cmd:'required'},{cmd:'minLength=5', err:'Pass must be at least 5 characters long.'}] },
 *		{ fld:'confPass', lbl:'Confirm password', req:[{cmd:'required', err:'Please confirm your password.'},{cmd:'sameAs=pass', err:'Confirm password and original password do not match.'}] },
 *		{ fld:'phone', lbl:'Phone number', mergeFromFlds:['phone1a','phone2','phone3'], req:[{cmd:'required'},{cmd:'phone', err:'Please enter a valid phone number.'}] },
 *		{ fld:'carrier', lbl:'Carrier', req:[{cmd:'dontSelect=0'}] }
 *	];
 *	var validation = new Validation('regForm', valConfig);
 *
 */

function Validation(frmName, configObj) {
	this.frmObj = document.forms[frmName];
	this.frmObj.configObj = configObj;
	this.frmObj.debug = false;
	
	if (this.frmObj.onsubmit) { // if form's onsubmit is defined		
		this.frmObj.userDefinedOnsubmit = this.frmObj.onsubmit;
		this.frmObj.onsubmit = null;
	} else this.frmObj.userDefinedOnsubmit = null;	
	
	this.frmObj.onsubmit = function() {
		if (this.userDefinedOnsubmit) this.userDefinedOnsubmit();
		for (var i=0; i<this.configObj.length; i++) {
			if (this.validate(i) == false) 
				return false;
		}
		if (this.customValidator) {
			var str = 'var result=' + this.customValidator + '()';
			eval(str);
			if (result == false) return false;
		}
		return true;
	}	
	
	// valididate input element at ith index
	this.frmObj.validate = function(i) {
		currObj = this.configObj[i];
		if (typeof currObj.lbl == 'undefined') currObj.lbl = currObj.fld;
		fldObj = this[currObj.fld];
		cmdArr = currObj.req;
		phone1 = '';
		if (currObj.lbl.toLowerCase().match("phone") != null) {
			phone1 = 'phone1'; phone2 = 'phone2'; phone3 = 'phone3'; 
			phoneArr = currObj.mergeFromFlds;					
			if (typeof phoneArr != 'undefined') { phone1 = phoneArr[0]; phone2 = phoneArr[1]; phone3 = phoneArr[2]; }
			fldObj.value = this[phone1].value + this[phone2].value + this[phone3].value;
		}
		
		// loop through each requirement command
		for (var j=0; j<cmdArr.length; j++) {				
			cmd = cmdArr[j].cmd; command = cmd; cmdValue = '';
			eqSignPos = cmd.search("=");
			if (eqSignPos >= 0) { 
				command = cmd.substring(0,eqSignPos); 
				cmdValue = cmd.substr(eqSignPos+1); 
			}	

			errorStr = cmdArr[j].err;
			noCustomError = (typeof errorStr == 'undefined');			
			notEmpty = !this.isEmpty(fldObj.value);
			isValid = true;
			
			switch (command) {
				case "required": {
					if (this.isEmpty(fldObj.value)) {
						if (noCustomError) errorStr = 'Please enter ' + currObj.lbl + '.';
						isValid = false;
					}
					break;
				}
				case "email": {
					if (notEmpty && !this.isValidEmail(fldObj.value)) {
						if (noCustomError) errorStr = 'Please enter a valid email address.';
						isValid = false;
					}
					break;
				}
				case "phone": {
					if (!this.isNumeric(fldObj.value) || fldObj.value.length != 10) {
						if (noCustomError) errorStr = 'Please enter a valid phone number.';
						isValid = false;
					}
					break;
				}
				case "sameAs": {
					if (fldObj.value != this[cmdValue].value) {
						if (noCustomError) errorStr = currObj.lbl + ' and ' +  cmdValue + ' do not match.';
						isValid = false;
					}
				}
				case "maxLength": {
					if (notEmpty && this.isOverMaxLength(fldObj.value, cmdValue)) {
						if (noCustomError) errorStr = currObj.lbl + ' is too long.';
						isValid = false;
					}
					break;
				}
				case "minLength": {
					if (notEmpty && this.isUnderMinLength(fldObj.value, cmdValue)) {
						if (noCustomError) errorStr = currObj.lbl + ' is too short.';
						isValid = false;
					}
					break;
				}
				case "alpha": {
					if (notEmpty && !this.isAlpha(fldObj.value)) {
						if (noCustomError) errorStr = currObj.lbl + ' can only contain letters.';
						isValid = false;
					}
					break;
				}
				case "alphaNumeric": {
					if (notEmpty && !this.isAlphaNumeric(fldObj.value)) {
						if (noCustomError) errorStr = currObj.lbl + ' can only contain alpha-numeric characters.';
						isValid = false;
					}
					break;
				}
				case "aphaNumericHyphen": {
					if (notEmpty && !this.isAlphaNumericHyphen(fldObj.value)) {
						if (noCustomError) errorStr = currObj.lbl + ' can only contain A-Z,a-z,0-9,- and _ characters.';
						isValid = false;
					}
					break;
				}
				case "numeric": {
					if (notEmpty && !this.isNumeric(fldObj.value)) {
						if (noCustomError) errorStr = currObj.lbl + ' can only contain numbers.';
						isValid = false;
					}
					break;
				}
				case "lessThan": {
					if (notEmpty && !this.isLessThan(fldObj.value, cmdValue)) {
						if (noCustomError) errorStr = currObj.lbl + ' should be less than ' + cmdValue;
						isValid = false;
					}
					break;
				}
				case "greaterThan": {
					if (notEmpty && !this.isGreaterThan(fldObj.value, cmdValue)) {
						if (noCustomError) errorStr = currObj.lbl + ' should be greater than ' + cmdValue;
						isValid = false;
					}
					break;
				}
				case "regExp": {
					if (notEmpty && !this.regExp(fldObj.value, cmdValue)) {
						if (noCustomError) errorStr = 'Invalid characters found.';
						isValid = false;
					}
					break;
				}
				case "dontSelect": {
					if (!this.dontSelect(fldObj.selectedIndex, cmdValue)) {
						if (noCustomError) errorStr = 'Please choose ' + currObj.lbl + '.';
						isValid = false;
					}
					break;
				}				
			}

			if (!isValid) {
				alert(errorStr);
				if (phone1 != '') this[phone1].focus();
				else fldObj.focus();
				return false;
			}			
		}
		return true;
	}

	this.setCustomValidator = function(functionName) { this.frmObj.customValidator = functionName; }	
	this.removeCustomValidator = function() { this.frmObj.customValidator = null; }

	this.frmObj.isValidEmail = function(value) { var regex = /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; return regex.test(value); }
	this.frmObj.isEmpty = function (value) { return value.length == 0; }	
	this.frmObj.isOverMaxLength = function (value, maxLength) { return value.length > maxLength; }	
	this.frmObj.isUnderMinLength = function (value, minLength) { return value.length < minLength; }	
	this.frmObj.isAlphaNumeric = function (value) { return (value.length > 0 && value.search("[^A-Za-z0-9]") < 0); }	
	this.frmObj.isAlpha = function (value) { return (value.length > 0 && value.search("[^A-Za-z]") < 0); }	
	this.frmObj.isAlphaNumericHyphen = function (value) { return (value.length > 0 && value.search("[^A-Za-z0-9\-_]") < 0); }	
	this.frmObj.isNumeric = function (value) {	return (value.length > 0 && value.search("[^0-9]") < 0); }	
	this.frmObj.isLessThan = function (value, cmdValue) { return isNaN(value) || eval(value) >= eval(cmdValue); }	
	this.frmObj.isGreaterThan = function (value, cmdValue) { return isNaN(value) || eval(value) <= eval(cmdValue);	}	
	this.frmObj.regExp = function (value, cmdValue) {	return value.length > 0 && value.match(cmdValue); }	
	this.frmObj.dontSelect = function (value, cmdValue) { return value != null && value != eval(cmdValue);	}
}
