var fValidator = new Class({
	Implements: [Options],

	options: {
		msgContainerTag: "div",
		msgClass: "fValidator-msg",

		styleNeutral: {"background-color": "white", "border": "2px solid #E2E2E2"},
		styleInvalid: {"background-color": "#fcc", "border-color": "#c00"},
		styleValid: {"background-color": "#cfc", "border-color": "#0c0"},

		real: {type: "real", re: /^[-+]?\d*\.?\d+$/, msg: "Please enter a valid number."},
		alpha: {type: "alpha", re: /^[a-z ._-]+$/i, msg: "This field accepts alphabetic characters only."},
		alphanum: {type: "alphanum", re: /^[a-z0-9 ._-]+$/i, msg: "This field accepts alphanumeric characters only."},
		url: {type: "url", re: /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i, msg: "Please enter a valid url."},
	
		required: {type: "required", re: /[^.*]/, msg: "validate_campoVuoto"},
		integer: {type: "integer", re: /^[-+]?\d+$/, msg: "validate_numInt"},
		ip: {type: "ip",re: /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,msg: "validate_formatoIp"},
		float: {type: "float", re: /^((\d+(\,\d{0,2})?)|((\d*\,)?\d{0,2}))$/ , msg: "validate_formatoFloat"},
		value: {type: "float", re: /^((\d(\,\d{0,2})?)|(((\d{0,3})|(\.\d{3}))+(\,\d{0,2})?))$/ , msg: "validate_formatoValue"},
		time: {type: "time", re: /^(?:[01]\d|2[0-3]|\d)\:(?:[0-5]\d|5[1-9])\:(?:[0-5]\d|5[1-9])$/ , msg: "validate_formatoTime"},
		codicefiscale: {type: "codicefiscale", re: /^[a-zA-Z]{6}\d\d[a-zA-Z]\d\d[a-zA-Z]\d\d\d[a-zA-Z]$/, msg: "validate_CFnonCorretto"},
		dateAmerican: {type: "dateAmerican", re: /^((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4}$/, msg: "validate_formatoData"},
		dateItalian: {type: "dateItalian", re:/^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[-/.](19|20)\d\d$/, msg: "validate_formatoData"},
		
		email: {type: "email", re: /^\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+$/, msg: "validate_EmailnonValida"},
		phone: {type: "phone", re: /^((00|\+)\d{2}[\. ]?)?(\d)+$/, msg: "validate_telefono"},
		confirm: {type: "confirm", msg: "validate_PasswordnonCoincide"},
	
		no_required: {type: "no_required", re: /[^.*]?/, msg: "validate_campoVuoto"},
		no_integer: {type: "no_integer", re: /^([-+]?\d+)?$/, msg: "validate_numInt"},
		no_ip: {type: "no_ip",re: /^((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))?$/,msg: "validate_formatoIp"},
		no_float: {type: "no_float", re: /^((\d+(\,\d{0,2})?)|((\d*\,)?\d{0,2}))?$/ , msg: "validate_formatoFloat"},
		no_value: {type: "no_float", re: /^((\d(\,\d{0,2})?)|(((\d{0,3})|(\.\d{3}))+(\,\d{0,2})?))?$/ , msg: "validate_formatoValue"},
		no_time: {type: "no_time", re: /^((?:[01]\d|2[0-3]|\d)\:(?:[0-5]\d|5[1-9])\:(?:[0-5]\d|5[1-9]))?$/ , msg: "validate_formatoTime"},
		no_codicefiscale: {type: "no_codicefiscale", re: /^([a-zA-Z]{6}\d\d[a-zA-Z]\d\d[a-zA-Z]\d\d\d[a-zA-Z])?$/, msg: "validate_CFnonCorretto"},
		no_dateAmerican: {type: "no_dateAmerican", re: /^(((((0[13578])|([13578])|(1[02]))[\/](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[\/](([1-9])|([0-2][0-9])|(30)))|((2|02)[\/](([1-9])|([0-2][0-9]))))[\/]\d{4}$|^\d{4})?$/, msg: "validate_formatoData"},
		no_dateItalian: {type: "no_dateItalian", re:/^((0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[-/.](19|20)\d\d)?$/, msg: "validate_formatoData"},
				
		no_email: {type: "no_email", re: /^(\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+)?$/, msg: "validate_EmailnonValida"},
		no_phone: {type: "no_phone", re: /^(((00|\+)\d{2}[\. ]?)?(\d)+)?$/, msg: "validate_telefono"},
		no_confirm: {type: "no_confirm", msg: "validate_PasswordnonCoincide"},

		onValid: Class.empty,
		onInvalid: Class.empty
	},

	initialize: function(form, options) {
		this.form = $(form);
		this.setOptions(options);

		this.fields = this.form.getElements("*[class^=fValidate]");
		this.validations = [];

		this.fields.each(function(element) {
			if(!this._isChildType(element)) element.setStyles(this.options.styleNeutral);
			element.cbErr = 0;
			var classes = element.getProperty("class").split(' ');
			classes.each(function(klass) {
				if(klass.match(/^fValidate(\[.+\])$/)) {
					var aFilters = eval(klass.match(/^fValidate(\[.+\])$/)[1]);
					for(var i = 0; i < aFilters.length; i++) {
						if(this.options[aFilters[i]]) this.register(element, this.options[aFilters[i]]);
						if(aFilters[i].charAt(0) == '=') this.register(element, $extend(this.options.confirm, {idField: aFilters[i].substr(1)}));
					}
				}
			}.bind(this));
		}.bind(this));

		this.form.addEvents({
			"submit": this._onSubmit.bind(this),
			"reset": this._onReset.bind(this)
		});
	},

	register: function(field, options) {
		field = $(field);
		this.validations.push([field, options]);
		field.addEvent("blur", function() { //aggiunge alla onblur del field la funzione _validate
			this._validate(field, options);
		}.bind(this));
	},

	_isChildType: function(el) {
		var elType = el.type.toLowerCase();
		if((elType == "radio") || (elType == "checkbox")) return true;
		return false;
	},

	_validate: function(field, options) {
		switch(options.type) {
			case "confirm":
				if($(options.idField).get('value') == field.get('value')) 
					this._msgRemove(field, options);
				else 
					this._msgInject(field, options);
				break;
			default:
				if(options.re.test(field.get('value'))){
					this._msgRemove(field, options);
					this._chkStatus(field, options);
				}
				else
					this._msgInject(field, options);
		}
	},

	_validateChild: function(child, options) {
		var nlButtonGroup = this.form[child.getProperty("name")];
		var cbCheckeds = 0;
		var isValid = true;
 		for(var i = 0; i < nlButtonGroup.length; i++) {
			if(nlButtonGroup[i].checked) {
				cbCheckeds++;
				if(!options.re.test(nlButtonGroup[i].get('value'))) {
					isValid = false;
					break;
				}
			}
		}
		if(cbCheckeds == 0 && options.type == "required") isValid = false;
		if(isValid) this._msgRemove(child, options);
		else this._msgInject(child, options);
	},

	_msgInject: function(owner, options) {
		if(!$(owner.getProperty("id") + options.type +"_msg")) {
			var msgContainer = new Element(this.options.msgContainerTag, {"id": owner.getProperty("id") + options.type +"_msg", "class": this.options.msgClass})
// 			.set('html',options.msg)
			
			.set('html', getGlobalLabel(options.msg))
			
			.set('opacity',0)
			.inject(owner, 'after');
			new Fx.Morph(msgContainer, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': [0, 1]});
			owner.cbErr++;
			this._chkStatus(owner, options);
		}
	},

	_msgRemove: function(owner, options, isReset) {
		isReset = isReset || false;
		if($(owner.getProperty("id") + options.type +"_msg")) {
			var el = $(owner.getProperty("id") + options.type +"_msg");
			new Fx.Morph(el, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': 1});
			el.destroy();
			if(!isReset) {
				owner.cbErr=0;
				this._chkStatus(owner, options);
			}
		}
	},

	_chkStatus: function(field, options) {
		if(field.cbErr == 0) {
			new Fx.Morph(field, {duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleValid);
			this.fireEvent("onValid", [field, options], 50);
		} else {
			new Fx.Morph(field, {duration: 500, transition: Fx.Transitions.linear}).start(this.options.styleInvalid);
			this.fireEvent("onInvalid", [field, options], 50);
		}
	},

	_onSubmit: function(event) {
		event = new Event(event);
		var isValid = true;
		this.validations.each(function(array) {
			if(this._isChildType(array[0])) this._validateChild(array[0], array[1]);
			else this._validate(array[0], array[1]);
			if(array[0].cbErr > 0) isValid = false;
		}.bind(this));

		if(!isValid) {
			event.stop();
		}
		if(isValid) this.form.submit();
		return isValid;
		
	},

	_onReset: function() {
		this.validations.each(function(array) {
			if(!this._isChildType(array[0])) array[0].setStyles(this.options.styleNeutral);
			array[0].cbErr = 0;
			this._msgRemove(array[0], array[1], true);
		}.bind(this));
	}
});

fValidator.implement(new Events, new Options);