function ValidatorMessage(el, msg){
	this.msg = msg;
	this.el = el;

	this.toString = function(){
		return this.el + ': ' + this.msg;
	}
}

function FormValidator(){
	var min_description_length = 100;
	this.messages = {
		'empty': 'Please fill this field.',
		'int': 'Please enter a whole, not negative number (no decimals)',
		'description': "Thank you for your post, but it is quite short; are you sure you don't have more details to provide?"
		, 'description_of_service': "Are you sure you don't have more information that may help other WisePrice users? If you don't know what to write, please read our <a href='/writing-guide.htm'>Writing Guide</a>  for ideas"
		, 'review_of_service' : "Are you sure you don't have more information that may help other WisePrice users? If you don't know what to write, please read our <a href='/writing-guide.htm'>Writing Guide</a>  for ideas" 
		, 'tips': "Are you sure you don't have more information that may help other WisePrice users? If you don't know what to write, please read our <a href='/writing-guide.htm'>Writing Guide</a>  for ideas"
		, 'text': "Are you sure you don't have more information that may help other WisePrice users? If you don't know what to write, please read our <a href='/writing-guide.htm'>Writing Guide</a>  for ideas"
	}

	this.is_incorrect_optional = function(el){
		return ((el.value === '') && !el.hasAttribute('optional'));
	}

	this.is_shorter_than  = function(el, len){
		return (el.value.replace(/$\s+/, '').replace(/\s+$/, '').length < len);
	}


	this.functions = { // returns true if error found
		'is_incorrect_optional' :function(el){
			var inp = el.getAttribute('inplace');
			return (((el.value === '') || (inp == el.value)) && !el.hasAttribute('optional'));
		},
		'is_shorter_than' : function(el, len){
			return (el.value.replace(/$\s+/, '').replace(/\s+$/, '').length < len);
		},
		'empty': function(el){
			return this.is_incorrect_optional(el);
		},
		'int': function(el){
			el.value = el.value.split('$').join('');
			el.value = el.value.split(' ').join('');
			el.value = el.value.split(',').join('');
			var fl = parseFloat(el.value);
			if (! isNaN(fl)){
				el.value = Math.round(fl);
			}
			return  this.is_incorrect_optional(el) 
				||		
				isNaN(parseInt(el.value)) 
				|| 
				(parseInt(el.value).toString() !== el.value)
				||
				(parseInt(el.value) < 0)
			;
		},
		'description': function(el){
			return (
					(el.value.length == 0)
					&& 
					(el.hasAttribute('optional'))
				)
				? false
				: (el.value.replace(/$\s+/, '').replace(/\s+$/, '').length < min_description_length);
		}
		, 'description_of_service' : function(el){
			return this.is_incorrect_optional(el) || this.is_shorter_than(el, min_description_length);
		}
		, 'review_of_service' : function(el){
			return this.is_incorrect_optional(el) || this.is_shorter_than(el, min_description_length);
		}
		, 'text' : function(el){
			return this.is_incorrect_optional(el) || this.is_shorter_than(el, min_description_length);
		}
		, 'tips' : function(el){
			return this.is_incorrect_optional(el) || this.is_shorter_than(el, min_description_length);
		}
	}

	this.check_el = function(el){
		// returns error message if error found else null
		if (this.functions.empty(el)){
			return this.messages.empty;
		}else{
			var type = el.getAttribute('field_type');
			if (type && this.functions[type] && this.functions[type](el)){
				return this.messages[type];
			}else{
				return null;
			}
		}
	}

	this.check_array = function(els){	
		// returns ValidatorMessage if error found. false otherwise
		var n = els.length;
		for (var i = 0 ; i < n; i++){
			var el = els[i];
			if (el.type && (el.type != 'submit')){
				var msg = this.check_el(el);
				if (msg){
					return new ValidatorMessage(el, msg);
				}		
			}
		}
		return false;	
	}

	this.check_form = function (form){
		return (form) ? this.check_array(form.elements) : null;
	}

	this.show_error = function (vmsg,id){
		if (!vmsg) return;
		if (!id) id = 'validation_error';
		var new_div = document.createElement('div');
		new_div.id = 'validation_error';
		new_div.innerHTML = vmsg.msg;
		if (vmsg.el){
			vmsg.el.parentNode.insertBefore(new_div, vmsg.el.parentNode.firstChild);
			vmsg.el.focus();
		}
	}

	this.clear_error = function(id){
		if (!id) {
			id = 'validation_error';
		}
		var err = document.getElementById(id);
		if (err) { 
			var p = err.parentNode;
			p.removeChild(err);
		}		
	}

	this.show_field_error = function (el){
		// returns true if found error
		if (!el) return false;
		this.clear_error();
		var msg = this.check_el(el);
		if (msg){
			this.show_error(new ValidatorMessage(el, msg));
			return true;
		}else{
			return false;
		}
	}

	this.show_array_error = function(els){
		// returns true if found error
		if (!els) return false;
		this.clear_error();
		var vmsg = this.check_array(els);
		if (vmsg){
			this.show_error(vmsg);
		}
		return (vmsg)? true : false;
	}

	this.show_form_error = function(form){
		// returns true if found error
		if (!form) return false;
		return this.show_array_error(form.elements);
	}
}
