// $Revision: 2853 $
function ValidateAllInputs(formId) {
	var form = getElement(unEscape(formId));
	if (form == null || form.tagName.toLowerCase() != "form") {
		return false;
	}
	return DoValidateAllInputs(form);
}

function DoValidateAllInputs(form) {
	return DoValidateInputs(form, form.elements);
}

function DoValidateInputs(form, elems) {
	if (form == null) {
	    return false;
	}
	// optimization: if form has attribute hasvalidations='false', skip validation
	var hasValidations;
	if (isIE) {
		hasValidations = form.hasvalidations;
	} else {
		hasValidations = form.getAttribute("hasvalidations");
	}
	if (hasValidations == null || hasValidations == "false") {
		return true;
	}
	var R = true;
	var r = true;
	for (var i = 0; i < elems.length; i++) {
		var elem = elems[i];
		if (elem != null) {
			ClearErrorMsg(elem);
		}
	}
	for (var i = 0; i < elems.length; i++) {
		var elem = elems[i];
		if (elem != null) {
			var last_r = r;
			r = (ValidateInput(form, elem) && r);
			if (r != last_r) {
				DoScrollIntoViewAbsolute(elem, false, 100);
			}
			R = r && R;
		}
	}
	return R;
}

function ValidateInput(form, elem) {
	if (elem == null || !IsVisibleElement(elem, true)) {
		return true;
	}
	if (elem.type == "hidden" || elem.disabled) {
		return true;
	}
	var masterName = elem.getAttribute("mastername");
	var masterValue = elem.getAttribute("mastervalue");
	// ignore this element if master not set
	if (masterName != null && !IsValueSet(elem.form, masterName, masterValue)) {
		return true;
	}
	var label = elem.getAttribute("label");
	var value = elem.value;
	var isRequired = elem.getAttribute("required") != null;
	// check required
    if (isRequired && IsEmpty(value)) {
		DoSetErrorMsg(elem, (label != null ? label + ": " : "") + "Value required.");
		return false;
    }
	var validations = eval(elem.getAttribute("validation"));
	if (IsEmpty(validations)) {
		return true;
	}
	var explicitMsg = elem.getAttribute("validationmsg");
    // perform other configured validations
    var R = true;
    var msg = null;
    for (var i = 0; i < validations.length; i++) {
        var v = validations[i].split("=");
        var vname = v[0];
        var vval = v.length > 1 ? v[1] : null;
        var r = true;
		switch (elem.type) {
			case "select-one":
			case "select-multiple":
				switch (vname) {
					case "minselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNSelected(elem) < vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select at least " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
					case "maxselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNSelected(elem) > vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select no more than " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
					case "exactselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNSelected(elem) != vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
				}
				break;
			case "checkbox":
				switch (vname) {
					case "minselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNChecked(elem) < vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select at least " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
					case "maxselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNChecked(elem) > vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select no more than " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
					case "exactselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNChecked(elem) != vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
				}
				break;
			case "radio":
				switch (vname) {
					case "exactselected":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (GetNRadio(elem) != vval) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label + ": " : "") + "Must select " + vval + " value" + ((vval > 1) ? "s." : "."));
							r = false;
						}
						break;
				}
				break;
			default:
				// other element types - mainly text inputs
				if (IsEmpty(value)) {
					continue;
				}
				switch (vname) {
					case "numeric":
						if (!IsEmpty(value) && isNaN(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a number.");
							r = false;
						}
						break;
					case "integer":
						if (!IsEmpty(value) && !/^-?\d+$/.test(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be an integer.");
							r = false;
						}
						break;
					case "digits":
						if (!IsEmpty(value) && !/^\d+$/.test(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a string of decimal digits.");
							r = false;
						}
						break;
					case "zip":
						if (!IsEmpty(value) && !/^\d{5}$/.test(value) && !/^\d{5}[ -]?\d{4}$/.test(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a valid 5-digit or 9-digit Zip Code. &ldquo;-&rdquo; or &ldquo; &rdquo; can separate the first 5 digits from the last 4 digits.");
							r = false;
						}
						break;
					case "townshiprange":
						var n = parseInt(value);
						var a = value.split(/\s+/);
						var fraction = null;
						if (a.length > 1) {
							fraction = a[1];
						}
						if (isNaN(n) || n < 1 || n > parseInt(vval) || (fraction != null && !/^[13]\/4$/.test(fraction) && !/^1\/2$/.test(fraction))) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a number between 1 and " + vval + " inclusive, plus (optionally) &ldquo;1/4&rdquo;, &ldquo;1/2&rdquo;, or &ldquo;3/4&rdquo;.");
							r = false;
						}
						break;
					case "section":
						var n = parseInt(value);
						if (!IsEmpty(value) && (isNaN(n) || n < 1 || n > vval || !/^[0-9]+[UD]?$/i.test(value))) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a number between 1 and " + vval + " inclusive, plus (optionally) &ldquo;U&rdquo; or &ldquo;D&rdquo;.");
							r = false;
						}
						break;
					case "minwordlength":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						var minwordlengthpattern = new RegExp("\\S{" + parseInt(vval) + ",}");
						if (!IsEmpty(value) && !minwordlengthpattern.test(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Words must be at least " + vval + " characters long.");
							r = false;
						}
						break;
					case "ifnotonwordboundaries":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						var onwordboundaries = elem.form.searchonwordboundaries;
						if (onwordboundaries == null || onwordboundaries.checked) {
							continue;
						}
						var onwordboundariesLabel = onwordboundaries.label;
						if (IsEmpty(onwordboundariesLabel)) {
							onwordboundariesLabel = onwordboundaries.getAttribute("label");
						}
						var minwordlengthpattern = new RegExp("\\S{" + parseInt(vval) + ",}");
						if (!IsEmpty(value) && !minwordlengthpattern.test(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": If &ldquo;" + onwordboundariesLabel + "&rdquo; is not checked, words must be at least " + vval + " characters long.");
							r = false;
						}
						break;
					case "minvalue":
						if (isNaN(value) || vval == null) {
							continue;
						}
						if (isNaN(vval)) {
							var peer = eval("elem.form." + vval);
							if (peer == null) {
								continue;
							}
							if (isNaN(peer.value)) {
								continue;
							}
							var peerLabel = peer.getAttribute("label");
							if (parseFloat(value) < parseFloat(peer.value)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be >= " + (peerLabel != null ? peerLabel : peer.value) + ".");
								r = false;
							}
						} else {
							if (parseFloat(value) < parseFloat(vval)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be >= " + vval + ".");
								r = false;
							}
						}
						break;
					case "maxvalue":
						if (isNaN(value) || vval == null) {
							continue;
						}
						if (isNaN(vval)) {
							var peer = eval("elem.form." + vval);
							if (peer == null) {
								continue;
							}
							if (isNaN(peer.value)) {
								continue;
							}
							var peerLabel = peer.getAttribute("label");
							if (parseFloat(value) > parseFloat(peer.value)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be <= " + (peerLabel != null ? peerLabel : peer.value) + ".");
								r = false;
							}
						} else {
							if (parseFloat(value) > parseFloat(vval)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be <= " + vval + ".");
								r = false;
							}
						}
						break;
					case "greaterthan":
						if (isNaN(value) || vval == null) {
							continue;
						}
						if (isNaN(vval)) {
							var peer = eval("elem.form." + vval);
							if (peer == null) {
								continue;
							}
							if (isNaN(peer.value)) {
								continue;
							}
							var peerLabel = peer.getAttribute("label");
							if (parseFloat(value) <= parseFloat(peer.value)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be > " + (peerLabel != null ? peerLabel : peer.value) + ".");
								r = false;
							}
						} else {
							if (parseFloat(value) <= parseFloat(vval)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be > " + vval + ".");
								r = false;
							}
						}
						break;
					case "lessthan":
						if (isNaN(value) || vval == null) {
							continue;
						}
						if (isNaN(vval)) {
							var peer = eval("elem.form." + vval);
							if (peer == null) {
								continue;
							}
							if (isNaN(peer.value)) {
								continue;
							}
							var peerLabel = peer.getAttribute("label");
							if (parseFloat(value) >= parseFloat(peer.value)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be < " + (peerLabel != null ? peerLabel : peer.value) + ".");
								r = false;
							}
						} else {
							if (parseFloat(value) >= parseFloat(vval)) {
								msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be < " + vval + ".");
								r = false;
							}
						}
						break;
					case "minlength":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (value.length < parseInt(vval)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be at least " + vval + " characters.");
							r = false;
						}
						break;
					case "maxlength":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (value.length > parseInt(vval)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be no longer than " + vval + " characters.");
							r = false;
						}
						break;
					case "exactlength":
						if (vval == null || isNaN(vval)) {
							continue;
						}
						if (value.length != parseInt(vval)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be exactly " + vval + " characters.");
							r = false;
						}
						break;
					case "email":
						if (!IsEmpty(value) && !IsEmailAddress(value)) {
							msg = FormatMsg(msg, explicitMsg, (label != null ? label : Truncate(value)) + ": Must be a valid email address.");
							r = false;
						}
						break;
				}
				break;
		}
		R = R && r;
	}
	if (!R) {
		DoSetErrorMsg(elem, msg);
	}
	return R;
}
var atomPat = "[a-z0-9!#$%&\\'\\*\\+\\-/=\\?^_`{|}~]";
var dotAtomPat = atomPat + "+(\\." + atomPat + "+)*";
var quotedStringPat = "\\\"[^\\\"]*\\\"";
var topLevelPat = "(aero|arpa|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|travel|[a-z]{2})";
var addrSpecPat = "(" + dotAtomPat + "|" + quotedStringPat + ")@" + dotAtomPat + "\\." + topLevelPat;
var nameAddrPat = "[^<]*\\s+<" + addrSpecPat + ">";
var addrSpecRE = new RegExp("^" + addrSpecPat + "$", "i");
var nameAddrRE = new RegExp("^" + nameAddrPat + "$", "i");

function IsEmailAddress(value) {
	value = value.replace(/^\s*(\S.*\S)\s*$/, "$1");
	var i = value.indexOf("@");
	if (i < 0 || i > 64 || (value.length - i > 255)) {
		return false;
	}
	return addrSpecRE.test(value) || nameAddrRE.test(value);
}

function GetNSelected(select) {
	if (select.selectedIndex < 0) {
		return 0;
	}
	var n = 0;
	for (var i = 0; i < select.length; i++) {
		if (select.options[i].selected && select.options[i].value != "emptyselectoption") {
			n++;
		}
	}
	return n;
}

function GetNChecked(checkbox) {
	var n = 0;
	var elements = checkbox.form.elements;
	for (var i = 0; i < elements.length; i++) {
		var elem = elements[i];
		if (elem.type == "checkbox" && elem.name == checkbox.name && elem.checked) {
			n++;
		}
	}
	return n;
}

function GetNRadio(radio) {
	var n = 0;
	var elements = radio.form.elements;
	for (var i = 0; i < elements.length; i++) {
		var elem = elements[i];
		if (elem.type == "radio" && elem.name == radio.name && elem.checked) {
			n++;
		}
	}
	return n;
}

function IsValueSet(form, name, value) {
	if (form == null || name == null) {
		return false;
	}
	var elements = form.elements;
	for (var i = 0; i < elements.length; i++) {
		var elem = elements[i];
		if (elem.name == name) {
			switch (elem.type) {
				case "checkbox":
				case "radio":
					if (elem.value == value) {
						return elem.checked;
					}
					break;	
				case "text":
					return elem.value != null && elem.value.length > 0;
					break;
			}
		}
	}
	return false;
}

var MAX_TRUNC = 30;

function Truncate(s) {
	return s.length <= MAX_TRUNC ? s : s.substring(0, MAX_TRUNC) + "...";
}

// replace msg with explicitMsg, if present, else append defaultMsg
function FormatMsg(msg, explicitMsg, defaultMsg) {
	if (explicitMsg != null) {
		return explicitMsg;
	}
	if (msg == null) {
		return defaultMsg;
	}
	return msg + "<br>" + defaultMsg;
}

function ClearErrorMsg(elem) {
    var valId = elem.getAttribute("validationId");
    if (valId == null) {
        return;
    }
    var val = getElement(valId);
    if (val == null) {
        return;
    }
    val.innerHTML = "";
    var row = GetAncestorByTagName(val, "tr");
    row.style.display = "none";
}

function SetErrorMsg(formId, name, msg) {
	var form = getElement(formId);
	if (form == null) {
		return;
	}
	var elem = eval("form." + name);
	if (elem != null) {
		DoSetErrorMsg(elem, msg);
	}
}

function DoSetErrorMsg(elem, msg) {
    var valId = elem.getAttribute("validationId");
    if (valId == null) {
        return;
    }
    var val = getElement(valId);
    if (val == null) {
        return;
    }
    val.innerHTML += msg + '<br>'
    var row = GetAncestorByTagName(val, "tr");
    row.style.display = "";
}
