var Validator = new Class({
	validate: function(anInput){ //Template Method
		return this.getRegularExpression().test(anInput.value);
	},

	getRegularExpression: function(){
		return {test:function(){return true;}};
	}
});

EmailValidator = new Class({
	Extends: Validator,

	getRegularExpression: function(){
		return /^(([\-\w]+)\.?)+@(([\-\w]+)\.?)+\.[a-zA-Z]{2,4}$/;
	}
});

AlphaValidator = new Class({
	getRegularExpression: function(){
		return /[a-zA-Z]+$/; //Match for upper- or lowercase letters
	}
});

NumberValidator = new Class({
	Extends: Validator,

	getRegularExpression: function(){
		return /(^\d+$)|(^\d+\.\d+$)/;
	}
});

NotEmptyValidator = new Class({
	Extends: Validator,

	getRegularExpression: function(){
		return /(^[\s\S])/;
	}
});

NotEqualValidator = new Class({
	Extends: Validator,

	initialize: function(aValue) {
		this.valueComparator = aValue;
	},

	getRegularExpression: function(){
		return eval('/^(?!'+this.valueComparator+')/');
	}
});

DateValidator = new Class({
	Extends: Validator,

	validate: function(anInput){
		if (anInput.value != "") {
			var result = this.parent(anInput);
			var fields = anInput.value.split('/');
			var d = new Number(fields[0]);
			if(fields[2]){
				var y = new Number(fields[2]);
				if(!(y % 4) && (y % 100) || !(y % 400) ? true : false) {
					if(d > 29) {
						result = false;
					}
				} else {
					if(d > 28) {
						result = false;
					}
				}
			} else {
				if(new Number(fields[1])==2 && d > 29) {
					result = false;
				}
			}
			return result;
		}
		return true;
	}
});

SpanishDateValidator = new Class({
	Extends: DateValidator,

	getRegularExpression: function(){
		return /((0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$)|((0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])$)/;
	}
});

LengthValidator = new Class({
	Extends: Validator,

	initialize: function(options) {
		if(options.exactly) {
			options.min = options.exactly;
			options.max = options.exactly
		}
		this.min = $pick(options.min, 0);
		this.max = $pick(options.max, '');
	},

	getRegularExpression: function() {
		return eval('/^(.){' + this.min + ',' + this.max + '}$/');
	},
    //Originalmente no se redefinía esta función. 
	//No aceptaba enters en textos largos, así que se modificó redefiniendo	
	validate: function(anInput){ 
		var largo = anInput.value.trim().length;
		return   (this.min < largo) & (largo < this.max);
	}
});

EqualsFieldsValidator = new Class({
	Extends: Validator,

	initialize: function(inputOne, inputTwo) {
		this.inputOne = inputOne;
		this.inputTwo = inputTwo;
	},

	validate: function() {
		return this.inputOne.value == this.inputTwo.value;
	}
});

//Form Validator Manager
FormValidatorManager = new Class({

	messages: new Hash,
	validators: new Hash,

	initialize: function(form, options) {
		var that = this;
		this.form = $(form);
		this.display = $(options.display);
		this.preSubmit = options.preSubmit;
		this.immediately = options.immediately;
		options.rules.each(function(aRule){
			that.addSimpleRule(that.form, aRule[0], aRule[1], aRule[2]);
			//aRule[0] //name
			//aRule[1] //validator
			//aRule[2] //message
		});
		this.form.addEvent('submit', function() {
			var valid = true;
			if(that.preSubmit) {
				pre = that.preSubmit();
				valid = pre.validator.validate();
				if(!valid) {
					that.displayError(pre.message);
				}
			}
			if(!(that.validate() && valid)) {
				
				return false;
			} else {
				if(options.ajax) {
					options.ajax();
					return false;
				}
			}
			return true;
		});
	},

	findElementByName: function(aForm, anElementName){
		var i=0;
		var result = false;
		while(i<aForm.elements.length){
			if (aForm.elements.item(i).name == anElementName){
				result = aForm.elements.item(i);
			}
			i++;
		}
		return result;
	},

	addSimpleRule: function(aForm, anElementName, validator, aTextMessage) {
		var messageEntry = {};
		messageEntry[anElementName] = aTextMessage;
		this.messages.extend(messageEntry);

		var validatorEntry = {};
		validatorEntry[anElementName] = validator;
		this.validators.extend(validatorEntry);

		this.setupValidation(aForm, anElementName, validator); //Ã³
	},

	setupValidation: function(aForm, anElementName, validator) {
		var that = this;
		var element = $(this.findElementByName($(aForm), anElementName));
		if(this.immediately) {
			element.addEvent('blur', function(){
				try{
					if(!validator.validate(element)){
						that.showError(element);
					} else {
						that.hideError(element);
					}
				} catch(e) {
					console.error(e);
					for(var m in e) {
						if(m != 'stack') console.error(m + ": " + e[m]);
						else {
							console.group("Stack trace:");
							console.log(e.stack);
							console.groupEnd();
						}
					}
				}
			});
		}
		element.addEvent('focus', function() {
			element.removeClass('fv-error');
		});
	},

	displayError: function(message) {
		this.display.set('text', message);
		this.display.set('class', 'authenticationError');
	},

	showError: function(element) {
		element.addClass('fv-error');
		this.displayError(this.messages.get(element.name));
	},

	hideError: function(element) {
		element.removeClass('fv-error');
		this.display.set('class', 'authenticationErrorHide');
		this.display.set('text', '');
	},

	hideErrors: function() {
		var i=0;
		while(i<this.form.elements.length){
			$(this.form.elements.item(i)).removeClass('fv-error');
			i++;
		}
		this.display.set('class', 'authenticationErrorHide');
		this.display.set('text', '');
	},

	validate: function() {
		var that = this;
		var isValid = true;
		this.validators.each(function(validator, anElementName){
			if(isValid) {
				var element = that.findElementByName(that.form, anElementName);
				if(!validator.validate(element)) {
					isValid = false;
					if(element){
						element.focus();
						that.showError(element);
					}					
				} else {
					element.removeClass('fv-error');
				}
			}
		});
		return isValid;
	}

});

ContactFormValidatorManager = new Class({

	messages: new Hash,
	validators: new Hash,

	initialize: function(form, options) {
		var that = this;
		this.form = $(form);
		this.display = $(options.display);
		this.preSubmit = options.preSubmit;
		this.immediately = options.immediately;
		options.rules.each(function(aRule){
			that.addSimpleRule(that.form, aRule[0], aRule[1], aRule[2]);
			//aRule[0] //name
			//aRule[1] //validator
			//aRule[2] //message
		});
		this.form.addEvent('submit', function() {
			var valid = true;
			if(that.preSubmit) {
				pre = that.preSubmit();
				valid = pre.validator.validate();
				if(!valid) {
					that.displayError(pre.message);
				}
			}
			if(!(that.validate() && valid)) {
				
				return false;
			} else {
				if(options.ajax) {
					options.ajax();
					return false;
				}
			}
			return true;
		});
	},

	findElementByName: function(aForm, anElementName){
		var i=0;
		var result = false;
		while(i<aForm.elements.length){
			if (aForm.elements.item(i).name == anElementName){
				result = aForm.elements.item(i);
			}
			i++;
		}
		return result;
	},

	addSimpleRule: function(aForm, anElementName, validator, aTextMessage) {
		var messageEntry = {};
		messageEntry[anElementName] = aTextMessage;
		this.messages.extend(messageEntry);

		var validatorEntry = {};
		validatorEntry[anElementName] = validator;
		this.validators.extend(validatorEntry);

		this.setupValidation(aForm, anElementName, validator); //Ã³
	},

	setupValidation: function(aForm, anElementName, validator) {
		var that = this;
		var element = $(this.findElementByName($(aForm), anElementName));
		if(this.immediately) {
			element.addEvent('blur', function(){
				try{
					if(!validator.validate(element)){
						that.showError(element);
					} else {
						that.hideError(element);
					}
				} catch(e) {
					console.error(e);
					for(var m in e) {
						if(m != 'stack') console.error(m + ": " + e[m]);
						else {
							console.group("Stack trace:");
							console.log(e.stack);
							console.groupEnd();
						}
					}
				}
			});
		}
		element.addEvent('focus', function() {
			element.removeClass('fv-error');
		});
	},

	displayError: function(message) {
		this.display.set('text', message);
		this.display.set('class', 'authenticationError');
	},

	showError: function(element) {
		element.addClass('fv-error');
		this.displayError(this.messages.get(element.name));
	},

	hideError: function(element) {
		element.removeClass('fv-error');
		this.display.set('class', 'authenticationErrorHide');
		this.display.set('text', '');
	},

	hideErrors: function() {
		var i=0;
		while(i<this.form.elements.length){
			$(this.form.elements.item(i)).removeClass('fv-error');
			i++;
		}
		this.display.set('class', 'authenticationErrorHide');
		this.display.set('text', '');
	},

	validate: function() {
		var that = this;
		var isValid = true;
		this.validators.each(function(validator, anElementName){
			if(isValid) {
				var element = that.findElementByName(that.form, anElementName);
				if(!validator.validate(element)) {
					isValid = false;
					if(element){
						element.focus();
						that.showError(element);
					}					
				} else {
					element.removeClass('fv-error');
				}
			}
		});
		return isValid;
	}

});

