var _WL_InputField_SEPARATOR = '-';
var _WL_FormValidator_SUFFIX = '-WL_FormValidator';
var _WL_FormValidator_MSG_NO = 'WL_FormValidator-msgNo';
var _WL_FormValidator_MSG = 'WL_FormValidator-msg';
var _WL_FormValidator_ERROR = 'WL_FormValidator-error';

var WL_FormValidator = new Class({

	initialize : function(form, formFunc, fieldFuncs, fieldMsgs) {
		var f = $(form) || $(document.forms[form]);
		f.addEvent('submit', this.validateForm.create({ 'bind' : this }));
		this.form = f;
		this.formFunc = formFunc;
		this.fieldFuncs = {};
		this.fieldMsgs = $defined(fieldMsgs) ? fieldMsgs : {};
		for (n in fieldFuncs) this.enableField(n, fieldFuncs[n]);
	},

	msgId : function(fieldName) {
		return this.form.name + _WL_InputField_SEPARATOR + fieldName + _WL_FormValidator_SUFFIX;
	},

	msgElement : function(fieldName) {
		return $(this.msgId(fieldName));
	},

	enableMsg : function(fieldName, msg) {
		var m = this.msgElement(fieldName);
		if (!$defined(m)) {
			m = new Element('span', { 'id' : this.msgId(fieldName), 'class' : _WL_FormValidator_MSG });
			var f = this.fieldObj(fieldName);
			if ($type(f) == 'element') {
				m.inject($(f), 'after');
			} else {
				for (var k = f.length - 1; k >= 0; k--) {
					if ($type(f[k]) == 'element') {
						var i = $(f[k]);
						var n = i.getNext();
                        m.inject($defined( n) && n.match('label') ? n : i, 'after');
						
						break;
					}
				}
			}
		}
		m.set('text', msg);
		m.removeClass(_WL_FormValidator_MSG_NO);
	},

	disableMsg : function(fieldName) {
		var m = this.msgElement(fieldName);
		if ($defined(m)) {
			m.set('text', '');
			m.addClass(_WL_FormValidator_MSG_NO);
		}
	},

	fieldObj : function(fieldName) {
		return this.form.elements[fieldName] || this.form.elements[fieldName + '[]'];
	},

	fieldElement : function(fieldName) {
		var f = this.fieldObj(fieldName);
		if ($type(f) == 'element') {
			var n = f.getProperty('name');
			if (n.substr(n.length - 2) == '[]') {
				var m = this.form.elements[n.substr(0, n.length - 2) + '-src'];
				if ($type(m) == 'element') return $(m);
			}
			return $(f);
		}
		for (var k = 0; k < f.length; k++) if ($type(f[k]) == 'element') return $(f[k]);
		return null;
	},

	enableField : function(fieldName, func, showMsg) {
		var v = this.validateField.create({ 'arguments' : fieldName, 'bind' : this });
		var f = this.fieldObj(fieldName);
		this.fieldFuncs[fieldName] = func;
		this.fieldMsgs[fieldName] = showMsg;
		this.disableMsg(fieldName);
		if ($type(f) == 'element') { // elemento singolo
			f = $(f);
			f.addEvent('change', v);
		} else { // array di elementi
			for (var k = 0; k < f.length; k++) {
				if ($type(f[k]) == 'element') $(f[k]).addEvent('click', v);
			}
		}
	},

	validateField : function(fieldName) {
		var f = this.fieldObj(fieldName);
		var e = ($type(f) == 'element');
		if (e) f = $(f);
		var v = this.fieldFuncs[fieldName];
		var r = v(f);
		if (r === true) {
			if (e) f.removeClass(_WL_FormValidator_ERROR);
			this.disableMsg(fieldName);
			return true;
		} else {
			if (e) f.addClass(_WL_FormValidator_ERROR);
			var c = this.fieldMsgs[fieldName];
			if ((!$defined(c) || c) && $type(r) == 'string') {
				this.enableMsg(fieldName, r);
			} else {
				this.disableMsg(fieldName);
			}
			return false;
		}
	},

	validateForm : function() {
		var v = true;
		var f = new Array();
		for (n in this.fieldFuncs) {
			if (!this.validateField(n)) {
				v = false;
				f.push(this.fieldElement(n));
			}
		}
		// campi non validi
		if (v == false) {
			alert(_WL_FormValidator_ALERT);
			for (var i = 0; i < f.length && !v; i++) {
				try {
					f[i].focus();
					v = true;
				} catch (e) {}
			}
			return false;
		}
		// verifica se il form è valido
		if ($defined(this.formFunc)) {
			var r = this.formFunc.run([], this.form);
			if (r === true) {
				return true;
			} else {
				var m = ''; // messaggio di errore
				f = undefined; // campo da evidenziare
				switch ($type(r)) {
					case 'string':
						m = r;
						break;
					case 'array':
						for (var k = 0; k < r.length; k++) {
							var i = r[k];
							if ($type(i) == 'string') {
								m += "\n" + i;
							} else if (i.msg) {
								m += "\n" + i.msg;
								if (i.fieldName && !$defined(f)) f = this.fieldElement(i.fieldName);
							}
						}
						if (m) m = m.substr(1);
						break;
					case 'element':
						f = r;
						break;
					case 'object':
						if (r.msg) m = r.msg;
						if (r.fieldName) f = this.fieldElement(r.fieldName);
						break;
				}
				alert(m ? m : _WL_FormValidator_ALERT);
				if ($defined(f)) {
					try { f.focus(); } catch (e) {}
				}
				return false;
			}
		}
	}

});