Validator = new Class({
	Box : false,
	Result: true,
	Fields: new Hash(),
	Failed: false,

	Add: function( Id, Type, Message, Parameter ) {
		if ( this.Fields.get(Id) == null ) {
			this.Fields.set( Id, new Hash() );
		}
		var Rule = new Hash();
		Rule.set( 'Type', Type );
		if ( Message ) {
			Rule.set( 'Message', Message );
		}
		if ( Parameter ) {
			Rule.set( 'Parameter', Parameter );
		}
		this.Fields.get(Id).set( this.Fields.get(Id).getLength()+1, Rule );
	},

	ValidateForm: function( Form ) {
		this.Result    = true; //We assume by default everything is ok.
		var LastFailed = Validator.Failed;
		var FailedField;

		this.Fields.getKeys().each( function( FieldId ) {
			var Field = $(FieldId);

			if ( Field.form == Form ) {
				if ( Validator.Result ) { //If its already failed, do not continue.
					Validator.ValidateElement( Field );
					if ( !this.Result ) {
						FailedField = Field;
					}
				}
			}
		});
		if ( FailedField ) {
			FailedField.focus();
			window.scrollTo( FailedField.getCoordinates()['top'], 0 );
		}
		if ( this.Failed && (this.Failed == LastFailed) ) {
			this.Box.highlight();
		}
		return this.Result;
	},

	ValidateElement: function( Field ) {
		Validator.Result = true;

		Validator.Fields.get(Field.get('id')).getValues().each( function( Rule ) {
			if ( Validator.Result ) { //This is here to avoid validating of an element where some other one is already failed: just one error at a time
				var Function = Rule.get('Type');

				if ( typeof( Function ) == 'function' ) {
					if ( Field.get('value').trim().length < 1 && Function._name != 'Required' ) {
						return ;
					}
					var Result = Function(Field, Rule);
					if ( Result ) {
						Validator.Result = true;
					} else {
						Validator.Failed = Rule;
						Validator.Result = false;
					}
				}
				
			}
		});
		if ( Validator.Result ) {
			Field.addClass('Validator Success').removeClass('Validator Failed');
			if ( Validator.Box.On == Field ) {
				Validator.Hide();
			}
		} else {
			Field.addClass('Validator Failed').removeClass('Validator Success');
			Validator.Show( Field, Validator.Failed );
		}
	},

	Show: function( Field, Rule ) {
		if ( !this.Box ) {
			this.Box = new Element( 'span', { id : 'Validator' } );
			this.Box.inject( $$('body')[0] );
			this.Box.setStyle('position', 'absolute');
			this.Box.set('morph', {duration: 'long', transition: 'bounce:out'});
		}
		this.Box.set( 'html', Rule.get( 'Message' ) );

		var X = Field.getCoordinates()['left'] + Field.getSize()['x'] + 5;
		var Y = Field.getCoordinates()['top'];
		this.Box.show();
		this.Box.morph({ top: Y, left : X, opacity:1 });
		this.Box.On = Field;
	},

	Hide: function() {
		if ( this.Box ) {
			this.Box.morph({opacity:0});
			this.Box.hide();
		}
		this.Box.On = '';
	},

	Required: function(Field) {
		return Field.get('value').clean() != "";
	},

	Length: function(Field, Rule) {
		var Minimum = Rule.get('Parameter').Minimum;
		var Maximum = Rule.get('Parameter').Maximum;

		if ( Minimum && ( Field.value.length < Minimum ) ) {
			return false;
		}
		if ( Maximum && ( Field.value.length > Maximum ) ) {
			return false;
		}
		return true;
	},

	Email: function(Field, Rule) {
		var Email = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
		if ( Email.test( Field.value ) ) {
			return true;
		}
		return false;
	},

	Number: function(Field, Rule) {
		var Number = /^\d+$/;
		if ( Number.test( Field.value ) ) {
			return true;
		}
		return false;
	}

});

Validator = new Validator;

window.addEvent('domready', function() {
	$$('form input').each( function( E ) {
		E.addEvent('keyup', function() {
			Validator.ValidateElement( E );
		});
	});
});