if (!Array.prototype.push) {
	Array.prototype.push=function () {
		for (var iArg=0;iArg<arguments.length;iArg++) this[this.length]=arguments[iArg];
		return this.length;
	}
}

Array.prototype.indexOf=function (vVar,sProp) {
	var iItem=0;

	while (iItem<this.length && this[iItem]!=vVar) iItem++;

	return iItem==this.length ? -1 : iItem;
}

Array.prototype.remove=function (iIndex) {
	if (iIndex<0 || iIndex>=this.length) return;
	for (var iItem=iIndex+1;iItem<this.length;iItem++) this[iItem-1]=this[iItem];
	this.length--;

	return this;
}
String.prototype.toRX=function () {
	return this.replace(/(\(|\)|\[|\]|\{|\}|\.|\*|\+|\?|\:|\=|\!|\^|\$|\||\,|\-|\\|\/)/g,"\\$1");
}

var Validator={
	templates:{
		email:[ /^[\w\-\.]+@([a-z0-9\-]+\.)+[a-z]{2,4}$/,"a valid e-mail address" ],
		numeric:[ /^-?\d+$/,"digits" ],
		"float":[ /^-?\d+(\.\d+)?$/,"float number" ],
		url:[ /^(https?|ftp):\/\/([\w\-]+\.)+\w{2,4}\/?.*$/,"a valid url address" ]
	},

	check:function (oForm) {
		var oInp,
			oEl,
			sType,
			sErr="",
			sCurrErr="";

		this.checkboxes=[];

		for (var iInp=0;iInp<oForm.length;iInp++) {
			oInp=oForm[iInp];
			if (oInp.getAttribute("desc")==null) {
				try {
					oEl=oInp.parentNode.previousSibling;
					while (oEl.nodeName.toLowerCase()!="label" && oEl.previousSibling) oEl=oEl.previousSibling;
					oInp.setAttribute("desc",oEl.innerHTML);
				}
				catch (oErr) {}
			}

			if (oInp.type && !oInp.disabled && (sCurrErr=this.validator[this.types[oInp.type]](oInp))) sErr+=sCurrErr;
		}

		if (sErr) {
			alert("The following errors occured:\n"+sErr);
			return false;
		}

		return true;
	},

	checkboxes:[],

	types:{
		"text":0,
		"hidden":0,
		"textarea":0,
		"password":0,
		"file":0,
		"submit":0,
		"button":0,
		"radio":1,
		"checkbox":2,
		"select-one":3,
		"select-multiple":3
	},

	validator:[
		// text
		function (oInp) {
			if (oInp.getAttribute("template") && !Validator.templates[oInp.getAttribute("template")]) throw new Error("No such template '"+oInp.getAttribute("template")+"'");

			if (oInp.getAttribute("required")!=null && !oInp.value) return "\n* '"+oInp.getAttribute("desc")+"' is a required field.";

			if (oInp.getAttribute("template")!=null && oInp.value && !Validator.templates[oInp.getAttribute("template")][0].test(oInp.value)) return "\n* '"+oInp.getAttribute("desc")+"' should contain "+Validator.templates[oInp.getAttribute("template")][1]+".";

			if (oInp.getAttribute("min")!=null || oInp.getAttribute("max")!=null) {
				var iMin=+oInp.getAttribute("min"),
					iMax=+oInp.getAttribute("max");

				if (oInp.getAttribute("template")=="numeric" || oInp.getAttribute("template")=="float") {
					if (
						oInp.value
						&&
						(
							(iMax && +oInp.value>iMax)
							||
							(iMin && +oInp.value<iMin)
						)
					) {
						return "\n* '"+oInp.getAttribute("desc")+"' should be"+
							(iMin ? " over "+iMin : "")+
							(iMin && iMax? " and" : "")+
							(iMax ? " under "+iMax : "")+
							".";
					}
				}
				else if (+oInp.value.length>iMax || +oInp.value.length<iMin) {
					return "\n* '"+oInp.getAttribute("desc")+"' length should be"+
						(iMin ? " over "+iMin : "")+
						(iMin && iMax ? " and" : "")+
						(iMax ? " under "+iMax : "")+
						".";
				}
 			}

			if (oInp.getAttribute("rx")!=null && oInp.getAttribute("rxerror")!=null && !new RegExp(oInp.getAttribute("rx"),oInp.getAttribute("rxflags")).test(oInp.value)) return "\n* '"+oInp.getAttribute("desc")+"' "+oInp.getAttribute("rxerror");
		},

		// radio
		function (oInp) {
			var oRadios,
				iRd=0;

			if (oInp.getAttribute("required")!=null) {
				oRadios=oInp.form[oInp.name];

				if (!oRadios) return "";

				while (iRd<oRadios.length && !oRadios[iRd].checked) iRd++;

				if (iRd==oRadios.length) return "\n* '"+oInp.getAttribute("desc")+"'  is a required field, please select one.";
			}
		},

		// checkbox
		function (oInp) {
			var oChecks=oInp.form[oInp.name],
				iChecked=0,
				aErrors=[];

			if (Validator.checkboxes.indexOf(oChecks)>-1) return "";
			Validator.checkboxes.push(oChecks);

			if (!oChecks) return "";

			if (oChecks.length && (oInp.getAttribute("min")!=null || oInp.getAttribute("max")!=null)) {
				if (oInp.getAttribute("min")==null) {
					if (oInp.getAttribute("required")!=null) oInp.setAttribute("min",1);
					else oInp.setAttribute("min",0);
				}
				if (oInp.getAttribute("max")==null) oInp.setAttribute("max",oChecks.length);

				if (oInp.getAttribute("min")!=null && oInp.getAttribute("max")!=null) {
					oChecks=oInp.form[oInp.name];

					if (oChecks.length) {
						for (var iChk=0;iChk<oChecks.length;iChk++) if (oChecks[iChk].checked) iChecked++;
					}
					else iChecked=oInp.checked;

					if (iChecked<oInp.getAttribute("min") || iChecked>oInp.getAttribute("max")) {
						if (oInp.getAttribute("min")>0) aErrors.push("at least "+oInp.getAttribute("min")+" selected option"+(oInp.getAttribute("min")>1 ? "s" : ""));
						if (oInp.getAttribute("max")<oChecks.length) aErrors.push("at most "+oInp.getAttribute("max")+" selected option"+(oInp.getAttribute("max")>1 ? "s" : ""));

						return "\n* '"+oInp.getAttribute("desc")+"' should contain "+aErrors.join(" and ")+".";

						//"at least "+oInp.getAttribute("min")+" selected option"+(() ? "s" : "") +" and at most "+oInp.getAttribute("max")+" selected options.";
					}
				}
			}
			else if (!oInp.checked && oInp.getAttribute("required")!=null) return "\n* "+(oInp.getAttribute("error") ? oInp.getAttribute("error") : "'"+oInp.getAttribute("desc")+"' is a required field.");
		},

		// select
		function (oInp) {
			var iSelected=0,
				iOpt=0;

			if (oInp.multiple) {
				if (oInp.getAttribute("min")==null) oInp.setAttribute("min",1);
				if (oInp.getAttribute("max")==null) oInp.setAttribute("max",oInp.length);

				for (var iOpt=0;iOpt<oInp.options.length;iOpt++) {
					if (oInp.options[iOpt].selected) {
						if (oInp.getAttribute("invalid")!=null && iOpt==+oInp.getAttribute("invalid")) return "\n* '"+oInp.getAttribute("desc")+"' "+(oInp.getAttribute("required") ? "has no selected option or " : "")+"contains a disallowed selected option.";
						iSelected++;
					}
				}

				if (iSelected<+oInp.getAttribute("min") || iSelected>+oInp.getAttribute("max")) return "\n* '"+oInp.getAttribute("desc")+"' should contain at least "+oInp.getAttribute("min")+" selected options and at most "+oInp.getAttribute("max")+" selected options."
			}
			else {
				if (oInp.getAttribute("required") && oInp.getAttribute("invalid")==null) oInp.setAttribute("invalid","0");
				if (oInp.getAttribute("invalid")!=null && oInp.selectedIndex==+oInp.getAttribute("invalid")) return "\n* '"+oInp.getAttribute("desc")+"' "+(oInp.getAttribute("required") || oInp.getAttribute("invalid")=="0" ? "has no selected option." : "contains a disallowed selected option.");
			}
		}
	],

	// Textarea

	// onkeypress="return Validator.limit(this)"
	limit:function (oTA) {
		if (+oTA.value.length==oTA.getAttribute("maxlength")) return false;
	},

	// onkeyup="return Validator.count(this)"
	count:function (oTA,oCnt) {
		if (oTA.value.length>+oTA.getAttribute("maxlength")) oTA.value=oTA.value.substring(0,+oTA.getAttribute("maxlength"));
		if (oCnt) oCnt.innerText=oTA.getAttribute("maxlength")-oTA.value.length;
	}
}