Validator = function(name) {
	this.onblur = false;
	if (!document.forms[name]) {
		alert('Error: could not get form object ' + name + '!');
		return;
	}
	this.o = document.forms[name];
	this.o.old_onsubmit = (this.o.onsubmit ? this.o.onsubmit : null);
	this.o.vsubmit = null;
	this.o.onsubmit = validator_callback;
};

Validator.prototype.set = function(funcname) {
	if (this.o) this.o.vsubmit = funcname;
};


Validator.prototype.clear = function() {
	if (this.o) for (var i = 0; i < this.o.elements.length; i++) this.o.elements[i].validationset = null;
};

validator_callback = function() {
	if (!this) {
		alert('Error: the form object is not set properly!');
		return false;
	}
	for (var i = 0; i < this.elements.length; i++) if (this.elements[i].validationset && !this.elements[i].validationset.validate()) return false;
	if (this.vsubmit) {
		eval('var ret=' + this.vsubmit + '()');
		return ret;
	}
	return true;
};

Validator.prototype.add = function(ename, desc, errstr) {
	var cond = null;
	if (arguments.length > 3) cond = arguments[3];
	if (!this.o) {
		alert('Error: the form object is not set properly!');
		return;
	}
	var e = this.o.elements[ename];
	// for radio button; don't do for 'select' item
	if (e.length && isNaN(e.selectedIndex)) e = e[0];
	if (!e) {
		alert('Error: could not get the element ' + ename + '!');
		return;
	}
	if (this.onblur) e.onblur = element_onblur;
	if (!e.validationset) e.validationset = new ValidationSet(e);
	e.validationset.add(desc, errstr, cond);
	e.validatorobj = this;
};

element_onblur = function() {
	// To avoid repeated looping message boxes
	if (this.validatorobj.disable_validations) {
		this.validatorobj.disable_validations = false;
		return false;
	}
	return (this.validationset == null || this.validationset.validate());
};

ValidationDesc = function(o, desc, error, condition) {
	this.desc = desc;
	this.error = error;
	this.o = o;
	this.condition = condition;
}

ValidationDesc.prototype.validate = function() {
	if (this.condition != null && !eval(this.condition)) return true;
	if (this.validateInput()) {
		return true;
	} else {
		this.o.validatorobj.disable_validations = true;
		this.o.focus();
		return false;
	}
};

ValidationSet = function(o) {
	this.vSet = new Array();
	this.o = o;
};

ValidationSet.prototype.add = function(desc, error, condition) {
	this.vSet[this.vSet.length] = new ValidationDesc(this.o, desc, error, condition);
};

ValidationSet.prototype.validate = function() {
	for (var i = 0; i < this.vSet.length; i++) if (!this.vSet[i].validate()) return false;
	return true;
};

// validation functions
var hasRegExp = (parseInt(navigator.appVersion) >= 4);
function validateEmail(email) {
	if (!hasRegExp) return (email.indexOf('@') > 0);
	var s = email.match(/^(.+)@(.+)$/);
	if (!s) return false;
	if (s[1] != null) if (s[1].match(/^\"?[\w-_\.]*\"?$/) == null) return false;
	if (s[2] != null) return (s[2].match(/^[\w-\.]*\.[A-Za-z]{2,4}$/) != null || s[2].match(/^\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]$/) != null);
	return false;
}

function TestComparison(objValue,strCompareElement,strvalidator,strError) {
	if (!objValue.form) {
		alert("Error: No Form object!");
		return false;
	}
	var objCompare = objValue.form.elements[strCompareElement];
	if (!objCompare) {
		alert("Error: Element with name"+strCompareElement+" not found !");
		return false;
	}
	if (strvalidator != "eqelmnt" && strvalidator != "neelmnt") {
		if (isNaN(objValue.value)) {
			alert(objValue.name+": Should be a number ");
			return false;
		}
		if (isNaN(objCompare.value)) {
			alert(objCompare.name+": Should be a number ");
			return false;
		}
	}
	var bRet = true;
	var cmpstr = '';
	switch(strvalidator) {
		case "eqelmnt":
			if (objValue.value != objCompare.value) {
				cmpstr = " should be equal to ";
				bRet = false;
			}
			break;
		case "ltelmnt":
			if (eval(objValue.value) >= eval(objCompare.value)) {
				cmpstr = " should be less than ";
				bRet = false;
			}
			break;
		case "leelmnt":
			if(eval(objValue.value) >  eval(objCompare.value)) {
				cmpstr = " should be less than or equal to";
				bRet = false;
			}
			break;
		case "gtelmnt":
			if (eval(objValue.value) <=	eval(objCompare.value)) {
				cmpstr = " should be greater than";
				bRet = false;
			}
			break;
		case "geelmnt":
			if (eval(objValue.value) < eval(objCompare.value)) {
			   cmpstr = " should be greater than or equal to";
			   bRet = false;
			}
			break;
		case "neelmnt":
			if (objValue.value.length > 0 && objCompare.value.length > 0 && objValue.value == objCompare.value) {
				cmpstr = " should be different from ";
				bRet = false;
			}
			break;
		default:
			break;
   }
   if (!bRet) {
	  if (!strError || strError.length == 0) strError = objValue.name + cmpstr + objCompare.value;
	  alert(strError);
   }
   return bRet;
}

function TestSelMin(objValue,strMinSel,strError) {
	var objcheck = objValue.form.elements[objValue.name];
	var chkcount = 0;
	if (objcheck.length) {
		for (var c = 0;c < objcheck.length; c++) if(objcheck[c].checked) chkcount++;
	} else {
		chkcount = (objcheck.checked ? 1: 0);
	}
	var minsel = eval(strMinSel);
	if (chkcount < minsel) {
		if(!strError || strError.length ==0) strError = "Please Select atleast"+minsel+" check boxes for"+objValue.name;
		alert(strError);
		return false;
	}
	return true;
}

function IsCheckSelected(objValue,chkValue) {
	var objcheck = objValue.form.elements[objValue.name];
	if(objcheck.length) {
		var idxchk=-1;
		for(var c=0;c < objcheck.length;c++) {
		   if(objcheck[c].value == chkValue) {
			 idxchk=c;
			 break;
		   }
		}
		if(idxchk>= 0) if(objcheck[idxchk].checked) return true;
	} else {
		if(objValue.checked) return true;
	}
	return false;
}

function TestDontSelectChk(objValue,chkValue,strError) {
	if (IsCheckSelected(objValue,chkValue)) {
		if(!strError || strError.length ==0) strError = "Can't Proceed as you selected "+objValue.name;
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestShouldSelectChk(objValue,chkValue,strError) {
	if (IsCheckSelected(objValue,chkValue)) {
		return true;
	} else {
		if(!strError || strError.length ==0) strError = "You should select"+objValue.name;
		alert(strError);
		return false;
	}
}

function TestRequiredInput(objValue,strError) {
	if (eval(objValue.value.length) == 0) {
		if(!strError || strError.length ==0) strError = objValue.name + " : Required Field";
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestFileExtension(objValue,cmdvalue,strError) {
	if (objValue.value.length <= 0) return true;
	var extns = cmdvalue.split(";");
	for (var i = 0; i < extns.length; i++) {
		var ext = objValue.value.substr(objValue.value.length - extns[i].length,extns[i].length);
		ext = ext.toLowerCase();
		if (ext == extns[i]) return true;
	}
	if(!strError || strError.length == 0) strError = objValue.name + " allowed file extensions are: "+cmdvalue;
	alert(strError);
	return false;
}

function TestMaxLen(objValue,strMaxLen,strError) {
	if (eval(objValue.value.length) > eval(strMaxLen)) {
		if(!strError || strError.length ==0) strError = objValue.name + " : "+ strMaxLen +" characters maximum ";
		alert(strError + "\n[Current length = " + objValue.value.length + " ]");
		return false;
	} else {
		return true;
	}
}

function TestMinLen(objValue,strMinLen,strError) {
	if (eval(objValue.value.length) < eval(strMinLen)) {
		if (!strError || strError.length ==0) strError = objValue.name + " : " + strMinLen + " characters minimum  ";
		alert(strError + "\n[Current length = " + objValue.value.length + " ]");
		return false;
	} else {
		return true;
	}
}

function TestInputType(objValue,strRegExp,strError,strDefaultError) {
	if (!hasRegExp) return true;
	var charpos = objValue.value.search(strRegExp);
	if (objValue.value.length > 0 && charpos >= 0) {
		if(!strError || strError.length ==0) strError = strDefaultError;
		alert(strError + "\n [Error character position " + eval(charpos+1)+"]");
		return false;
	} else {
		return true;
	}
}

function TestEmail(objValue,strError) {
	if (objValue.value.length > 0 && !validateEmail(objValue.value)) {
		if(!strError || strError.length ==0) strError = objValue.name+": Enter a valid Email address ";
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestLessThan(objValue,strLessThan,strError) {
	if (isNaN(objValue.value)) {
		alert(objValue.name+": Should be a number ");
		return false;
	} else if (eval(objValue.value) >= eval(strLessThan)) {
		if(!strError || strError.length ==0) strError = objValue.name + " : value should be less than "+ strLessThan;
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestGreaterThan(objValue,strGreaterThan,strError) {
	if (isNaN(objValue.value)) {
		alert(objValue.name+": Should be a number ");
		return false;
	} else if (eval(objValue.value) <=  eval(strGreaterThan)) {
		if(!strError || strError.length ==0) strError = objValue.name + " : value should be greater than "+ strGreaterThan;
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestRegExp(objValue,strRegExp,strError) {
	if (!hasRegExp) return true;
	if (objValue.value.length > 0 && !objValue.value.match(strRegExp)) {
		if(!strError || strError.length ==0) strError = objValue.name+": Invalid characters found ";
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestDontSelect(objValue,index,strError) {
	if (objValue.selectedIndex == null) {
		alert("Error: dontselect command for non-select Item");
		return false;
	} else if(objValue.selectedIndex == eval(index)) {
		if (!strError || strError.length ==0) strError = objValue.name+": Please Select one option ";
		alert(strError);
		return false;
	} else {
		return true;
	}
}

function TestSelectOneRadio(objValue,strError) {
	var objradio = objValue.form.elements[objValue.name];
	for (var r = 0; r < objradio.length; r++) if (objradio[r].checked) return true;
	if(!strError || strError.length ==0) strError = "Please select one option from "+objValue.name;
	alert(strError);
	return false;
}

function TestSelectRadio(objValue,cmdvalue,strError,testselect) {
	var objradio = objValue.form.elements[objValue.name];
	var selected = false;
	for (var r = 0;r < objradio.length; r++) {
		if (objradio[r].value == cmdvalue && objradio[r].checked) {
			selected = true;
			break;
		}
	}
	if (testselect == selected) {
		return true;
	} else {
		alert(strError);
		return false;
	}
}

function TestEnglish(objValue,strError) {
	if (objValue.value.length > 0 && !objValue.value.match(/^[\s\u0020-\u0080]+$/)) {
		if(!strError || strError.length ==0) strError = objValue.name+": Invalid characters found ";
		alert(strError);
		return false;
	} else {
		return true;
	}
}

// Checks each field in a form
ValidationDesc.prototype.validateInput = function() {
	var epos = this.desc.indexOf("=");
	var command = "";
	var cmdvalue = "";
	if (epos >= 0) {
		command  = this.desc.substring(0,epos);
		cmdvalue = this.desc.substr(epos+1);
	} else {
		command = this.desc;
	}
	switch (command) {
		case "req":
		case "required":
			return TestRequiredInput(this.o,this.error);
		case "maxlength":
		case "maxlen":
			return TestMaxLen(this.o,cmdvalue,this.error);
		case "minlength":
		case "minlen":
			return TestMinLen(this.o,cmdvalue,this.error);
		case "alnum":
		case "alphanumeric":
			return TestInputType(this.o,"[^A-Za-z0-9]",this.error, this.o.name+": Only alpha-numeric characters allowed ");
		case "alnum_s":
		case "alphanumeric_space":
			return TestInputType(this.o,"[^A-Za-z0-9\\s]",this.error, this.o.name+": Only alpha-numeric characters and space allowed ");
		case "num":
		case "numeric":
			return TestInputType(this.o,"[^0-9]",this.error, this.o.name+": Only digits allowed ");
		case "alphabetic":
		case "alpha":
			return TestInputType(this.o,"[^A-Za-z]",this.error, this.o.name+": Only alphabetic characters allowed ");
		case "alphabetic_space":
		case "alpha_s":
			return TestInputType(this.o,"[^A-Za-z\\s]",this.error, this.o.name+": Only alphabetic characters and space allowed ");
		case "email":
			return TestEmail(this.o,this.error);
		case "lt":
		case "lessthan":
			return TestLessThan(this.o,cmdvalue,this.error);
		case "gt":
		case "greaterthan":
			return TestGreaterThan(this.o,cmdvalue,this.error);
		case "regexp":
			return TestRegExp(this.o,cmdvalue,this.error);
		case "dontselect":
			return TestDontSelect(this.o,cmdvalue,this.error)
		case "dontselectchk":
			return TestDontSelectChk(this.o,cmdvalue,this.error)
		case "shouldselchk":
			return TestShouldSelectChk(this.o,cmdvalue,this.error)
		case "selmin":
			return TestSelMin(this.o,cmdvalue,this.error);
		case "selone":
			return TestSelectOneRadio(this.o,this.error);
		case "dontselectradio":
			return TestSelectRadio(this.o,cmdvalue,this.error,false);
		case "selectradio":
			return TestSelectRadio(this.o,cmdvalue,this.error,true);
		//Comparisons
		case "eqelmnt":
		case "ltelmnt":
		case "leelmnt":
		case "gtelmnt":
		case "geelmnt":
		case "neelmnt":
			return TestComparison(this.o,cmdvalue,command,this.error);
		case "req_file":
			return TestRequiredInput(this.o,this.error);
		case "file_extn":
			return TestFileExtension(this.o,cmdvalue,this.error);
		case "english":
			return TestEnglish(this.o,this.error);
		default:
			return true;
	}
}
