/*
VERSION:
12/13/2008	1.0.4 Added methods `clearHilite` and `setHilite`. 
					Added 4th argument to`addItem` - "hiliteElem".
					Reorganized several methods.
10/22/2008	1.0.3 Changed the `validationType` argument of method `addItem` to `validator`, 
					and gave it the ability to also pass a callback function.
					Removed the 4th argument `comparison`, but it can still be passed for a `validator` of type "select".
					Updated method `isChecked`. Updated some error trapping. Streamlined the file a bit.
7/10/2008		1.0.2	Reversed the array before joining the string at the end of method `callAlert`.
3/5/2008		1.0.1	Updated 'numeric' regular expression to accept
					negative and decimal numeric values
					1.0.0	Begin versioning.
*/
function Validation(formRef, alertType) {
//this object is for simple validation only
//if an item's validation relies upon multiple factors
//other than its own value, then other means are necessary
//as of this writing
this.f = formRef;
this.alertType = alertType; //1 = window.alert only, 2 = hilite only, anything else = both
this.alertOverride = ""; //will replace default alert if present
this.borderClr = "red";
this.backgroundClr = "yellow";
this.textClr = "";
this.inputs = new Array();

/**METHODS**/

this.addItem = function(formElementName, alertMsg, validator, hiliteElem) {
/*
The argument `validator` can be of type string or function.
If `validator` is a function, it passes the element itself to the callback, which should return a true or false value.
If `validator` is a string (defaults to "string"), it must be one of the built-in validators listed in method `validateString`.
The following built-in validators have different behaviors:
	select - returns true if select.selectedIndex > 0. If a 5th argument is provided, returns true if selected option value matches argument.
	selectmultiple - returns true if at least one item is selected.
	radio, checkbox - returns true if at least one item is checked.
`hiliteElem	` is an optional string id of a an html element to hilite alternatively to the element itself.
*/
this.inputs.push({	
	elem: formElementName, //string req
	msg: alertMsg, //req
	val: validator, //opt
	comparison: arguments[4], //opt
	ok: true, //internal use,
	he: hiliteElem
});
};
this.callAlert = function() {
	var i = this.inputs.length-1;
	var arMsg = new Array();
	var thisItem;
	var thisElem;
	for(var i = this.inputs.length-1; i >= 0; i--) {
		thisItem = this.inputs[i];
		thisElem = typeof(thisItem.he) == 'string' && thisItem.he != '' ? getRef(thisItem.he) : this.f[thisItem.elem];
		
		if(!thisItem.ok) {
			switch(this.alertType) {
				case 1 :
					arMsg.push(thisItem.msg);
					break;
				case 2 :
					this.setHilite(thisElem);
					break;
				default :
					arMsg.push(thisItem.msg);
					this.setHilite(thisElem);
					break;
			}
		}
	}
	if(arMsg.length > 0) {
		if(this.alertOverride.length > 0) {
			window.alert(this.alertOverride);
			return false;
		}
		window.alert("Please correct the following:\n" + arMsg.reverse().join("\n"));
	}
	return false;
};
this.clearHilite = function(elem) {
	if(elem && elem.style) {
		elem.style.borderColor = '';
		elem.style.backgroundColor = '';
		elem.style.color = '';
	}
};
this.clearHilites = function() {
	var inp;
	for(var i = this.inputs.length-1; i >= 0; i--) {
		inp = this.inputs[i];
		inp = typeof(inp.he) == 'string' && inp.he != '' ? getRef(inp.he) : this.f[inp.elem];
		this.clearHilite(inp);
	}
};
this.isChecked = function(checkGroup) {
	/**** RETURNS FALSE IF NO BOXES ARE CHECKED, TRUE OTHERWISE ****/
	if(checkGroup === undefined) { return false; }
	if(typeof(checkGroup[0]) == "undefined") {
		return checkGroup.checked; //if only one element in the group
	}
	var i = checkGroup.length-1;
	while(i >= 0) {
		if(checkGroup[i].checked == true) {
			return true;
		}
		i--;
	}
	return false;
};
this.setHilite = function(elem) {
if(elem.style) {
	switch(elem.type) {
		case 'select-one' : case 'select-multiple' :
			elem.style.color = this.textClr;
			break;
		default :
			elem.style.borderColor = this.borderClr;
			elem.style.backgroundColor = this.backgroundClr;
			elem.style.color = this.textClr;
	}
}
};
this.validate = function() {
	this.clearHilites();
	var i = this.inputs.length-1;
	var thisItem;
	var thisElem;
	var er = false;
	while(i >= 0) {
		thisItem = this.inputs[i];
		if(typeof(this.f[thisItem.elem]) == "undefined") { alert('Error: The item \'' + thisItem.elem + '\' is not a valid field.'); i--; continue; }
		thisElem = this.f[thisItem.elem];
		if(typeof(thisItem.val) != "function") {
			switch(thisItem.val) {
			case 'radio' : case 'checkbox' :
				thisItem.ok = this.isChecked(thisElem);
				break;
			case 'select' :
				if(thisItem.comparison === undefined) {
					if(thisElem.selectedIndex == 0) {
						thisItem.ok = false;
					}
				} else {
					if(thisElem[thisElem.selectedIndex].value != thisItem.comparison) {
						thisItem.ok = false;
					}
				}
				break;
			case 'selectmultiple' :
				if(thisElem.selectedIndex == -1) {
					thisItem.ok = false;
				}
				break;
			default :
				thisItem.ok = this.validateString(thisElem.value, thisItem.val);
			} //end switch
		} else {
			thisItem.ok = thisItem.val(thisElem);
		}
		if(!thisItem.ok) { er = true; }
		i--;
	}
	if(er == true) {
		return this.callAlert();
	} else {
		return true;
	}
	
};
this.validateString = function(str, validator) {
if(typeof(str) != "string") { return false; }
var objRegExp;
switch(validator) {
case 'phone_full' : //xxX-XXX-XXX-XXXX w/req country code digits, strict
objRegExp  = /^\d{1,3}\-\d{3}\-\d{3}\-\d{4}$/;
break;
case 'phone' :  //xxx-XXX-XXX-XXXX w/opt country code digits and req area code.
objRegExp  = /^(\d{1,3}\-)?\d{3}\-\d{3}\-\d{4}$/;
break;
case 'phone_part' :  //xxx-XXX-XXXX w/opt area code
objRegExp  = /^(\d{3}\-)?\d{3}\-\d{4}$/;
break;
case 'email' :
objRegExp  = /^[a-z0-9]([a-z0-9_\-\.]*)@([a-z0-9_\-\.]*)(\.[a-z]{2,3}(\.[a-z]{2}){0,2})$/i;
break;
case 'state' :
objRegExp = /^(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NB|NC|ND|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)$/i; 
break;
case 'zip' :
objRegExp  = /(^\d{5}$)|(^\d{5}-\d{4}$)/;
break;
case 'ssn' :
objRegExp  = /^\d{3}\-\d{2}\-\d{4}$/;
break;
case 'alpha' :
objRegExp = /[^A-Za-z]/;
break;
case 'numeric' :
objRegExp = /-?[0-9]+\.?[0-9]+?$/;
break;
case 'alphanumeric' : //numbers and letters only
objRegExpr = /[^A-Za-z0-9]/;
break;
case 'maxlength' :
var l = (formItem.comparison === undefined || isNaN(formItem.comparison) ? 1 : formItem.comparison);
return (str.length <= l ? true : false);
case 'minlength' :
var l = (formItem.comparison === undefined || isNaN(formItem.comparison) ? 1 : formItem.comparison);
return (str.length >= l ? true : false);
default : //any non-empty string
var v = str.replace(/^\s+/,'').replace(/\s+$/,''); //trim spaces
return (v.length > 0 ? true : false);
} //end switch

return (str.search(objRegExp) > -1 ? true : false);
	
};

}; //end Validation