/* FormValidator.js written by Wayne Woodfield

Form Validator is an object oriented form validation tool that checks for text field, checkbox, radio, and checkbox values.
For text values, special conditions may also be added to check for numbers, e-mail addresses, etc.

To create a FormValidator:
1) Call the FormValidator constructor with the form name as a parameter.
2) Use the FormValidator.addField(name, display, special) method to add required fields.  This method is further detailed below.
3) In your HTML, add an "onSubmit" listener to your form (or an "onClick" to your submit button) that calls FormValidator.validate();

If any field entered is missing when validate() is called, an alert box will appear with a list of all missing or malformed fields.
FormValidator.validate() will return true if there were no problems, false if an alert box appeared.  This means that your form tag
in your HTML may look like this: <form action="index.html" name="formname" onsubmit="return fv.validate();">

The "return" part of this form tag's "onsubmit" action is important, since returning false causes the form to cancel submitting.
If you forget it, even though things were missing and an alert box appears, the form will still submit.

The addField method takes between 1-3 parameters.  The parameters are:
1) name: The name of the field in the form to validate
2) display: The user viewable name for this missing field.  This is what will be displayed in the alert box if this field is missing or malformed.
3) special: Besides just checking for blank fields, a special value will tell the FormValidator that another check is required.
	Possible values for special are:
		email: Must be a valid e-mail address
		number: Must be a number, integer or double, positive or negative
		int: Must be an integer, positive or negative
		natural: Must be a positive integer
		positive: Must be a positive number, integer or double
		length: takes one integer argument, specifies that the field must be a minimum length
		match: takes one string argument, specifies that this field must match the given field
*/
function VField(name) {
	this.name = name;
	this.display = name;
	this.special = null;
	this.specialArg = null;
	this.newSpecial = null;
	this.newSpecialArg = null;
}

function FormValidator(formname) {
	this.formname = formname;
	this.fields = new Array();
}

function fv_addField(name, display, special, specialArg, newSpecial, newSpecialArg) {
	var v = new VField(name);
	if (typeof(display) != "undefined" && display != null) v.display = display;
	if (typeof(special) != "undefined" && special != null) v.special = special;
	if (typeof(specialArg) != "undefined" && specialArg != null) v.specialArg = specialArg;
	if (typeof(newSpecial) != "undefined" && newSpecial != null) v.newSpecial = newSpecial;
	if (typeof(newSpecialArg) != "undefined" && newSpecialArg != null) v.newSpecialArg = newSpecialArg;
	this.fields[this.fields.length] = v;
}
FormValidator.prototype.addField = fv_addField;

function fv_validate(vfield) {
	var badform = eval("typeof(document." + this.formname + ") == 'undefined';");
	if (badform) {
		alert("FormValidator error: There is no form named \"" + this.formname + "\"");
		return false;
	}
	if (typeof(vfield) == "undefined") {
		var errors = "";
		for (var i = 0; i < this.fields.length; i++) {
			var result = this.validate(this.fields[i]);
			if (result == "") result = this.fields[i].display;
			else if (result != null) result = this.fields[i].display + " (" + result + ")";
			if (result != null) errors += " - " + result + "\n";
		}
		if (errors != "") {
			alert("The following required information is missing or malformed:\n\n" + errors);
			return false;
		}
		return true;
	}
	var badfield = eval("typeof(document." + this.formname + "." + vfield.name + ") == 'undefined';");
	if (badfield) {
		alert("FormValidator error: There is no field named \"" + vfield.name + "\" in form \"" + this.formname + "\"");
		return "doesn't exist in form";
	}
	var el = eval("document." + this.formname + "." + vfield.name);
	// checkboxes
	if (vfield.special == "checked") return el.checked ? null : "must be checked";
	// radio buttons
	if (typeof(el.length) != "undefined" && typeof(el[0]) != "undefined" && typeof(el[0].checked) != "undefined") {
		for (var i = 0; i < el.length; i++) {
			if (el[i].checked) return null;
		}
		return "none checked";
	}
	// select boxes
	if (typeof(el.options) != "undefined") {
		if (el.selectedIndex == -1) return "nothing selected";
		if (typeof(el.value) != "undefined" && el.value != "") return null;
		var whichselect = -1;
		for (var i = 0; i < el.options.length; i++) {
			if (i != el.selectedIndex && el.options[i].value == "") {
				return (el.selectedIndex == 0 ? "select one" : null);
			}
		}
		return "select one";
	}
	// text boxes
	if (typeof(el.value) != "undefined") {
		if (vfield.special == "checkRequired") {
			var requiredChecked = eval("document." + this.formname + "." + vfield.specialArg + ".checked");
			if(requiredChecked) {
				vfield.special = vfield.newSpecial;
				vfield.newSpecial = "specialChanged";
				newSpecialArgToBe = vfield.specialArg;
				vfield.specialArg = vfield.newSpecialArg;
				vfield.newSpecialArg = newSpecialArgToBe;
			} else {
				return null;
			}
		}
		if (vfield.newSpecial == "specialChanged") { 
			var requiredChecked = eval("document." + this.formname + "." + vfield.newSpecialArg + ".checked");
			if(!requiredChecked) return null;
		}
		if (vfield.special == "match") {
			var el2 = eval("document." + this.formname + "." + vfield.specialArg);
			if (el.value != el2.value) return "";
			return null;
		}
		if (el.value == null || el.value == "") return "";
		if (vfield.special == null) return null;
		if (vfield.special == "email") {
			eval("re = /\.+\\@\.+\\.\.+/;");
			return el.value.search(re) == -1 ? "invalid e-mail address" : null;
		}
		if (vfield.special == "number") {
			var num = Number(el.value);
			return isNaN(num) ? "must be a number" : null;
		}
		if (vfield.special == "int") {
			var num = Number(el.value);
			if (isNaN(num)) return "must be a number";
			return el.value.indexOf(".") != -1 ? "must be an integer" : null;
		}
		if (vfield.special == "natural") {
			var num = Number(el.value);
			if (isNaN(num)) return "must be a number";
			if (el.value.indexOf(".") != -1) return "must be an integer";
			return num < 0 ? "must be positive" : null;
		}
		if (vfield.special == "counting") {
			var num = Number(el.value);
			if (isNaN(num)) return "must be a number";
			if (el.value.indexOf(".") != -1) return "must be an integer";
			if (num < 0) return "must be positive";
			return num == 0 ? "must be greater than zero" : null;
		}
		if (vfield.special == "positive") {
			var num = Number(el.value);
			if (isNaN(num)) return "must be a number";
			return num < 0 ? "must be positive" : null;
		}
		if (vfield.special == "length") {
			if (el.value.length < vfield.specialArg) return "Must be " + vfield.specialArg + " or more characters long";
		}
	}
	return null;
}
FormValidator.prototype.validate = fv_validate;