var fValidator = new Class({
	Implements: [Options],

	options: {
		viewMsg: true,
		viewMsgButton: true,
		msgContainerTag: "div",
		msgClass: "fValidator-msg",
		onComplete: $empty,
		onNotValid: $empty,
		onBeforeSubmit: "",
		colorButton: true,
		formToSubmit: '',
		
		styleNeutral: {backgroundColor: '#FFFFFF', borderColor: '#BBBBBB', borderWidth:'1px', borderStyle:'solid'},
		styleValid: {backgroundColor: '#FFFFFF', borderColor: '#BBBBBB', borderWidth:'1px', borderStyle:'solid'},

		styleFocus: {backgroundColor: '#EEEEEE', borderColor: '#BBBBBB', borderWidth:'1px', borderStyle:'solid'},
		styleInvalid: {backgroundColor: '#FFCCCC', borderColor: '#CC0000', borderWidth:'1px', borderStyle:'solid'},

		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."},
		
	
		required: {type: "required", re: /[^.*]/, msg: "validate_campoVuoto"},
		integer: {type: "integer", re: /^[-+]?\d+$/, msg: "validate_numInt"},
		integer_nozero: {type: "integer_nozero", re: /^[-+]?\d+$/, msg: "validate_numInt_nozero"},
		
		select: {type: "select", re: /^[-+]?[1-9]\d*$/, msg: "validate_occorreSelezionare"},
		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})?$/ , msg: "validate_formatoFloat"},
		float_nozero: {type: "float_nozero", re: /^\d+(\,\d{0,2})?$/ , msg: "validate_formatoFloat_nozero"},

		value: {type: "value", re: /^\d{1,3}(.\d{3})*(\,\d{1,2})$/, msg: "validate_formatoValue"},
		value_nozero: {type: "value_nozero", re: /^\d{1,3}(.\d{3})*(\,\d{1,2})$/ , msg: "validate_formatoValue_nozero"},
		
		time: {type: "time", re: /^(([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-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|21|22)\d\d$/, msg: "validate_formatoData"},
		
		datetime: {type: "datetime", re: /^(0[1-9]|[12][0-9]|3[01])[/](0[1-9]|1[012])[/](19|20|21|22)\d\d ((([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?)?$/, msg: "validate_Datetime" },
		
		
		email: {type: "email", re: /^\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+$/, msg: "validate_EmailnonValida"},
		emailmultiple: {type: "emailmultiple", re: /^([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}(,)?)+$/, msg: "validate_EmailMultiplanonValida"},
		
		phone: {type: "phone", re: /^((00|\+)\d{1,}[\. ]?)?(\d[\. ]?)*(\d)+$/, msg: "validate_telefono"},
		confirm: {type: "confirm", msg: "validate_PasswordnonCoincide"},
		url: {type: "url", re: /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9A-Z\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/, msg: "validate_UrlnonValido"},
	
		check: {type: "check", re: 'checked', msg: "validate_Checkbox"},
		radio: {type: "radio", re: /^[-+]?[1-9]\d*$/, msg: "validate_campoVuoto"},
		consenso: {type: "consenso", re:/^[1-9]\d*$/, msg: "error_notelegali"},
		
		no_required: {type: "no_required", re: /[^.*]?/, msg: "validate_campoVuoto"},
		
		no_integer: {type: "no_integer", re: /^([-+]?\d+)?$/, msg: "validate_numInt"},
		no_integer_nozero: {type: "no_integer_nozero", re: /^([-+]?\d+)?$/, msg: "validate_numInt_nozero"},
		
		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})?))?$/ , msg: "validate_formatoFloat"},
		no_float_nozero: {type: "no_float_nozero", re: /^((\d+(\,\d{0,2})?))?$/ , msg: "validate_formatoFloat_nozero"},

		no_value: {type: "no_value", re: /^(\d{1,3}(.\d{3})*(\,\d{1,2}))?$/ , msg: "validate_formatoValue"},
		no_value_nozero: {type: "no_value_nozero", re: /^(\d{1,3}(.\d{3})*(\,\d{1,2}))?$/ , msg: "validate_formatoValue_nozero"},
		
		no_time: {type: "no_time", re: /^((([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-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|21|22)\d\d)?$/, msg: "validate_formatoData"},
				
		no_email: {type: "no_email", re: /^(\w+((-\w+)|(\.\w+))*\@\w+((\.|-)\w+)*\.\w+)?$/, msg: "validate_EmailnonValida"},
		no_emailmultiple: {type: "no_emailmultiple", re: /^(([a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}(,)?)+)?$/, msg: "validate_EmailMultiplanonValida"},
		
		no_phone: {type: "no_phone", re: /^(((00|\+)\d{1,}[\. ]?)?(\d{4}[\. ]?)*(\d)+)?$/, msg: "validate_telefono"},
		no_confirm: {type: "no_confirm", msg: "validate_PasswordnonCoincide"},
		
		no_check: {type: "no_check", re: 'checked', msg: "validate_Checkbox"},
		no_radio: {type: "no_radio", re: /^([-+]?[1-9]\d*)?$/, msg: "validate_campoVuoto"},
		
		no_datetime: {type: "no_datetime", re: /^((0[1-9]|[12][0-9]|3[01])[/](0[1-9]|1[012])[/](19|20|21|22)\d\d ((([0-1]?[0-9])|([2][0-3])):([0-5]?[0-9])(:([0-5]?[0-9]))?)?)?$/, msg: "validate_Datetime" },
		no_url: {type: "no_url", re: /^((http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9A-Z\-\._\?\,\'\/\\\+&amp;%\$#\=~])*)?$/, msg: "validate_UrlnonValido"},
		
		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.bottoneInvia=this.form.getElement('button[type=submit]');

		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 = klass.match(/^fValidate(\:.+)$/);
					
// 					var aFiltersSplitted = aFilters[1].substring(1).split('_');
// 					if(aFiltersSplitted[0]=='no'){
// 						var aFilter = aFiltersSplitted[1];
// 						var opzioniOggetto=this.options[aFilter];
// 						opzioniOggetto['re']=opzioniOggetto['re'].replace('{1}$/','?$/');
// 					}else{
// 						var aFilter = aFiltersSplitted[0];
// 						var opzioniOggetto=this.options[aFilter];
// 					}
					var aFilter = aFilters[1].substring(1);
					if(this.options[aFilter]) this.register(element, this.options[aFilter]);
					if(aFilter.charAt(0) == '=') this.register(element, $extend(this.options.confirm, {idField: aFilter.substr(1)}));
					if(aFilter.charAt(0) == '&') this.register(element, $extend(this.options.confirm, {idField: aFilter.substr(1)}));
				}
			}.bind(this));
		}.bind(this));

		this.form.addEvents({
			"submit": this._onSubmit.bind(this),
			"reset": this._onReset.bind(this)
		});
		
		if(this.form.get('tag')!='form'){
			if(!this.bottoneInvia) 
				this.bottoneInvia=this.form.getElement('input[name=submit]');
			else
				this.bottoneInvia.addEvent('click', this._onSubmit.bind(this) );
		}
	},

	register: function(field, options) {
		field = $(field);
		field.store('options',options);
		this.validations.push([field, options]);
		switch (options.type) {
			case "consenso":
				break;
			case "check":
				break;
			case "select":
				if($(field.id+"_INPUT")){
					fieldtempI=$(field.id+"_INPUT");
					fieldtempI.addEvent("blur", function() {
						this._validate(field);
					}.bind(this));
					
					fieldtempL=$(field.id+"_LIST");
					fieldtempL.addEvent("click", function() {
						this._validate(field);
					}.bind(this));
					
					field.addEvent("click", function() {
						this._validate(field);
					}.bind(this));
				}else if(field.id.contains("lbl_")){
// 					fieldOriginal=field.id.replace("lbl_","");
// 					fieldOriginal=$(fieldOriginal);
// 					fieldOriginal.store('options',options);
					field.addEvent("blur", function() {
						this._validate(field);
					}.bind(this));
				}else{
					field.addEvent("blur", function() {
						this._validate(field);
					}.bind(this));
				}
				
				field.addEvent("focus", function() {
					new Fx.Morph(field, {duration: 250, transition: Fx.Transitions.linear}).start(this.options.styleFocus);
				}.bind(this));
				break;
			case "dateItalian":
				if (!field.hasClass('disallowUserInput')){
					field.addEvent("blur", function() {
						this._validate(field);
					}.bind(this));
					field.addEvent("focus", function() {
						new Fx.Morph(field, {duration: 250, transition: Fx.Transitions.linear}).start(this.options.styleFocus);
					}.bind(this));
				}
				break;
			default:
				field.addEvent("blur", function() {
					this._validate(field);
				}.bind(this));
				field.addEvent("focus", function() {
					new Fx.Morph(field, {duration: 250, transition: Fx.Transitions.linear}).start(this.options.styleFocus);
				}.bind(this));
		}
	},
	
	_log: function(){
		console.log(this.validations);
	},
	
	unregister: function(field, options) {
		field = $(field);
		options=field.retrieve('options');
		if(options){
			this._msgRemove(field, options);
			field.removeEvents("blur");
			this.validationsTemp=[];
			this.validations.each(function(array) {
				if (field!=array[0]){
					this.validationsTemp.push([array[0], array[1]]);
				}
			}.bind(this));
			this.validations=this.validationsTemp;
		}
	},

	_isChildType: function(el) {
		var elType = el.type;
		if (elType) var elType = elType.toLowerCase();
		if((elType == "radio") || (elType == "checkbox")) return true;
		return false;
	},

	_validate: function(field) {
		field = $(field);
		options=field.retrieve('options');
		switch(options.type) {
			case "no_float_nozero":
			case "no_value_nozero":
			case "float_nozero":
			case "value_nozero":
			case "integer_nozero":
			case "no_integer_nozero":	
				if(field.get('value')=='0' || field.get('value')=='0,00' ) {
					this._msgInject(field, options);
					if(this.options.onNotValid!=$empty)
						this.fireEvent('onNotValid', [this.sets, this]);     
				}
				else {
					if(options.re.test(field.get('value'))) {
						this._msgRemove(field, options);
						//this._chkStatus(field, options);
					}
					else {
						this._msgRemoveNoMorph(field, options);
						this._msgInject(field, options);
						if(this.options.onNotValid!=$empty)
							this.fireEvent('onNotValid', [this.sets, this]);          
					}	       
				}		
				break;
			case "confirm":
				if($(options.idField).get('value') == field.get('value')) 
					this._msgRemove(field, options);
				else 
					this._msgInject(field, options);
				break;
			case "select":
				if($(field.id+"_DIV")){
					fieldtempD=$(field.id+"_DIV");
					if(options.re.test(field.get('value'))){
						this._OK(field, options);
						this._msgRemove(fieldtempD, options);
						this._chkStatus(field, options);
					}else {
						this._KO(field, options);
						this._msgInject(fieldtempD, options);
						if(this.options.onNotValid!=$empty)
							this.fireEvent('onNotValid', [this.sets, this]);          
					}
				}else if(field.id.contains("lbl_")){
					fieldOriginal=field.id.replace("lbl_","");
					fieldOriginal=$(fieldOriginal);
					if(options.re.test(fieldOriginal.get('value'))) {
						this._msgRemove(field, options);
					}	else {
						this._msgInject(field, options);
						if(this.options.onNotValid!=$empty)
							this.fireEvent('onNotValid', [this.sets, this]);          
					}
				}else{
					if(options.re.test(field.get('value'))) {
						this._msgRemove(field, options);
					}
					else {
						this._msgInject(field, options);
						if(this.options.onNotValid!=$empty)
							this.fireEvent('onNotValid', [this.sets, this]);          
					}
				}
				break;
			case "email":
			case "no_email":
			default:
				if (field.value!='' || (options.type.contains('no_')) ) {
					this._chkStatus(field, options);
					if(options.re.test(field.get('value'))) {
						this._msgRemove(field, options);
						//this._chkStatus(field, options);
					}
					else {
						this._msgRemoveNoMorph(field, options);
						this._msgInject(field, options);
						if(this.options.onNotValid!=$empty)
							this.fireEvent('onNotValid', [this.sets, this]);          
					}				
				}else{ 
					this._msgRemoveNoMorph(field, options);
					this._msgInject(field, options, true);
					if(this.options.onNotValid!=$empty)
						this.fireEvent('onNotValid', [this.sets, this]);    
				}

		}
	},

	_validateChild: function(child) {	
		child = $(child);
		options=child.retrieve('options');
// 			case "check":
// 				console.log(options);
// 				if($(options.idField).get('value') == field.get('value')) 
// 					this._msgRemove(field, options);
// 				else 
// 					this._msgInject(field, options);
// 				break;
	
		switch(options.type) {
			case "check":
				var isValid = true;
				if(child.checked == false && options.type == "check") isValid = false;
				if(isValid) this._msgRemove(child, options);
				else {
					this._msgInject(child, options);
					if(this.options.onNotValid!=$empty)
						this.fireEvent('onNotValid', [this.sets, this]);
				}
				
				break;
			default:
				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 (Browser.Engine.trident) 
							valore=nlButtonGroup[i].value;
						else
							valore=nlButtonGroup[i].get('value');
						if(!options.re.test(valore)) {
							isValid = false;
							break;
						}
					}
				}
				if(cbCheckeds == 0 && options.type == "required") isValid = false;
				
				parentID=child.getParent('div').id;
				
				if(isValid) this._msgRemoveChild(child,parentID, options);
				else {
					this._msgInjectChild(child,parentID, options);
					if(this.options.onNotValid!=$empty)
						this.fireEvent('onNotValid', [this.sets, this]);          
				}
		}
	},

	_msgInject: function(owner, options, vuoto) {
		if(vuoto!=undefined) 
			msg=getGlobalLabel("validate_campoVuoto")
		else
			msg=getGlobalLabel(options.msg);
			
		if(!$(owner.getProperty("id")  + "__" + options.type +"_msg")) {
			if (this.options.viewMsg) {
				var msgContainer = new Element(this.options.msgContainerTag, {"id": owner.getProperty("id") + "__" + options.type +"_msg", "class": this.options.msgClass})
	// 			.set('html',options.msg)
				.set('html', 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);
	},
	_msgInjectChild: function(owner,parentID, options) {
		if(!$(parentID  + "__" + options.type +"_msg")) {
			if (this.options.viewMsg) {
				var msgContainer = new Element(this.options.msgContainerTag, {"id": parentID  + "__" + options.type +"_msg", "class": this.options.msgClass})
	// 			.set('html',options.msg)
				.set('html', getGlobalLabel(options.msg))
				.set('opacity',0)
				.inject(parentID, 'after');
				new Fx.Morph(msgContainer, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': [0, 1]});
			}
		}
		owner.cbErr++;
	},
	
	_OK: function (owner, options) {
		owner.cbErr=0;
	},

	_KO: function (owner, options) {
		owner.cbErr++;
	},

	_msgRemoveNoMorph: function(owner, options, isReset) {
		isReset = isReset || false;
		if($(owner.getProperty("id") + "__" + options.type +"_msg")) {
			var el = $(owner.getProperty("id")  + "__" + options.type +"_msg");
			el.destroy();
		}
		if(!isReset) {
			owner.cbErr=0;
		}
	},
	_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);
		}
	},
	_msgRemoveChild: function(owner,parentID, options, isReset) {
		isReset = isReset || false;
		if($(parentID  + "__" + options.type +"_msg")) {
			var el = $(parentID  + "__" + options.type +"_msg");
			new Fx.Morph(el, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': 1});
			el.destroy();
		}
		if(!isReset) {
			owner.cbErr=0;
		}
	},

	_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);
		}
	},
	
	_ResetBottoneInvia: function(){
		if($(this.bottoneInvia.getProperty("id") +"_msg")){
			var el = $(this.bottoneInvia.getProperty("id") +"_msg");
			new Fx.Morph(el, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': 1});
			new Fx.Morph(this.bottoneInvia, {duration: 500, transition: Fx.Transitions.linear}).start({'color': ['red', 'black']});
			el.destroy();		
		}
	},
	_BottoneInviaInvalid: function(){
		if(!$(this.bottoneInvia.getProperty("id") +"_msg")){
			if (this.options.colorButton){
				new Fx.Morph(this.bottoneInvia, {duration: 500, transition: Fx.Transitions.linear}).start({'color': ['black', 'red']});
			}
			if(this.options.viewMsgButton){
				var msgContainer = new Element('div', {"id": this.bottoneInvia.getProperty("id") +"_msg", "class": this.options.msgClass})
				.set('html', getGlobalLabel("validate_RicontrollareForm"))
				.set('opacity',0)
				.inject(this.bottoneInvia.getParent());
				new Fx.Morph(msgContainer, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': [0, 1]});
			}
		}
	},

	_onSubmit: function(event) {
		event = new Event(event);
		var isValid = true;
		this.validations.each(function(array) {
			if(this._isChildType(array[0])) this._validateChild(array[0]);
			else this._validate(array[0]);
			if(array[0].cbErr > 0) isValid = false;
		}.bind(this));
		
		if(!isValid) {
			if (this.options.colorButton || this.options.viewMsgButton) this._BottoneInviaInvalid();
			if(this.options.onNotValid!=$empty)
				this.fireEvent('onNotValid', [this.sets, this]);
			event.stop();
		}
		
		if(isValid){
			if(this.options.onBeforeSubmit!="") {
				eval('isValid='+this.options.onBeforeSubmit);
			}
		}
		
		if(isValid){
			if (this.options.colorButton) this._ResetBottoneInvia();
			new Fx.Morph(this.bottoneInvia, {duration: 500, transition: Fx.Transitions.linear}).start({'opacity': [1, 0]});
			if(this.form.get('tag')!='form')
				this.form = this.form.getElement('form[name='+this.options.formToSubmit+']');
			this.form.submit();
			if(this.options.onComplete!=$empty)
				this.fireEvent('onComplete', [this.sets, this]);
		}
		return isValid;
	},

	_onReset: function() {
		this._ResetBottoneInvia();
		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));
	},
	
	isValidForm: function() {
		var isValid = true;
		this.validations.each(function(array) {
			if(this._isChildType(array[0])) this._validateChild(array[0]);
			else this._validate(array[0]);
			if(array[0].cbErr > 0) {
				isValid = false;
// 				colorMenu(array[0].id); //commentato il 16/02/2010
			}
		}.bind(this));
		return isValid;
	}
	
	
});

fValidator.implement(new Events, new Options);