function FormValidator(f){
	this.elementRequirements 	= new Array();		// Element Requirement Array
	this.formRequirements		= new Array();		// Form Requirement Array
	this.requirementType 		= "object";			// Use object references to validations
	this.resumeOnError 			= true;				// Check entire form
	this.errorMessages			= "";					// All error messages
	this.errorElements			= ",";				// Elements with errors
	this.errorClass				= "";					// CSS style to apply to fields with errors

	if(typeof this.setForm!="function"){
		FormValidator.prototype.setForm = function(f){
			if(typeof(f)=="string"){
				if(document.forms[f]){
					this.form = document.forms[f];
				};
			}else if(typeof(f)=="object"){
				this.form = f;
			};
		};
		
		FormValidator.prototype.setErrorClass = function(c){
			this.errorClass = c;
		};
		
		FormValidator.prototype.setElementRequirementType = function(t){
			this.requirementType = t;	
		};
		
		FormValidator.prototype.setErrorResumption = function(b){
			this.resumeOnError = b;
		};
		
		FormValidator.prototype.addElementRequirement = function(i,v,m){
			this.elementRequirements[this.elementRequirements.length] = new Object();
			this.elementRequirements[this.elementRequirements.length-1]["i"] = i;
			this.elementRequirements[this.elementRequirements.length-1]["v"] = v;
			this.elementRequirements[this.elementRequirements.length-1]["m"] = m;
		};
		
		FormValidator.prototype.addFormRequirement = function(t,a,v,m){
			this.formRequirements[this.formRequirements.length] = new Object();
			this.formRequirements[this.formRequirements.length-1]["type"] = t;
			this.formRequirements[this.formRequirements.length-1]["value"] = v;
			this.formRequirements[this.formRequirements.length-1]["elements"] = a;
			this.formRequirements[this.formRequirements.length-1]["message"] = m;
		};
		
		FormValidator.prototype.addError = function(msg,elId){
			if(this.errorMessages.indexOf(msg)==-1){
				this.errorMessages += msg + "\n";
			};
			this.errorElements += elId + ",";
			return false;
		};
		
		FormValidator.prototype.checkElementValidation = function(elId,vType,vValue,msg,val,el){
			switch(vType){
				case "required":
					if(isEmpty(val)){
						return this.addError(msg,elId);
					};
					break;
				case "datatype":
					if(!isEmpty(val)){
						switch(vValue){
							case "integer":
								if(!isInteger(val)){
									return this.addError(msg,elId);
								};
								break;
							case "float":
								if(!isFloat(val)){
									return this.addError(msg,elId);
								};
								break;
							case "email":
								if(!isEmail(val)){
									return this.addError(msg,elId);
								};
								break;
							case "phone":
								if(!is10Phone(val)){
									return this.addError(msg,elId);
								};
								break;
							case "uszip":
								if(!is59Zip(val)){
									return this.addError(msg,elId);
								};
								break;
							case "date":
								if(!isGenericDate(val)){
									return this.addError(msg,elId);
								};
								break;
						};
					};
					break;
				case "dateformat":
					if(!isEmpty(val)){
						switch(vValue){
							case "mm/dd/yyyy":
								if(!isGenericDate(val)){
									return this.addError(msg,elId);
								};
								var arrDate = val.split("/");
								if(arrDate[0]>12){
									return this.addError(msg,elId);
								};
								if(arrDate[1]>getMonthLength(val)){
									return this.addError(msg,elId);	
								};
								if(arrDate[2]<1 || arrDate[2].length!=4){
									return this.addError(msg,elId);	
								};
								break;
						};
					}
					break;
				case "rangemin":
					if(!isEmpty(val)){
						if(parseFloat(val)<parseFloat(vValue)){
							return this.addError(msg,elId);
						};
					};
					break;
				case "rangemax":
					if(!isEmpty(val)){
						if(parseFloat(val)>parseFloat(vValue)){
							return this.addError(msg,elId);
						};
					};
					break;
				case "lengthmin":
					if(!isEmpty(val)){
						if(val.length<parseFloat(vValue)){
							return this.addError(msg,elId);
						};
					};
					break;
				case "lengthmax":
					if(!isEmpty(val)){
						if(val.length>parseFloat(vValue)){
							return this.addError(msg,elId);
						};
					};
					break;
				case "selectedmin":
					var arrTemp = val.split(",");
					if(arrTemp<parseInt(vValue)){
						return this.addError(msg,elId);
					};
					break;
				case "selectedmax":
					var arrTemp = val.split(",");
					if(arrTemp>parseInt(vValue)){
						return this.addError(msg,elId);
					};
					break;
				case "datetimeformat":
					
					break;
				case "datetimemin":
					
					break;
				case "datetimemax":
					
					break;
			};
			return true;
		};
		
		FormValidator.prototype.validateElements = function(){
			var r	= this.elementRequirements;				// Shortcut to element requirements object
			for(var i=0;i<r.length;i++){						/* Loop through all form elements */
				if(this.requirementType=="object"){			/* Use object definition */
					var elId	= r[i]["i"];						// Element to validate
					var arr	= r[i]["v"].split(",");			// Validations to perform
					var msg	= r[i]["m"];						// Invalid message
					el = this.form.elements[elId];			// Element object
					if(el){
						var val = this.getValue(el);
						for(var j=0;j<arr.length;j++){
							if(!this.checkElementValidation(elId,arr[j].split("=")[0],arr[j].split("=")[1],msg,val,el)){
								break;
							};
						};
					}else{
						return false;
					};
				}else if(this.requirementType=="form"){/*Use element attribute definition*/
					//TODO: if validations are part of HTML output as attributes
				};
			};
		};
		
		FormValidator.prototype.checkFormValidation = function(obj){
			switch(obj["type"]){
				case "atleast":
					var arrTemp = obj["elements"];
					var cntTemp = 0;
					for(var i=0;i<arrTemp.length;i++){
						var elTemp = this.form.elements[arrTemp[i]];
						if(elTemp){
							if(!isEmpty(this.getValue(elTemp))){
								cntTemp++;
							};
						};
					};
					if(cntTemp<parseInt(obj["value"])){
						return this.addError(obj["message"],obj["elements"].join(","));
					};
					break;
				case "conditionalrequired":
					var arrTemp = obj["elements"];
					var blnCheck = false;
					for(var i=1;i<arrTemp.length;i+=2){
						var tempVal = this.getValue(this.form.elements[arrTemp[i]]);
						if(tempVal==arrTemp[i+1] || (arrTemp[i+1]=="_" && !isEmpty(tempVal))){
							blnCheck = true;
							break;	
						};
					}
					if(blnCheck){
						if(isEmpty(this.getValue(this.form.elements[arrTemp[0]]))){
							return this.addError(obj["message"],arrTemp[0]);
						};
					};
					break;
				case "conditionalgreater":
					var arrTemp = obj["elements"];
					var blnCheck = false;
					for(var i=1;i<arrTemp.length;i+=2){
						if(this.getValue(this.form.elements[arrTemp[i]])>arrTemp[i+1]){
							blnCheck = true;
							break;	
						};
					};
					if(blnCheck){
						if(isEmpty(this.getValue(this.form.elements[arrTemp[0]]))){
							return this.addError(obj["message"],arrTemp[0]);
						};
					};
					break;
				case "match":
					var arrTemp = obj["elements"];
					for(var i=0;i<arrTemp.length-1;i++){
						if(this.getValue(this.form.elements[arrTemp[i]])!=this.getValue(this.form.elements[arrTemp[i+1]])){
							return this.addError(obj["message"],arrTemp[0]);	
						};
					};
					break;
			};
			return true;
		};
		
		FormValidator.prototype.validateForm = function(){
			this.validateElements();
			var f		= this.form;								// Shortcut to form
			var r		= this.formRequirements;				// Shortcut to form requirements object
			for(var i=0;i<r.length;i++){						/* Loop through all form elements */
				this.checkFormValidation(r[i]);
			};
			if(this.errorMessages!=""){
				var setFirst = false;
				for(var i=0;i<f.elements.length;i++){
					if(this.errorElements.indexOf(","+f.elements[i].id+",")>-1){
						if(!setFirst){
							try{f.elements[i].focus();f.elements[i].select();}catch(e){};
							setFirst = true;
						};
						f.elements[i].className += " errorField";
					}else if(f.elements[i].className.indexOf("errorField")>-1){
						f.elements[i].className = trim(f.elements[i].className.replace(/errorField/g,""));
					};
				};
				alert(this.errorMessages);
				return false;
			}else{
				for(var i=0;i<f.elements.length;i++){
					if(f.elements[i].className.indexOf("errorField")>-1){
						f.elements[i].className = trim(f.elements[i].className.replace(/errorField/g,""));
					};
				};
			};
			return true;
		};
		
		FormValidator.prototype.getValue = function(el){
			var elType = (el.type)?(el.type):(el[0].type);
			switch(elType){
				case "text":
				case "textarea":
				case "button":
				case "submit":
				case "hidden":
				case "password":
					return el.value;
					break;
				case "select-one":
					if(el.selectedIndex>-1){
						return el[el.selectedIndex].value;
					}else{
						return "";
					};
					break;
				case "select-multiple":
					var arrTemp = new Array();
					for(var i=0;i<el.length;i++){
						if(el[i].selected){
							if(!isEmpty(el[i].value)){
								arrTemp[arrTemp.length] = el[i].value;
							};
						};
					};
					if(arrTemp.length>0){
						return arrTemp.join(",");	
					}else{
						return "";
					};
					break;
				case "checkbox":
					var arrTemp = new Array();
					if(el.length){
						for(var i=0;i<el.length;i++){
							if(el[i].checked){
								if(!isEmpty(el[i].value)){
									arrTemp[arrTemp.length] = el[i].value;
								};
							};
						};
						if(arrTemp.length>0){
							return arrTemp.join(",");	
						};
					}else if(el.checked){
						return el.value;
					}
					return "";
					break;
				case "radio":
					if(el.length){
						for(var i=0;i<el.length;i++){
							if(el[i].checked){
								return el[i].value;
							};
						};
					}else{
						if(el.checked){
							return el.value;
						};
					};
					return "";
					break;
			};
			return "";
		};
		
		FormValidator.prototype.setValue = function(el,opt,val){
			var elType = (el.type)?(el.type):(el[0].type);
			switch(elType){
				case "text":
				case "textarea":
				case "button":
				case "submit":
				case "hidden":
				case "password":
					el.value = val;
					break;
				case "select-one":
					if(opt>-1 && el.length>opt){
						el[opt].value = val;
					};
					break;
				case "select-multiple":
					if(opt>-1 && el.length>opt){
						el[opt].value = val;
					};
					break;
				case "checkbox":
					if(el.length){
						if(opt>-1 && el.length>opt){
							el[opt].value = val;
						};
					}else{
						if(opt=="" || opt==0){
							el.value = val;
						};
					};
					break;
				case "radio":
					if(el.length){
						if(opt>-1 && el.length>opt){
							el[opt].value = val;
						};
					}else{
						if(opt=="" || opt==0){
							el.value = val;
						};
					};
					break;
			};
		};
		
		FormValidator.prototype.reformatPhone = function(s){
			try{
				if(!isEmpty(this.form.elements[s].value)){
					var p = this.form.elements[s].value.toString();
					var tmp = "";
					for(var i=0;i<p.length;i++){
						if(!isNaN(parseInt(p.substr(i,1)))){
							tmp+=p.substr(i,1);
						};
					};
					this.form.elements[s].value = tmp;
				};
			}catch(e){};
		};
		
		FormValidator.prototype.replaceValue = function(f,t){
			try{
				if(!isEmpty(this.getValue(f))){
					if(t){
						this.setValue(t,"",this.getValue(f));
					};
				};
			}catch(e){};
		}
	}
	
	this.setForm(f);// Set current form to validate
	
}
