function validate(Form) {
	var V = new Validator(Form);
	return V.process();
}

function Validator(Form) {
	this.Form = Form;
	this.addMessage = function (elem, message) {
		$(elem).parents().filter("div.row")
			.addClass("warning")
			.prepend("<div class=\"message\">" + message + "<\/div>");
	};
	this.process = function () {
		if ($(this.Form).hasClass("submitted")) {
//			console.info("Already been submitted:", this.Form);
			return false;
		}
		
		this.Form.isValid = true;
		$(this.Form).removeClass("invalid")
		$(this.Form).find(".message").remove();
		$(this.Form).find("div.row").removeClass("warning");
		
		this.Elem = {};
		
		var validatorValue, validatorMessage;
		
		for (var i = 0, ii = this.Form.elements.length; i < ii; i++) {
			this.Elem = this.Form.elements[i];
			if (!this.Elem.id || !ValidatorData[this.Elem.id] || this.Elem.type == "hidden") {
				continue;
			}
//console.group(this.Elem)
			
			for (var func in ValidatorData[this.Elem.id]) {
				if (!this[func]) {
					continue;
				}
				
				validatorMessage = ValidatorData[this.Elem.id][func][ ValidatorData[this.Elem.id][func].length - 1];
				validatorValue = ValidatorData[this.Elem.id][func].slice(0, ValidatorData[this.Elem.id][func].length - 1);
				if (validatorMessage.indexOf("%%") > -1) {
					validatorMessage = validatorMessage.replace(/%%/g, validatorValue[0]);
				}
				if (validatorValue.length == 1) {
					validatorValue = validatorValue[0];
				}
//console.debug(func, validatorValue, this[func](validatorValue))				
				if (!this[func](validatorValue)) {
					if (!this.Form.isValid) {
						$(this.Form).addClass("invalid");
					}
					this.Form.isValid = false;
					this.addMessage(this.Elem, validatorMessage);
//					console.warn(this.Elem,"failed for",func, validatorValue);
				}
			}
//console.groupEnd();
		};
		
		if (this.Form.isValid) {
			$(this.Form).addClass("submitted");
		} else {
			alert(ValidatorData[""].invalid);
		}
		
		return this.Form.isValid;
	};
};

Validator.prototype.mandatory = function (value){
	if (!value) {
		return true;
	}
	switch (this.Elem.type) {
		default:
			if (value == "trim") {
				this.Elem.value = $.trim(this.Elem.value);
			}
			return !!this.Elem.value.length;
	}
};
Validator.prototype.minLength = function (value) {
	if (!this.Elem.value.length) {
		return true;
	}
	return this.Elem.value.length >= value;
};
Validator.prototype.maxLength = function (value) {
	if (!this.Elem.value.length) {
		return true;
	}
	return this.Elem.value.length <= value;
};
Validator.prototype.maxRows = function (value) {
	this.Elem.value = $.trim(this.Elem.value);
	var aRows = this.Elem.value.split(/\n/g);
	return aRows.length <= value;
}
Validator.prototype.pattern = function (value) {
	if (!this.Elem.value.length) {
		return true;
	}
	var regex = value;
	var modifiers = "";
	if (typeof value.push == "function") {
		regex = value[0];
		modifiers = value[1];
	}
	return new RegExp(regex, modifiers).test(this.Elem.value);
};
Validator.prototype.dataType = function (value) {
	if (!this.Elem.value.length) {
		return true;
	}
	switch (value) {
		case "email":
			return !!this.Elem.value.match(/^\S+@\S+\.\S{2,}$/);
			break;
	}
};
Validator.prototype.extension = function (value) {
	if (!this.Elem.value.length) {
		return true;
	}
	var rx = new RegExp(value.split(/[, ]+/g).join("|") + "$", "i");
	return rx.test(this.Elem.value);
};
Validator.prototype.equalsTo = function (value) {
	var aRefs = value.split(/[, ]+/g);
	for (var i = 0, ii = aRefs.length; i < ii; i++) {
		if (this.Elem.value != $("#" + aRefs[i]).val()) {
			return false;
		}
	}
	return true;
}
Validator.prototype.notEqualsTo = function (value) {
	var aRefs = value.split(/[, ]+/g);
	for (var i = 0, ii = aRefs.length; i < ii; i++) {
		if (this.Elem.value == $("#" + aRefs[i]).val()) {
			return false;
		}
	}
	return true;
}

