
/**
 * Simple Validator
 * Replaces the text of an element with an error message if the given validation fails and adds and class to this element.
 * When an Element is focused again, the class is removed and the wrong value (if there was one) is restored
 */
var Validator = new Class({
	
	options: {
		text: { // Text of the Error Message; The key must be the ID of an element with class="validate[xy]"
			name: "Name fehlt",
			first_name: "Vorname fehlt",
			last_name: "Nachname fehlt",
			firma: "Firma fehlt",
			adresse: "Adresse fehlt",
			plz: "PLZ fehlt",
			ort: "Stadt fehlt",
			telefon: "Telefon fehlt",
			fax: "Telefax fehlt",
			email: "eMail Adresse fehlt"
		},
		selector: "error",
		form: "",
		event: "submit" // Valid are "submit" and "blur"
	},
	fields:    [],
	backups:   [],
	form:      null,
	error:     false,
	lastValue: '',
	
	
	regexp : {
		alpha : /^[a-z ._-]+$/i,
		alphanum : /^[a-z0-9 ._-]+$/i,
		digit : /^[-+]?[0-9]+$/,
		nodigit : /^[^0-9]+$/,
		number : /^[-+]?\d*\.?\d+$/,
		email : /^[a-z0-9._%-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i,
		phone : /^[\d\s \/().-]+$/
		//url : /^(http|https|ftp)\:\/\/[a-z0-9\-\.]+\.[a-z]{2,3}(:[a-z0-9]*)?\/?([a-z0-9\-\._\?\,\'\/\\\+&amp;%\$#\=~])*$/i
	},
	
	initialize: function(options) {

		this.setOptions(options);
		this.form = $(this.options.form);

		if ($type(this.form) != "element") return;

			// Push all Elements
		form = '#' + this.options.form + ' ';
		$$(form + 'input', form + 'textarea').each(function(element) {
			if (element.className.test(/validate\[(.+)\]$/i)) { // Is a form
				this.fields.push({
					"el": element,
					"tests": element.className.match(/validate\[(.+)\]$/i)[1].split(",")
				});
			}
		}, this);
	
			// Bind validation to form
		this.form.addEvent("submit", this.validate.bind(this));
		
			// Remove Messages on exit
		window.addEvent('unload', this.removeAllErrors.bind(this));
	},
	
	validate: function(e) {
		
		this.error = false;
		
		this.fields.each(function(field) {
			
			if (!this.form.getElements('input').contains(field.el)) return;
			
			field.tests.each(function(test) {
				this.validateSingeItem(test, field);
			}, this);
			
		}.bind(this));
		if (this.error) {
			e = new Event(e).stop();
			return false;
		} else {
			return true;
		}
	},
	
	validateSingeItem: function(test, field) {
		test = test.split('-');
		this.currentElement = field;
		valid = true;
		
		switch(test[0]) {
				
			case 'email':
			case 'mail':
				valid = this._regexp(this.regexp.email);
				break;
				
			case 'number':
			case 'zahl':
				valid = this._regexp(this.regexp.number);
				break;
				
			case 'zip':
			case 'plz': // Contains 4, 5, or 6 numeric characters
				valid = (this._regexp(this.regexp.number) && this._length(4, 6));
				break;
						
			case 'length':
				valid = this._length(test[1], test[2]);
				break;
						
			case 'phone':
			case 'tel':
			case 'telefon':
				valid = this._regexp(this.regexp.phone);
				break;
		}
			
			// Test fails, or value is the error message -> throw an error	
		if (!valid || this.lastValue == this.options.text[this.currentElement.el.id]) this.setError();
			
	},
	
	setError: function() {
		el = this.currentElement.el;
		if (this.options.text[el.id] != this.lastValue.clean()) this.backups[ el.id ] = this.lastValue;
		el.setProperty('value', this.options.text[el.id]).addClass(this.options.selector).addEvent("focus", this.removeError.bind(this));
		this.error = true;
	},
	
	removeAllErrors: function() {
		this.fields.each(function(item) {
			if (item.el.hasClass(this.options.selector)) item.el.fireEvent('focus');
		}, this);
	},
	
	removeError: function(e) {
	
		this.currentElement = new Event(e).target;
		this.fields.each(function(field) {
			
			if (this.currentElement == field.el && this.currentElement.hasClass(this.options.selector)) {
				this.currentElement.removeClass(this.options.selector).setProperty("value", (this.backups[ this.currentElement.id ] ? this.backups[ this.currentElement.id ] : ''));
			}
			
		}.bind(this));
	
	},
	
	_regexp: function(exp) {	
		return (this.last().search(exp) != -1);
	},
	
	
	_length: function(min, max) {
		min = min.toInt();		
		max = (max == 'x') ? 999999 : max.toInt();
		val = this.last();	
		
		return (val.length >= min && val.length <= max);
	},
	
	last: function() {
		this.lastValue = (" " + this.currentElement.el.getProperty('value')).trim();	
		return this.lastValue;
	}
	
});
Validator.implement(new Options);
