/* Validator Class Constructor */
function Validator(formName, formFields){
	/* Regular Expression Formats */
	
	this.RegFormats = $H({
		"alpha"   : /^[a-zA-Z\.\-]*$/,
		"alphanum": /^\w+$/,
		"unsigned": /^\d+$/,
		"integer" : /^[\+\-]?\d*$/,
		"real"    : /^[\+\-]?\d*\.?\d*$/,
		"email"   : /^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$/,
		"phone"   : /^[\d\.\s\-]+$/
	});
	
	/* Error Messages */
	this.ErrorMessages = $H({
		"alpha"   : "Must contain only letters",
		"alphanum": "Must contain only letters and numbers",
		"unsigned": "Must match an unsigned integer",
		"integer" : "Must contain only integer numbers",
		"real"    : "Must contain only real numbers",
		"email"   : "Not a valid email",
		"phone"   : "Not a valid phone number",
		"required_select" : "At least one item must be selected",
		"required_check" : "This field must be checked",
		"required_fill" : "This field is required"
	});
	
	this.Error = new Hash( {} );
	this.FormName = formName;
	this.ExaminedFields = formFields;
	this.DisplayElement = null;
	
	_root = this;
	window.onload = function(){
		_root.ExaminedFields.each(function(pair){
			var field = document.forms[_root.FormName][pair.key] || $(pair.key);
			
			if(field.type == "file"){
				field.onblur = function(){
					_root.Run("own", pair.key);
				}
			}
			
			if(field.type == "checkbox" || field.type == "file"){
				field.onchange = function(){
					_root.Run("own", pair.key);
				}
			}else if(field != "[object NodeList]"){
				field.onblur = function(){
					_root.Run("own", pair.key);
					
				}
			}
		});
		
		document.forms[_root.FormName].onreset = function(){
			_root.Error = new Hash( {} );
			_root.ExaminedFields.each(function(pair){
				if($("ErrorMsg_" + pair.key)) $("ErrorMsg_" + pair.key).remove();
			});
			if($(_root.DisplayElement)) $(_root.DisplayElement).innerHTML = "";
		}
	}
	
}

/* FORM ERROR REPORTS */
Validator.prototype.ExamineElement = function(fieldName, attributes){
	var frm = document.forms[this.FormName];
	var field = (!frm[fieldName]) ? $(fieldName) : frm[fieldName];
	var value = field.value;
	
	var required = (attributes.r) ? attributes.r : false;
	var format = (attributes.f) ? attributes.f : null;
	var minChars = (attributes.mn) ? attributes.mn : null;
	var maxChars = (attributes.mx) ? attributes.mx : null;
	var matchField = (attributes.mf) ? attributes.mf : null;
	var label = (attributes.l) ? attributes.l : fieldName;
	this.ExaminedFields[fieldName].l = label;
	
	/* WHETHER THE FIELD IS A CHECKBOX OR RADIO */
	if((field == "[object NodeList]" || field.length != undefined && !field.options) && required == true){
		for(i=0; i<field.length; i++){
			if(field[i].checked == true){
				var broken = true;
				break;
			}
		}
		if(!broken){
			this.Error[fieldName] = label + ": " + this.ErrorMessages["required_select"];
			return;
		}
	}
	if(field.type == "checkbox" || field.type == "radio"){
		if(required == true && field.checked == false){
			this.Error[fieldName] = label + ": " + this.ErrorMessages["required_check"];
			return;
		}
	}
	
	/* CONTROL IF REQUIRED */
	if(required == true && value == ""){
		this.Error[fieldName] = this.ErrorMessages["required_fill"];
		return;
	}
	/* FORMAT CONTROL */
	if(format != null){
		if(value != "" && !this.RegFormats[format].test(value)){
			this.Error[fieldName] = this.ErrorMessages[format];
			return;
		}
	}
	/* MINIMIM CHARACTER NUMBER CONTROL */
	if(minChars != null){
		//var val = (isNaN(value)) ? value.length : parseInt(value);
		var val = value.length;
		if(value != "" && val < minChars){
			this.Error[fieldName] = "You must type at least " + minChars + " characters!";
			return;
		}
	}
	/* MAXIMUM CHARACTER NUMBER CONTROL */
	if(maxChars != null){
		//var val = (isNaN(value)) ? value.length : parseInt(value);
		var val = value.length;
		if(value != "" && val > maxChars){
			this.Error[fieldName] = "You must at the most " + maxChars + " characters!";
			return;
		}
	}
	/* FIELD MATCH CONTROL */
	if(matchField != null){
		var matchValue = $F(frm[matchField]);
		if(value != matchValue){
			this.Error[fieldName] = "The Value you entered don't match " + matchField + " ";
			return;
		}
	}
}

/* DISPLAY ERRORS */
Validator.prototype.Run = function(type, field){
	var _root = this;
	var frm = document.forms[this.FormName];
	
	if(field == null){
		this.ExaminedFields.each(function(pair){
			_root.ExamineElement(pair.key, pair.value);
		});
	}else{
		this.ExamineElement(field, this.ExaminedFields[field]);
	}
	
	type = (type == null) ? "alert" : type;
	var errorContent = "";
	
	switch(type){
		case "alert":
			if(this.Error.values().length > 0){
				this.Error.each(function(pair){
					var subject = _root.ExaminedFields[pair.key].l + ": ";
					if(pair.value.indexOf(subject) != -1) val = pair.value.replace(subject, "");
					else val = pair.value;
					errorContent += subject + val + "\n";
				});
				alert(errorContent);
				this.Error = new Hash( {} );
				return false;
			}
		break;
		
		case "own":
		
			if(field == null){
				this.ExaminedFields.each(function(pair){
					if($("ErrorMsg_" + pair.key)) $("ErrorMsg_" + pair.key).remove();
				});
			}else{
				if($("ErrorMsg_" + field)) $("ErrorMsg_" + field).remove();
			}
			
			if(this.Error.values().length > 0){
				this.Error.each(function(pair){
					var parentElement = frm[pair.key].parentNode;
					var contentDiv = document.createElement("div");
					Element.extend(contentDiv);
					contentDiv.id = "ErrorMsg_" + pair.key;
					contentDiv.addClassName("ErrorMsg");
					contentDiv.style.width = "250px";
					contentDiv.innerHTML = pair.value;
					parentElement.appendChild(contentDiv);
					
					_root.Error.remove(pair.key);
				});
				this.Error = new Hash( {} );
				return false;
			}
		break;
		
		default:
			if(this.Error.values().length > 0){
				this.Error.each(function(pair){
					errorContent += _root.ExaminedFields[pair.key].l + " : " +  pair.value + "<br>";
				});
				var errorElement = $(type);
				errorElement.innerHTML = errorContent;
				_root.DisplayElement = errorElement;
				this.Error = new Hash( {} );
				return false;
			}
		break;
	}
	
	return true;
}
