var FormChecker = Class.create();
Object.extend(FormChecker.prototype, {
	EVENTS:     ['keyup', 'change', 'blur', 'click'],
	TEXT:       ['text', 'password', ''],
	CHECKBOX:   ['checkbox'],
	RADIO:      ['radio'],
	ATTRIBUTES: ['fc_name', 'fc_required', 'fc_type', 'fc_maxlength', 'fc_minlength', 'fc_max', 'fc_min', 'fc_pattern'],
	TYPES: {
		/* -, _, \, /, ., ;, :, ,, ?, !, a..z */
		alpha: /^[-_\\\/\.;:,\?!a-z]*$/i,
		/* -, 0..9 */
		numeric: /^-?[0-9]+$/,
		integer: /^-?[0-9]+$/,
		/* ., ,, 0..9 */
		decimal: /^-?([0-9]+|[0-9]*[\.,][0-9]+)$/,
		float: /^-?([0-9]+|[0-9]*[\.,][0-9]+)$/,
		/* -, _, \, /, ., ;, :, ,, ?, !, a..z, 0..9 */
		alphanum: /^[-_\\\/\.;:\?!a-z0-9]*$/i,
		email: /^([0-9a-z]([-.\w]*[0-9a-z])*@([0-9a-z][-\w]*[0-9a-z]\.)+[a-z]{2,6})$/i,
		zip: /^[0-9][0-9][0-9][0-9][0-9]?$/,
		phone: /^\+?[0-9]+$/,
		ip: /^(\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)(\.(\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)){3}$/,
		/* dd.mm.yyyy / dd.mm.yy */
		date: /^([0-2][0-9]|3[0-1])\.(0[1-9]|1[1-2])\.(19|20)?[0-9][0-9]$/
	},
	MESSAGES: [
		/* deutsch */
		{
			required:  'Das Feld "%fc_name%" ist ein Pflichtfeld',
			maxlength: 'Bitte geben Sie maximal %fc_maxlength% Zeichen ein',
			minlength: 'Bitte geben Sie mindestens %fc_minlength% Zeichen ein',
			max:       'Bitte geben Sie eine Zahl ein, die kleiner oder gleich %fc_max% ist',
			min:       'Bitte geben Sie eine Zahl ein, die grösser oder gleich %fc_min% ist',
			alpha:     'Bitte verwenden Sie nur folgende Zeichen: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z"',
			numeric:   'Bitte geben Sie eine gültige ganze Zahl ein',
			integer:   'Bitte geben Sie eine gültige ganze Zahl ein',
			decimal:   'Bitte geben Sie eine gültige Dezimalzahl ein',
			float:     'Bitte geben Sie eine gültige Dezimalzahl ein',
			alphanum:  'Bitte verwenden Sie nur folgende Zeichen: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z", "0" - "9"',
			email:     'Bitte geben Sie eine gültige E-Mail Adresse ein',
			zip:       'Bitte geben Sie eine gültige Postleitzahl ein (nur Zahlen)',
			phone:     'Bitte geben Sie eine gültige Telefon-/Faxnummer ein (nur Zahlen sowie optional ein "+", ohne Abstände)',
			ip:        'Bitte geben Sie eine gültige IP-Adresse ein',
			date:      'Bitte geben Sie ein gültiges Datum ein (dd.mm.yyyy)',
			unknown:   'Bitte überprüfen Sie Ihre Eingabe',
			dependency:'Bitte überprüfen Sie das Feld %fc_name%'
		},
		/* französisch */
		{
			required:  'champ obligatoire',
			maxlength: 'Nombre des lettres maximale: %fc_maxlength%',
			minlength: 'Nombre des lettres en moins: %fc_minlength%',
			max:       'Veuillez entrer un chiffre moins ou &eacute;gale %fc_max%',
			min:       'Veuillez entrer un chiffre plus ou &eacute;gale que %fc_min%',
			alpha:     'Veuillez n\'utiliser que les signes suivants: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z"',
			numeric:   'Veuillez entrer un chiffre entier valable',
			integer:   'Veuillez entrer un chiffre entier valable',
			decimal:   'Veuillez entrer un chiffre d&eacute;cimal valable',
			float:     'Veuillez entrer un chiffre d&eacute;cimal valable',
			alphanum:  'Veuillez n\'utiliser que les signes suivants: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z", "0" - "9"',
			email:     'Veuillez entrer une adresse e-mail valable',
			zip:       'Veuillez entrer un code postal valable',
			phone:     'Veuillez entrer un no. t&eacute;l&eacute;phone ou fax valable (seulement des chiffres ou "+" sans trous)',
			ip:        'Veuillez entrer une adresse IP valable',
			date:      'Veuillez entrer une date valable (dd.mm.yyyy)',
			unknown:   'Veuillez v&eacute;rifier votre entr&eacute;e',
			dependency:'Veuillez v&eacute;rifier le champ %fc_name%'
		},
		/* englisch */
		{
			required:  'Required Entry',
			maxlength: 'Maximum number of characters: %fc_maxlength%',
			minlength: 'Minimal number of characters: %fc_minlength%',
			max:       'Please enter a number smaller than or equal %fc_max%',
			min:       'Please enter a number bigger than or equal %fc_min%',
			alpha:     'Do only use the following symbols, please: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z"',
			numeric:   'Please enter a valid whole number',
			integer:   'Please enter a valid whole number',
			decimal:   'Please enter a valid decimal number',
			float:     'Please enter a valid decimal number',
			alphanum:  'Do only use the following symbols, please: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z", "0" - "9"',
			email:     'Please enter a valid e-mail address',
			zip:       'Please enter a valid zip code',
			phone:     'Please enter a valid phone or fax number (only numbers or "+" without gaps)',
			ip:        'Please enter a valid IP-address',
			date:      'Please enter a valid date (dd.mm.yyyy)',
			unknown:   'Please verify your entries',
			dependency:'Please verify the field %fc_name%'
		},
		/* italienisch */
		{
			required:  'Das Feld "%fc_name%" ist ein Pflichtfeld',
			maxlength: 'Bitte geben Sie maximal %fc_maxlength% Zeichen ein',
			minlength: 'Bitte geben Sie mindestens %fc_minlength% Zeichen ein',
			max:       'Bitte geben Sie eine Zahl ein, die kleiner oder gleich %fc_max% ist',
			min:       'Bitte geben Sie eine Zahl ein, die grösser oder gleich %fc_min% ist',
			alpha:     'Bitte verwenden Sie nur folgende Zeichen: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z"',
			numeric:   'Bitte geben Sie eine gültige ganze Zahl ein',
			integer:   'Bitte geben Sie eine gültige ganze Zahl ein',
			decimal:   'Bitte geben Sie eine gültige Dezimalzahl ein',
			float:     'Bitte geben Sie eine gültige Dezimalzahl ein',
			alphanum:  'Bitte verwenden Sie nur folgende Zeichen: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z", "0" - "9"',
			email:     'Bitte geben Sie eine gültige E-Mail Adresse ein',
			zip:       'Bitte geben Sie eine gültige Postleitzahl ein (nur Zahlen)',
			phone:     'Bitte geben Sie eine gültige Telefon-/Faxnummer ein (nur Zahlen sowie optional ein "+", ohne Abstände)',
			ip:        'Bitte geben Sie eine gültige IP-Adresse ein',
			date:      'Bitte geben Sie ein gültiges Datum ein (dd.mm.yyyy)',
			unknown:   'Bitte überprüfen Sie Ihre Eingabe',
			dependency:'Bitte überprüfen Sie das Feld %fc_name%'
		}
	],
	
	elements: [],
	showMessages: false,
	hasMessages: false,
	language:1,
	
	initialize: function(form) {
		this.form = $(form);
		this.form.fc = this;
		this.options = arguments[1] || {};
    this.language = this.options.language || 1;
		this.elements = [];
		this.showMessages = false;
		this.hasMessages = false;
		$A(this.form.getElementsByTagName('input')).each(this.initInputElement.bind(this));
		$A(this.form.getElementsByTagName('textarea')).each(this.initElement.bind(this));
		this.check();
	},
	
	initInputElement: function(element) {
		element = $(element);
		if (element.nodeName == 'INPUT' && this.TEXT.indexOf(element.type) > -1) {
			this.initElement(element);
		}
	},
	
	initElement: function(element) {
		element = $(element);
		this.elements[this.elements.length] = element;
		var att, i = 0;
		while (att = element.attributes[i++]) {
			if (att.nodeName.indexOf('fc_') == 0) {
				for (var j = 0; j < this.EVENTS.length; j++) {
					Event.observe(element, this.EVENTS[j], function(ev) {
						this.event = ev || window.event;
						this.checkElement(element);
					}.bind(this));
				}
				
				break;
			}
		}

		if (element.getAttribute('fc_showMessage')) {
			Event.observe(element, 'mouseover', function() {
				if (this.message) {
					var func = eval('function(){' + element.getAttribute('fc_showMessage') + '}');
					func.bind(this)();
				}
			});
		} else if (this.options.fieldShowMessage) {
			Event.observe(element, 'mouseover', this.options.fieldShowMessage.bind(element));
		} else if (this.options.fieldShowMessageDirect) {
			this.options.fieldShowMessageDirect.bind(element)();
		}
	},
	
	registerMessage: function(element, message) {
		if (message) {
			if (element.getAttribute('fc_message') && message != 'required') {
				element.message = element.getAttribute('fc_message');
			} else {
				if (this.MESSAGES[this.language - 1][message]) {
					element.message = this.MESSAGES[this.language - 1][message];
				} else {
					element.message = message;
				}
				
				for (var i = 0; i < this.ATTRIBUTES.length; i++) {
					if (element.getAttribute(this.ATTRIBUTES[i])) {
						element.message = element.message.replace('%' + this.ATTRIBUTES[i] + '%', element.getAttribute(this.ATTRIBUTES[i]));
					}
				}
			}
			
			this.hasMessages = true;
		} else {
			element.message = '';
		}
		
		if (this.options.fieldShowMessageDirect) {
			this.options.fieldShowMessageDirect.bind(element)(this.event.type);
		}
	},
	
	check: function(showMessages) {
		if (typeof(showMessages) == 'undefined' || showMessages) {
			this.event = {type: 'blur'};
		} else {
			this.event = {type: 'none'};
		}
		
		this.hasMessages = false;
		this.showMessages = showMessages;
		$A(this.elements).each(this.checkElement.bind(this));
		var el, i = 0;
		while (el = this.elements[i++]) {
			if (el.message) {
				if (this.options.fieldShowMessageDirect) {
					this.options.fieldShowMessageDirect.bind(el)();
				}
				Field.activate(el);
				break;
			}
		}
		if (this.hasMessages) {
			if (showMessages && typeof(showMessages) == 'function') {
				showMessages.bind(this)();
			} else if (showMessages) {
				for (var i = 0; i < this.elements; i++) {
					alert(this.getName(this.elements[i]) + ': ' + this.elements[i].message);
				}
			}
			
			this.showMessages = false;
			return false;
		}
		
		this.showMessages = false;
		return true;
	},
	
	checkElement: function(element) {
		element = $(element);
		if (element.nodeName == 'INPUT' && this.TEXT.indexOf(element.type) == -1) {
			return null;
		}
		
		if (this.isRequired(element) && element.value == '') {
			Element.addClassName(element, 'required');
			this.registerMessage(element, 'required');
			return false;
		}
		
		if (element.value != '') {
			if (this.getMaxLength(element) && this.getMaxLength(element) < element.value.length) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'maxlength');
				return false;
			}
			
			if (this.getMinLength(element) && this.getMinLength(element) > element.value.length) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'minlength');
				return false;
			}
			
			if (this.getMax(element) && this.getMax(element) < parseInt(element.value)) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'max');
				return false;
			}
			
			if (this.getMin(element) && this.getMin(element) > parseInt(element.value)) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'min');
				return false;
			}
			
			if (this.getType(element) && element.value.search(this.TYPES[this.getType(element)]) == -1) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, this.getType(element));
				return false;
			}
			
			if (this.getPattern(element) && element.value.search(this.TYPES[this.getPattern(element)]) == -1) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'unknown');
				return false;
			}
			
			if (this.getDependency(element) && $(this.getDependency(element)).value != element.value) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'dependency');
				return false;
			}
			
			var callback = this.getCallback(element);
			if (callback && callback() == false) {
				Element.addClassName(element, 'required');
				this.registerMessage(element, 'unknown');
				return false;
			}
		}
			
		var ajax = this.getAJAX(element);
		if (ajax) {
			if ((this.showMessages || (this.event && this.event.type == 'blur'))) {
				req = new Ajax.Request(ajax + $F(element), {
					asynchronous: false
				});
				
				var res = req.transport.responseText.split('|');
				if (res[0] != '1') {
					Element.addClassName(element, 'required');
					this.registerMessage(element, res[1]);
					return false;
				}
			} else {
				if (this.event.type == 'none') {
					Element.removeClassName(element, 'required');
					this.registerMessage(element);
				}
				
				return true;
			}
		}
		
		Element.removeClassName(element, 'required');
		this.registerMessage(element);
		return true;
	},
	
	getCallback: function(element) {
		if (element.getAttribute('fc_callback')) {
			var callback = eval('function(){' + element.getAttribute('fc_callback') + '}');
			return callback.bind(element);
		}
		
		return null;
	},
	
	isRequired: function(element) {
		if (element.getAttribute('fc_required') == '1') {
			return true;
		}
		
		return false;
	},
	
	getMaxLength: function(element) {
		if (element.getAttribute('fc_maxlength')) {
			return parseInt(element.getAttribute('fc_maxlength'));
		}
		
		return null;
	},
	
	getMinLength: function(element) {
		if (element.getAttribute('fc_minlength')) {
			return parseInt(element.getAttribute('fc_minlength'));
		}
		
		return null;
	},
	
	getMin: function(element) {
		if (element.getAttribute('fc_min')) {
			return parseInt(element.getAttribute('fc_min'));
		}
		
		return null;
	},
	
	getMax: function(element) {
		if (element.getAttribute('fc_max')) {
			return parseInt(element.getAttribute('fc_max'));
		}
		
		return null;
	},
	
	getType: function(element) {
		if (element.getAttribute('fc_type')) {
			return element.getAttribute('fc_type');
		}
		
		return null;
	},
	
	getPattern: function(element) {
		if (element.getAttribute('fc_pattern')) {
			return element.getAttribute('fc_pattern');
		}
		
		return null;
	},
	
	getDependency: function(element) {
		if (element.getAttribute('fc_dependency')) {
			return element.getAttribute('fc_dependency');
		}
		
		return null;
	},
	
	getName: function(element) {
		if (element.getAttribute('fc_name')) {
			return element.getAttribute('fc_name');
		}
		
		return element.name;
	},
	
	getAJAX: function(element) {
		if (element.getAttribute('fc_ajax')) {
			return element.getAttribute('fc_ajax');
		}
		
		return null;
	}
});

