/* ajax.js 
	(c) Polynorm Software AG ( marcel.tschopp@polynorm.ch )
*/

var FormValidatorField = {
	isRequired: function() {
		return this.getAttribute('fv_required') == '1';
	},
	
	getType: function() {
		return this.getAttribute('fv_type') || null;
	},
	
	getName: function() {
		return this.getAttribute('fv_name') || element.name;
	},
	
	getMaxLength: function() {
		return parseInt(this.getAttribute('fv_maxlength')) || null;
	},
	
	getMinLength: function() {
		return parseInt(this.getAttribute('fv_minlength')) || null;
	},
	
	getMin: function() {
		return parseInt(this.getAttribute('fv_min')) || null;
	},
	
	getMax: function() {
		return parseInt(this.getAttribute('fv_max')) || null;
	},
	
	getMinDate: function() {
		return this.getAttribute('fv_mindate') || null;
	},
	
	getMaxDate: function() {
		return this.getAttribute('fv_maxdate') || null;
	},
	
	getPattern: function() {
		return this.getAttribute('fv_pattern') || null;
	},
	
	getDependency: function() {
		return this.getAttribute('fv_dependency') || null;
	},
	
	getAJAX: function() {
		this.getAttribute('fv_ajax') || null;
	},
	
	getCallback: function() {
		if (this.getAttribute('fv_callback')) {
			try {
				var callback = eval('function(){' + this.getAttribute('fv_callback') + '}');
			} catch (e) {
				return null;
			}
			
			return callback.bind(element);
		}
		
		return null;
	}
};

var FormValidator = Class.create();
Object.extend(FormValidator.prototype, {
	TEXT:       ['text', 'password', ''],
	CHECKBOX:   ['checkbox'],
	RADIO:      ['radio'],
	ATTRIBUTES: ['fv_name', 'fv_maxlength', 'fv_minlength', 'fv_max', 'fv_min'],
	TYPES: {
		/* -, _, \, /, ., ;, :, ,, ?, !, a..z */
		alpha: /^[@-_\\\/\.;:,\?!a-z]*$/i,
		/* -, 0..9 */
		numeric: /^-?[0-9]+$/,
		integer: /^-?[0-9]+$/,
		/* ., ,, 0..9 */
		decimal: /^-?([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[0-2])\.(19|20)?[0-9][0-9]$/
	},
	MESSAGES: [
		/* deutsch */
		{
			required:  'Das Feld "%fv_name%" ist ein Pflichtfeld',
			maxlength: 'Bitte geben Sie maximal %fv_maxlength% Zeichen ein',
			minlength: 'Bitte geben Sie mindestens %fv_minlength% Zeichen ein',
			max:       'Bitte geben Sie eine Zahl ein, die kleiner oder gleich %fv_max% ist',
			min:       'Bitte geben Sie eine Zahl ein, die grösser oder gleich %fv_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',
			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 %fv_name%'
		},
		/* französisch */
		{
			required:  'champ obligatoire',
			maxlength: 'Nombre des lettres maximale: %fv_maxlength%',
			minlength: 'Nombre des lettres en moins: %fv_minlength%',
			max:       'Veuillez entrer un chiffre moins ou &eacute;gale %fv_max%',
			min:       'Veuillez entrer un chiffre plus ou &eacute;gale que %fv_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',
			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 %fv_name%'
		},
		/* englisch */
		{
			required:  'Required Entry',
			maxlength: 'Maximum number of characters: %fv_maxlength%',
			minlength: 'Minimal number of characters: %fv_minlength%',
			max:       'Please enter a number smaller than or equal %fv_max%',
			min:       'Please enter a number bigger than or equal %fv_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',
			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 %fv_name%'
		},
		/* ungarisch */
		{
			required:  'A "%fv_name%" mezo kötelezoen kitöltendo',
			maxlength: 'Kérem, maximálisan %fv_maxlength% karaktert írjon be',
			minlength: 'Kérem, legalább %fv_minlength% karaktert írjon be',
			max:       'Kérem, olyan számot írjon be, amelyik kisebb vagy egyenlo %fv_max%',
			min:       'Kérem, olyan számot írjon be, amelyik nagyobb vagy egyenlo %fv_min%',
			alpha:     'Kérem, hogy csak a következo karaktereket használja fel: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z"',
			numeric:   'Kérem, írjon be egy érvényes egész számot',
			integer:   'Kérem, írjon be egy érvényes egész számot',
			decimal:   'Kérem, írjon be érvényes tizedest',
			alphanum:  'Kérem, hogy csak a következo karaktereket használja fel: "-", "_", "\", "/", ".", ";", ":", ",", "?", "!", "A" bis "z", "0" - "9"',
			email:     'Kérem, írjon be egy érvényes e-mail-címet',
			zip:       'Kérem, írjon be egy érvényes irányítószámot (csak a számjegyeket)',
			phone:     'Kérem, írjon be egy érvényes telefon-/fax-számot (csak számok, meg esetleg egy "+", szóközök nélkül)',
			ip:        'Kérem, írjon be egy érvényes IP-címet',
			date:      'Kérem, írjon be egy érvényes dátumot (nn.hh.éééé)',
			unknown:   'Kérem, ellenorizze a beírtakat',
			dependency:'Kérem, ellenorizze a  %fv_name% mezot'
		}
	],
	
	initialize: function(form) {
		this.form = $(form);
		this.form.fv = this;
		this.elements = [];
		this.invalids = [];
		this.listeners = {};
		
		this.options = Object.extend({
			language: 1,
			validateEvents: ['blur', 'change', 'submit', 'init'],
			showMessageEvents: ['submit'],
			invalidClassName: 'invalid',
			onShowMessage: Prototype.emptyFunction
		}, arguments[1] || {});
		
		$A(this.form.getElementsByTagName('input')).each(this.initInputElement.bind(this));
		$A(this.form.getElementsByTagName('textarea')).each(this.initElement.bind(this));
		
		if (this.options.validateEvents.join(',').indexOf('init') > -1) this.check({type: 'init'});
		Event.observe(window, 'unload', this.destroy.bind(this));
	},
	
	destroy: function() {
		this.form.fv = null;
		this.elements = null;
		this.invalids = null;
		this.listeners = null;
	},
	
	initInputElement: function(element) {
		if (this.TEXT.indexOf(element.type) > -1) this.initElement(element);
	},
	
	initElement: function(element) {
		element = $(element);
		Object.extend(element, FormValidatorField);
		this.elements[this.elements.length] = element;
		var att, i = 0;
		while (att = element.attributes[i++]) {
			if (att.nodeName.indexOf('fv_') == 0) {
				for (var j = 0; j < this.options.validateEvents.length; j++) {
					if (this.options.validateEvents[j] == 'init') continue;
					this.listeners[this.options.validateEvents[j]] = this.checkElement.curry(element).bindAsEventListener(this);
					element.observe(this.options.validateEvents[j], this.listeners[this.options.validateEvents[j]]);
				}
				
				break;
			}
		}
	},
	
	registerMessage: function(element, message, event) {
		if (message) {
			if (event && this.options.showMessageEvents.join(',').indexOf(event.type) > -1) {
				if (element.getAttribute('fv_message') && message != 'required') {
					message = element.getAttribute('fv_message');
				} else {
					if (this.MESSAGES[this.options.language - 1] && this.MESSAGES[this.options.language - 1][message]) {
						message = this.MESSAGES[this.options.language - 1][message];
					} else {
						if (this.MESSAGES[1] && this.MESSAGES[1][message]) {
							message = this.MESSAGES[1][message];
						}
					}
					
					for (var i = 0; i < this.ATTRIBUTES.length; i++) {
						if (element.getAttribute(this.ATTRIBUTES[i])) {
							message = message.replace('%' + this.ATTRIBUTES[i] + '%', element.getAttribute(this.ATTRIBUTES[i]));
						}
					}
				}
				
				this.options.onShowMessage.bind(this)(element, message, event);
			}
			
			this.invalids[this.invalids.length] = element;
			element.addClassName(this.options.invalidClassName);
		} else {
			this.options.onShowMessage.bind(this)(element, '', event);
			element.removeClassName(this.options.invalidClassName);
		}
	},
	
	check: function(event) {
		this.invalids = [];
		$A(this.elements).each(function(element) {
			this.checkElement.bind(this)(element, event || {type: 'submit'});
		}.bind(this));
		
		if (this.invalids.length) {
			this.invalids[0].activate();
			return false;
		}
		
		return true;
	},
	
	checkElement: function(element, event) {
		element = $(element);
		if (element.nodeName == 'INPUT' && this.TEXT.indexOf(element.type) == -1) return null;
		
		if (element.isRequired() && element.value == '') {
			this.registerMessage(element, 'required', event);
			return false;
		}
		
		if (element.value != '') {
			if (element.getMaxLength() && element.getMaxLength() < element.value.length) {
				this.registerMessage(element, 'maxlength', event);
				return false;
			}
			
			if (element.getMinLength() && element.getMinLength() > element.value.length) {
				this.registerMessage(element, 'minlength', event);
				return false;
			}
			
			if (element.getMax() && element.getMax() < parseInt(element.value)) {
				this.registerMessage(element, 'max', event);
				return false;
			}
			
			if (element.getMin() && element.getMin() > parseInt(element.value.replace(/^0+(.+)$/, '\1'))) {
				this.registerMessage(element, 'min', event);
				return false;
			}
			
			if (element.getType() && element.value.search(this.TYPES[element.getType()]) == -1) {
				this.registerMessage(element, element.getType(), event);
				return false;
			}
			
			if (element.getType() == 'date' && element.getMaxDate()) {
				var d = element.value.split('.');
				var md = element.getMaxDate().split('.');
				
				d[0] = d[0].replace(/^0*/, '');
				d[1] = d[1].replace(/^0*/, '');
				d[2] = d[2].replace(/^0*/, '');
				md[0] = md[0].replace(/^0*/, '');
				md[1] = md[1].replace(/^0*/, '');
				md[2] = md[2].replace(/^0*/, '');
				
				if (parseInt(d[2]) < 50) {
					d[2] = 1900 + d[2];
				} else {
					if (parseInt(d[2]) < 100) d[2] = 2000 + d[2];
				}
				
				if (parseInt(md[2]) < 50) {
					md[2] = 1900 + md[2];
				} else {
					if (parseInt(md[2]) < 100) md[2] = 2000 + md[2];
				}
				
				var _d = parseInt(d[0]) + 100 * d[1] + 10000 * d[2];
				var _md = parseInt(md[0]) + 100 * md[1] + 10000 * md[2];
				
				if (_d > _md) {
					this.registerMessage(element, element.getType(), event);
					return false;
				}
			}
			
			if (element.getType() == 'date' && element.getMinDate()) {
				var d = element.value.split('.');
				var md = element.getMinDate().split('.');
				d[0] = d[0].replace(/^0*/, '');
				d[1] = d[1].replace(/^0*/, '');
				d[2] = d[2].replace(/^0*/, '');
				md[0] = md[0].replace(/^0*/, '');
				md[1] = md[1].replace(/^0*/, '');
				md[2] = md[2].replace(/^0*/, '');
				
				if (parseInt(d[2]) < 50) {
					d[2] = 1900 + d[2];
				} else {
					if (parseInt(d[2]) < 100) d[2] = 2000 + d[2];
				}
				
				if (parseInt(md[2]) < 50) {
					md[2] = 1900 + md[2];
				} else {
					if (parseInt(md[2]) < 100) md[2] = 2000 + md[2];
				}
				
				var _d = parseInt(d[0]) + 100 * d[1] + 10000 * d[2];
				var _md = parseInt(md[0]) + 100 * md[1] + 10000 * md[2];
				
				if (_d < _md) {
					this.registerMessage(element, element.getType(), event);
					return false;
				}
			}
			
			if (element.getPattern() && element.value.search(this.TYPES[element.getPattern()]) == -1) {
				this.registerMessage(element, 'unknown', event);
				return false;
			}
			
			if (element.getDependency() && $(element.getDependency()).value != element.value) {
				this.registerMessage(element, 'dependency', event);
				return false;
			}
			
			var callback = element.getCallback();
			if (callback && callback() == false) {
				this.registerMessage(element, 'unknown', event);
				return false;
			}
			
			if (event && this.options.showMessageEvents.join(',').indexOf(event.type) > -1) {
				var ajax = element.getAJAX();
				if (ajax) {
					var request = new Ajax.Request(ajax + $F(element), {
						asynchronous: false
					});
					
					var res = request.transport.responseText.split('|');
					if (res[0] != '1') {
						this.registerMessage(element, res[1], event);
						return false;
					}
				}
			}
		}
		
		this.registerMessage(element, '', event);
		return true;
	}
});