/**
 * 
 * NForm v1.0
 * 
 *	Classe de gestion de la validation des fomulaires
 * 
 */

var Resources = {
	autoCompletion:	'/js/NCompletion.js',
	ajaxForm:		'/js/library/jquery.form.js',
	jqueryCalendar:	'/js/library/jquery.calendar.js',
	sliderComponent:'/js/library/nslider.js'
};
var NConf = {
	datePivot: 50
};
//var noProgress = typeof(NForm.noProgress)!='undefined'? NForm.noProgress: false;
/**	Constructeur de l'objet NForm */
function	NForm(name, msg_div, parent) {

	/** Dans un contexte globale, ( pas new NForm(...) ) on va chercher le formulaire racine nommé */
	if (this==window)
		return (NForm.getForm(name));

	this._elements = [];	//!< liste des éléments du formulaire
	this._name = name;		//!< nom du formulaire
	this._parent = parent;	//!< pointeur vers le formulaire parent (un groupe est un sous objet NForm)

	var form = this;		//!< stockage de la variable this pour la closure

	/** on recupere le pointeur vers la balise <form> dans le cas du formulaire racine, sinon
	 *	on recupere la premiere balise <fieldset> dont className correspond au nom du groupe
	 */
	if (!this._parent) {
		this._form = document.getElementById(name);
		this._form.onsubmit = function() {
			return form.validate(true);
		}
		if (this._form.tagName != 'FORM')
			throw 'tagName is not FORM while constructing NForm('+name+') object: '+this._form;
	}
	else
		this._form = jQuery('fieldset.'+name, this._parent._form)[0];

	/** Vérification de la présence du formulaire (pour le groupe NForm racine) */
	if (!this._form || (this._form.tagName != 'FORM' && this._form.tagName != 'FIELDSET')) {
//		console.warn("Le "+(!this._parent? 'formulaire': 'groupe')+" '"+name+"' n'existe pas dans "+(!this._parent? 'la page': 'le formulaire \''+(this._parent._name)+'\''));
		return ;
	}

	/** On sauvegarde l'objet NForm dans la balise <form> ou <fieldset> */
	this._form._form = this;
	
	/** Dans le cas du groupe racine (donc correspondant à la balise <form>) */
	if (!this._parent) {
			
		jQuery(this._form).ready(function() {						//! Lorsque la page est chargée, initialisation des formulaires
			var forms = document.getElementsByTagName('form');
			for (var i=0; i<forms.length; i++)
				if (forms[i]._form && !forms[i]._inited) {
					forms[i]._inited = true;
					forms[i]._form.Init();
				}

		});
	}
	if (typeof(NForm[name])!='undefined')
		throw "Le formulaire '"+name+"' est déjà défini";
	NForm[name] = this;
}
NForm.noProgress = true;

/** fonction pour recharger dynamiquement le script NForm */
NForm.reload = function() {
	var file = 'NForm.js';
	var scripts = document.getElementsByTagName('script');
	for (var i=0; i<scripts.length; i++) {
		var path = scripts[i].src;
		var pos = path.lastIndexOf('?');
		if (pos>0)
			path = path.substr(0, pos);
		if (path.lastIndexOf(file) == path.length-file.length) {
			alert('reloading NForm: '+scripts[i].src);
			var parent = scripts[i].parentNode;
			var next = scripts[i].nextSibling;
			parent.removeChild(scripts[i]);
			var script = document.createElement('script');
			script.src = path+'?reload='+time();
			if (next)parent.insertBefore(script, next);
			else parent.appendChild(script);
			return ;
		}
	}
};
/**	Fonction d'initialisation des formulaires, la fonction est appelée lorsque la page est chargée (=window.onload) */
NForm.prototype.Init = function() {
	/** évite l'initialisation multiple */
	if (this._inited)
		return ;
	this._inited = true;
	/** Association de l'évènement onblur() sur tous les inputs */
	for (var i=0; i<this._form.length; i++)
		NForm.addCallback(this._form[i], 'onblur', blurinput);
	/** Initialisation de tous les elements du formulaire (NInput et NForm) */
	for (var i in this._elements)
		this._elements[i].Init();
};
NForm.prototype.getAction = function() {
	return (this._form.action);
}
NForm.prototype.setAction = function(action) {
	this._form.action = action;
}
NForm.prototype.getTarget = function() {
	return (this._form.target);
}
NForm.prototype.setTarget = function(target) {
	this._form.target = target;
}
/**	Ajoute un groupe nommé au formulaire */
NForm.prototype.addGroup = function(name) {
	return (this.addElement(new NForm(name, null, this)));
};
/**	Récupère le type de l'element */
NForm.prototype.getType = function() {
	return ('group');
};
/**	Récupère le nom du formulaire (ou du sous groupe) */
NForm.prototype.getName = function() {
	return (this._name);
};
/**	Spécifie le formulaire <form> de l'objet NForm */
NForm.prototype.setForm = function(form) {
	this._form = form;
};
/**	Récupère le groupe parent du groupe en cours */
NForm.prototype.getGroup = function() {
	return (this._parent);
};
/**	Spécifie le groupe parent du formulaire en cours */
NForm.prototype.setGroup = function(parent) {
	this._parent = parent;
};
/**	Calcul le chemin d'un groupe à partir du formulaire racine,
 *	ex: <form id="...">
 * 			my_groupe[my_sub_group][ ... ]
 */
NForm.prototype.getGroupPath = function() {
	var parent = this._parent;
	if (parent && parent._parent) {
		var path = parent.getGroupPath();
		return (path+(path? '['+parent.getName()+']': parent.getName()));
	}
	return ('');
};
/**	Calcul le chemin d'un groupe */
NForm.prototype.getPath = function() {
	var path = this.getGroupPath();
	return (path+(path? '['+this.getName()+']': this.getName()));
};
/**	Ajoute un élément au formulaire,
 * 		assigne le pointeur vers son groupe
 * 		assigne le pointeur vers la balise <form>
 */
NForm.prototype.addElement = NForm.prototype.add = function(element) {
	if (typeof(this._elements[element.getName()]) == 'undefined')
		this._elements[element.getName()] = element;
	element.setGroup(this);
	element.setForm(this._form);
	return (element);
};
/**	Récupère un élément nommé du formulaire dans le groupe courant
 */
NForm.prototype.getElement = NForm.prototype.get = function(name) {
	return (this._elements[name]);
};

/**	Affiche un message lorsque les données d'un input ne sont pas validée
 * 	@input, l'element qui n'est pas valide
 * 	@message, un tableau de messages associé à l'input
 *	@popup, la fonction de callback d'alert (non utilisée)
 */

NForm.appendMessage = function(messages) {
	var t = '';
	for (var i in messages)
		if (typeof(messages[i])=='object' && typeof(messages[i].message)!='undefined')
			t += messages[i].message+"<br />\n";
		else if (typeof(messages[i])=='object')
			t += NForm.appendMessage(messages[i]);
	return (t);
}
NForm.displayMessage = function(errors) {
	(jQuery.alert? jQuery.alert: alert)(typeof(errors)=='string'? errors: NForm.appendMessage(errors));
};
/**	Fonction stub pour ajouter une class à l'objet (inutile dans le cas d'un formulaire) */
NForm.prototype.removeClass = function() {};
/**	Fonction stub pour retirer une class à l'objet (inutile dans le cas d'un formulaire) */
NForm.prototype.appendClass = function() {};

/**	Fonction de validation */
NForm.prototype.validate = function(display_message) {
	var all_errors = {};		//! tableau de tous les messages d'erreurs
	
	this.fireEvent('onPreValidate');		//! Callback de prévalidation
	try {
		/** Dans le cas d'un element NForm, on boucle sur les elements */
		for (var name in this._elements) {
			this._elements[name].removeClass('error');
			var elm_errors = this._elements[name].validate();
			
			if (!this._parent && (typeof(elm_errors) != 'object'/* || typeof(elm_errors.length) != 'number'*/))
				throw "La validation de l'element '"+name+"' a renvoyée un code incorrect ("+typeof(elm_errors)+")";

			if (!empty(elm_errors))
				all_errors[name] = elm_errors;
		}
		/** Si on a un formulaire parent, on lui retourne directement les erreurs rencontrées */
		if (this._parent)							
			return (all_errors);

	}
	catch(e) {
		if (!confirm("Une erreur est survenue lors de la validation du formulaire '"+this._name+"' de cette page\n\n" +
				"voulez vous tout de même poursuivre ?\n\n - raison:\n"+(e.message? e.message: e)))
			return (false);
	}
	/** Si il n'y a aucun message d'erreur, on appelle le callback success puis on retourne true (pour le onsubmit()) */
	if (empty(all_errors)) {
		this.fireEvent('onSuccess', null);
		return (true);
	}
	
	/** Si le formulaire n'a pas été validé, on affiche un message d'erreur ou on retourne les elements/regles en erreur */
	if (display_message)
		NForm.displayMessage(all_errors);
	else
		return (all_errors);
	
	/** On ajoute la class css 'error' pour tous les elements en erreur */
	var elm_errors = [];
	var ret = true;

	for (var name in all_errors) {
		ret = false;
		var elm = this._elements[name];
		elm.appendClass('error');
		elm_errors.push(elm);
	}

	/**  On appelle le callback de gestion d'erreurs en lui passant la liste des NInput en erreur */
	this.fireEvent('onError', elm_errors);
	return (ret);
};

/**	Fonction de remplissage du formulaire à partir d'un tableau associatif
 * 		applique les valeurs des éléments trouvé en appelant les .setValue( ... )
 */
NForm.prototype.fillFromArray = function(arry) {
	for (var i in arry) {
		var elm = this.getElement(i);
		if (!elm)
			continue ;
		//! Si l'élément est un objet NForm, applique les valeurs récursivement
		elm[elm instanceof NForm? 'fillFromArray': 'setValue'](arry[i]);
	}
};

NForm.prototype.clear = function() {
	for (var i in this._elements)
		if (this._elements[i]._elements)
			this._elements[i].clear();
		else
			this._elements[i].setValue('');
};
/**	Retire un listener de la pile de listeners de l'objet
 */
NForm.prototype.removeListener = function(obj) {};

/**	Ajoute un listener à la pile de listeners de l'objet
 */
NForm.prototype.addListener = function(listener) {
	/** Si la pile n'est pas initialisée, on crée le tableau */
	if (typeof(this.listeners)!='object')
		this.listeners = [];
	/** Si le listener existe déjà dans la pile, on skip */
	if (array_search(this.listeners, listener)!=-1)
		return ;
	/** On ajoute le listener à la pile */
	this.listeners.push(listener);

	/** Si l'objet dispose d'une methode 'associateListener'
	 *	On l'appelle pour associer les fonctions listener on... de l'objet
	 */
	if (this.associateListener)
		this.associateListener(listener);
};

/**	Associe les fonction on... déclarée dans un listener à l'objet courant
 */
NForm.prototype._get_dom_elements = function() {
	var items = [];
	if (this._items) {
		for (var i in this._items)
			if (this._form[path+'['+this._items[i]+']'])
				items.push(this._form[path+'['+this._items[i]+']']);
	}
	if (this._elements) {
		for (var i in this._elements) {
			var list = this._elements[i]._get_dom_elements();
			for (var j in list)
				items.push(list[j]);
		}
	}
	var path = this.getPath();
//	console.info('_get_dom_elements for '+this.getName()+' (items: '+this._items+', element: '+this._elements+', path: '+path+', form: '+this.getGroup()._form+')');
	if (this.getGroup() && this.getGroup()._form[path]) {
		var input = this.getGroup()._form[path];
		if (!input.form && input.length && input[0]) {
			for (var i=0; i<input.length; i++)
				items.push(input[i]);
		}
		else if (input.form)
			items.push(input);
	}
	return (items);
}
NForm.allowedDOMEvent = ("blur,focus,load,resize,scroll,unload,click,dblclick," +
		"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + 
		"submit,keydown,keypress,keyup,error").split(",");

NForm.prototype.associateListener = function(listener) {
	var items = this._get_dom_elements();
	for (var name in listener) {
		
		/** Si la propriété est une fonction et que son nom commence par 'on' */
		if (name.indexOf('on')!==0 || typeof(listener[name]) != 'function')
			continue ;
		/** Si le callback est un evenement du DOM */
		if (array_search(NForm.allowedDOMEvent, name.substr(2).toLowerCase())===-1)
			continue ;

		/** On associe la fonction du listener à la fonction native de l'objet */
		for (var i in items)
			NForm.addListener(items[i], name.toLowerCase(), new Function('e', 'this.ninput.fireEvent("'+name+'", e)'));
	}
};

/**	Génération d'un évènement nommé sur les listeners
 * 		@event, nom de l'evenement
 * 		@e, objet Event natif
 * 		@data, parametre de l'evenement
 */
NForm.prototype.fireEvent = function(event, e, data) {
	
	if (!e)e=window.event;
	if (!e)e={};
	if (!e.ninput)
		e.ninput = this;
	if (e && typeof(e.which)!='undefined' && typeof(e.keyCode)=='undefined')e.keyCode=e.which;
	var bak = this[event];
	for (var j in this.listeners)
		if (typeof(this.listeners[j][event]) == 'function') {
			this[event] = this.listeners[j][event];
			this[event](e, this.listeners[j], data);
		}
	this[event] = bak;
	if (typeof(this[event]) == 'function')
		this[event](e, null, data);
	if (this._parent)
		this._parent.fireEvent(event, e, data);
};
/**	Methode toString appelée lorsqu'on print l'objet directement
 * 		(ne fonctionne pas sous IE)
 */
NForm.prototype.toString = function() {
	return ('[object: NForm ('+this.getName()+')]');
};
/**	Retourne la liste des éléments du formulaire NForm
 */
NForm.prototype.getElements = function() {
	return (this._elements);
};
/**	Recherche le/les tags parents/suivant/precedents de l'element en faisant une requete jQuery
 */
NForm.prototype.select = function(rel, jquery) {
	return (jQuery(this._form)[rel](jquery));
};
/**	Flag statique pour désactiver la barre de progression
 */
NForm.noProgress = false;

/**	fonction statique appelée lorsqu'un HtmlElement contenant plusieurs callbacks recoit un evenement
 * 		@obj, l'element recevant l'evenement
 * 		@event, le nom de l'evenement
 * 		@e, l'objet Event natif
 * 		@passthrough, flag pour spécifier si on doit s'arreter au premier callback qui retourne une valeur nulle
 */
NForm.onEvent = function(obj, event, e, passthrough) {
	if (passthrough) {
		NForm.callListener(obj, event, e);
	}
	else {
		for (var i in obj.newEvents[event])
			if (typeof(obj.newEvents[event][i]) == 'function') {
				obj.event = obj.newEvents[event][i];
				var ret = obj.event(e);
				if (!ret && !passthrough)
					return (false);
			}
	}
};

/**	fonction statique appelée lorsqu'un HtmlElement contenant plusieurs callbacks recoit un evenement
 * 		@obj, l'element recevant l'evenement
 * 		@event, le nom de l'evenement
 * 		@e, l'objet Event natif
 */
NForm.callListener = function(obj, event, e) {
	if (typeof(e)=='undefined')
		e = {};
	if (typeof(obj.newListeners) == 'undefined' && typeof(obj[event]) == 'function')
		return (obj[event]());
	if (typeof(obj.newListeners) == 'undefined')
		obj.newListeners = {};
	for (var i in obj.newListeners[event])
		if (typeof(obj.newListeners[event][i]) == 'function') {
			obj.event = obj.newListeners[event][i];
			var ret = obj.event(e);
		}
};
/**	fonction statique pour retirer un listener d'un HtmlElement
 */
NForm.removeListener = function(obj, event, call) {
	if (!obj)
		return (true);
	if (typeof(obj.newListeners) == 'undefined')
		obj[event] = null;
	else if (typeof(obj.newListeners[event]) == 'undefined')
		return ;
	else {
		for (var i=0; i<obj.newListeners[event].length; i++)
			if (obj.newListeners[event][i]) {
				obj.newListeners[event].splice(i, 1);
				break ;
			}
	}
};

/**	fonction statique pour ajouter un listener à un HtmlElement
 * 		les listeners seront executés dans leurs ordre d'ajout jusqu'a ce qu'un listener retourne une valeur nulle
 */
NForm.addListener = function(obj, event, call) {
//	return (jQuery(obj)[event.substr(2)](call));
	if (!obj)
		return (true);
	
	if (typeof(obj[event]) != 'function') {
		obj[event] = call;
		return ;
	}
	if (typeof(obj.newListeners) == 'undefined')
		obj.newListeners = {};
	if (typeof(obj.newListeners[event]) == 'undefined') {
		obj.newListeners[event] = [];
		obj.newListeners[event].push(obj[event]);
		obj[event] = new Function('e', "return (NForm.onEvent(this, '"+event+"', e, true));");
	}
	for (var i in obj.newListeners[event])
		if (obj.newListeners[event][i] == call)
			return (false);
	obj.newListeners[event].push(call);
	return (true);
};

/**	Fonction statique pour ajouter un callback à un HtmlElement,
 *	les listeners seront appelés dans leurs ordres d'ajout quelque soit leur retours
 */
NForm.addCallback = function(obj, event, call) {
	if (!obj)
		return ;
	if (typeof(obj[event]) != 'function') {
		obj[event] = call;
		return ;
	}
	if (typeof(obj.newEvents) == 'undefined')
		obj.newEvents = {};
	if (typeof(obj.newEvents[event]) == 'undefined') {
		obj.newEvents[event] = [];
		obj.newEvents[event].push(obj[event]);
		obj[event] = new Function('e', "return (NForm.onEvent(this, '"+event+"', e));");
	}
	for (var i in obj.newEvents[event])
		if (obj.newEvents[event][i] == call)
			return (false);
	obj.newEvents[event].push(call);
	return (true);
};

/**	Fonction statique pour récupérer un objet NForm nommé dans la page
 */
NForm.getForm = function(name) {
	var form = null;
	if (typeof(name) == 'string')
		form = document.getElementById(name);
	else if (typeof(name) == 'object' && name.tagName == 'FORM')
		form = name;
	else if (typeof(name) == 'object' && name.jquery)
		form = name[0];
	else
		form = null;
	
	if (form && form._form) {
		if (form.tagName != 'FORM' && form.tagName != 'FIELDSET')
			throw "L'objet pointé par l'ID '"+name+"' n'est pas un formulaire";
		return (form._form);
	}
	else if (form) {
		return (new NForm(form.id));
	}
	return (null);
};

/**	Fonction statique appelée lorsqu'on quitte un <input>
 */
function	blurinput() {
	if (typeof(this.helpBox) != 'undefined')
		setTimeout('document.getElementById(\'frm\').'+this.form.name+'.'+this.name+'.helpBox.setMessage()', 200);
};

/**	Affecte un message à la bulle d'aide associée à un element
 */
NForm.setHelp = function(input, message) {
	if (typeof(message) == 'undefined')
		message = '';	
	
	if (typeof(input.helpBox) == 'undefined')
		input.helpBox = new NHelp(input);

	try {
		if (!input)
			throw("invalid input: '"+input+"'\n");
		else if (!message)
			input.helpBox.hideHelp();
		else if (message.indexOf('error:')===0)
			input.helpBox.setMessage(message.substr(6), NHelp.ERROR);
		else if (message.indexOf('warning:')===0)
			input.helpBox.setMessage(message.substr(8), NHelp.WARNING);
		else if (message.indexOf('help:')===0)
			input.helpBox.setMessage(message.substr(5), NHelp.INFO);
		else
			throw("invalid message: '"+message+"'\n");
	}catch(e){console.info('message: '+e.message);}
};

/**	Fonction statique pour lancer la validation d'un element ou d'un formulaire
 * 		@input, objet <input> ou <form> à valider
 */
//NForm.validate = function(input) {
//	if (input && typeof(input.form) == 'undefined' && input.tagName != 'FORM')
//		input = this;
//	if (!input)
//		return ;
//	if (input.tagName=='FORM') {
//		var form = input;
//		var ret = form._form.validate(true);
//			try {
//				if (ret && !input.target && !NForm.noProgress) {
/////					new ProgressWindow();
//				}
//			}catch(e){}
//		return (ret);
//	}
//	return (input.form._form.validate(input));
//};

/**	Fonction de callback associé à un onkeypress pour limitée la saisie à des chiffres
 * 		@e, objet Event natif
 */
NForm.limitNumericKeyPress = function(e) {

	e = e? e: window.event;
	k = e.keyCode? e.keyCode: e.which;
	if (k >= 112 && k <= 123)		//! F1 => F12
		e.returnValue = true;
	else if (k >= 37 && k <= 40)	//! UP, DOWN, LEFT, RIGHT
		e.returnValue = true;
	else if (k == 13 || k == 27)	//! ENTER, ESC
		e.returnValue = true;
	else if (k >= 48 && k <= 57 || k >= 96 && k <= 105)		//! 0 => 9 || numpad 0 => 9
		e.returnValue = true;
	else if (this.value.indexOf('.') == -1 && (k == 110 || k == 190 || k == 188))
		e.returnValue = true;
	else if (k <= 46)
		e.returnValue = true;
	else
		e.returnValue = false;

//	console.info("keypress: "+k+" ... ("+(e.returnValue? 'OK': 'rejected')+")");
	return (e.returnValue);
};

/**	Fonction pour soumettre un formulaire (appelle la fonction onsubmit() de validation du formulaire)
 * 		@the_form, le nom ou l'objet NForm à soumettre
 */
NForm.submit = function(the_form) {
/*	if (typeof(the_form) == 'string')
		the_form = document.getElementById(the_form);
	if (typeof(the_form) != 'object' || the_form.constructor != NForm)
		throw 'Le formulaire spécifié n\'existe pas dans la page';*/
//	alert(the_form.onsubmit);
	var the_form = NForm.getForm(the_form);
	the_form.submit();
};

NForm.prototype.submit = function() {
	if (typeof(this._form.onsubmit)=='function') {
		if (this._form.onsubmit())
			this._form.submit();
	}
	else
		this._form.submit();
}

/**	Récupère les NElements contenur dans une balise
 * 		@id, identifiant unique ou element parent des elements à trouver
 */
NForm.prototype.getElementsById = function(id) {
	var node = typeof(id)=='string'? document.getElementById(id): id;
	var results = [];
	for (var i in this._elements) {
		if (this._elements[i]._elements) {
			var sub = this._elements[i].getElementsById(node);
			for (var j=0; j<sub.length; j++)
				results.push(sub[j]);
		}
		else if (NForm.isChildOf(this._elements[i], node)) {
			results.push(this._elements[i]);
		}
	}
	return (results);
};
NForm.prototype.selectParent = function(jquery) {
	return (this.select( 'parents', jquery));
/*	var path = this.getPath();
	var input = typeof(this._items)=='object'? this._form[path+'['+this._items[0]+']']: this._form[path];
	return (jQuery(input).parents(jquery));*/
};
NForm.prototype.select = function(rel, jquery) {
	if (typeof(jquery)=='undefined')
		return (jQuery(rel, this._form));
	return (jQuery(this._form)[rel](jquery));
};

/**	Vérifie si un element est fils du parent donné
 * 		@child, l'element fils à vérifier
 * 		@parent, le parent suspect de l'element fils
 */
NForm.isChildOf = function(child, parent) {


	var path = child.getPath();
	if (typeof(child._items) == 'object') {
		for (var i=0; i<child._items.length; i++) {
			for (var top = child._form[path+'['+child._items[i]+']']; top; top=top.parentNode) {
				if (top==parent)
					return (true);
			}
		}

	}
	else {
		for (var top=child._form[path]; top; top=top.parentNode) {
			if (top==parent)
				return (true);
		}
	}
	return (false);
};



/**	extension de NForm pour traiter les appels asynchrones
 * 		- charge le module 'jquery.form.js' si pas chargé
 * 		- charge le module 'jquery.jqmodal.js' si pas chargé
 * 		- soumet le formulaire via une XHR et récupère les messages pour les afficher dans une <div> modale
 */
NForm.ajaxSubmitWaiting = [];
NForm.prototype.ajaxSubmit = function(obj) {

	
	obj._form = this;
	
	if (jQuery(this._form).ajaxSubmit) {
		/** construction de l'objet de requete */
		if (typeof(obj) == 'function')
			obj = {success: obj};
		else if (typeof(obj) == 'undefined')
			obj = {};
		/** Execute the beforeSubmit hook */
		if (obj.preValidate && !obj.preValidate(obj._form))
			return (false);
		/** Execute the onsubmit validation hook */
		if ( this._form.onsubmit && ! this._form.onsubmit() ) {
			if (typeof(obj.error)!='undefined')
				obj.error();
			return (false);
		}

		/** si plugin chargé, soumettre le formulaire avec une XHR via ajaxSubmit */
		/** si une URL de remplacement a été fournie
		 * 	on gère les url absolue (http://.../path/to/file et /path/to/file) et relative (to/file?param=42)
		 */

		var url = this._form.action;
		var split = url.indexOf('?');
		var get = split!=-1? url.substr(split+1).split('&'): [];
		var params = {};
		var url = split!=-1? url.substr(0, split): url;

		for (var i in get) {
			var pair = get[i].split('=');
			var name = pair[0];
			var value = pair.length==2? pair[1]: '';
			params[name] = value;
		}

		if (obj.url) {
			
			var split = obj.url.indexOf('?');
			var get = split!=-1? obj.url.substr(split+1).split('&'): [];
			obj.url = split!=-1? obj.url.substr(0, split): obj.url;
			for (var i in get) {
				var pair = get[i].split('=');
				var name = pair[0];
				var value = pair.length==2? pair[1]: '';
				params[name] = value;
			}
			if (obj.url.indexOf('://')!=-1)		// absolute host and path
				url = obj.url;
			else if (obj.url.charAt(0) == '/')	// absolute path on the current host
				url = hosturl(url)+obj.url;
			else if (obj.url)					// relative path to the current directory
				url = dirname(url)+'/'+obj.url;
		}
		params.json='';
		var get = '';
		for (var i in params)
			get += (get? '&':'')+i+(params[i]? '='+escape(params[i]): '');
		obj.url = url+'?'+get;
		
		/** filtre pour soumettre un groupe (sous formulaire) (!!! experimental !!!) */
		var filterPath = this.getPath();
		obj.beforeSubmit = function(fields) {
			for (var i=0; i<fields.lengh; )
				if (fields[i].name.indexOf(filterPath)===0)
					i++;
				else
					fields.splice(i, 1);
		};
		obj.dataType = 'json';
		var oldSuccess = obj.success;
		obj.success = function(json) {
			json = json[0];
			if (json.error)
				NForm.displayMessage(json.error, true);
			if ( json.response === true ) {
				if (this.postValidate && !this.postValidate(this))
					return ;
				if (oldSuccess)
					oldSuccess.apply(this, [json]);
			}
			else {
				if (typeof(json.response) == 'object')
					NForm.displayMessage(json.response, true);
				if (this.error)
					this.error(json);
			}
		};
		return (jQuery(this._form).ajaxSubmit(obj));
	}
	else {
		/** si le plugin jquery.form.js n'est pas chargé
		 * 	on stack la demande de soumission du formulaire en cours
		 *	et on lance une requete de chargement du script
		 */
		NForm.ajaxSubmitWaiting.push(obj);
		if (!NForm.ajaxSubmitLoading) {
			NForm.ajaxSubmitLoading = true;
			jQuery.ajax({
				url: Resources.ajaxForm,
				dataType: 'script',
				cache: false,
				error: function() {
					/** Si le script n'a pu être chargé, on appelle les callbacks
					 *	d'erreur sur tous les formulaires en attente */
					for (var i in NForm.ajaxSubmitWaiting)
						NForm.ajaxSubmitWaiting[i].error();
					NForm.ajaxSubmitWaiting = [];
					throw 'Unable to load '+this.url;
				},
				success: function() {
					/** Si le script a été chargé, on rappelle la fonction d'ajaxSubmit
					 *	sur tous les formulaires en attente qui va directement utilisé
					 *	le plugin puisque celui ci est chargé
					 */
					for (var i in NForm.ajaxSubmitWaiting)
						NForm.ajaxSubmitWaiting[i]._form.ajaxSubmit(NForm.ajaxSubmitWaiting[i]);
					NForm.ajaxSubmitWaiting = [];
				}
			});
		}
		return (null);
	}
};





/******************************************************************************************************************/
/**	Elements abstrait NInput ...
 *		
 * 	
 * 
 */
function	NInput() {};
NInput.prototype.className = 'input';
/**	Récupère le type de l'objet */
NInput.prototype.getType = function() {
	return (this.className);
};
/**	Méthode toString appelée pour printer l'objet */
NInput.prototype.toString = function(){
	return('[object: NForm.N'+this.className.charAt(0).toUpperCase()+this.className.substr(1)+' ('+this.getName()+')]');
};
/**	Récupère le nom d'un objet */
NInput.prototype.getName = function() {
	return (this._name);
};
/**	Spécifie le fomulaire de l'element */
NInput.prototype.setForm = function(form) {
	this._form = form;
};
/**	Récupère le formulaire de l'element */
NInput.prototype.getForm = function() {
	return (this._form);
};
/**	Spécifie le groupe parent de l'element */
NInput.prototype.setGroup = function(parent) {
	this._parent = parent;
};
/**	Récupère le groupe parent de l'element */
NInput.prototype.getGroup = function() {
	return (this._parent);
};
/**	Recherche le/les tags parents de l'element en faisant une requete jQuery */
NInput.prototype.selectParent = NForm.prototype.selectParent;
/**	Recherche le/les tags parents de l'element en faisant une requete jQuery */
NInput.prototype.select = function(rel, jquery) {
	var path = this.getPath();
	var input = typeof(this._items)=='object'? this._form[path+'['+this._items[0]+']']: this._form[path];
	return (jQuery(input)[rel](jquery));
};
/**	Recherche le/les tags fils de l'element en faisant une requete jQuery */
NInput.prototype.selectChild = function(jquery) {
	var path = this.getPath();
	var input = typeof(this._items)=='object'? this._form[path+'['+this._items[0]+']']: this._form[path];
	return (jQuery(jquery, input));
};
/**	Fonction statique qui vérifie que l'element passé en parametre est bien un <input type=radio> ou une liste de radio */
NInput.isRadio = function(input) {
	return ((input && input.tagName && input.tagName == 'INPUT' && input.type == 'radio') ||
			(!input.tagName && input.length && input[0].tagName == 'INPUT' && input[0].type == 'radio'));
};
/**	Vérifie la consistance d'un NElement, boucle sur les objets multi elements (rib, date, secu) */
NInput.prototype.checkConsistency = function() {
	
	var path = this.getPath();
	if (typeof(this._items) == 'object') {
		for (var i in this._items)
			if (typeof(this._form[path+'['+this._items[i]+']']) != 'undefined') {
				var input = this._form[path+'['+this._items[i]+']'];
				if (!NInput.isRadio(input) && !input.tagName)
					throw 'L\'element '+this.getName()+' n\'est pas unique dans la page: '+input+'';
			}
	}
	else if (typeof(this._form[path]) != 'undefined') {
		var input = this._form[path];
		if (!NInput.isRadio(input) && !input.tagName)
			throw 'L\'element '+this.getName()+' n\'est pas unique dans la page: '+input+'';
	}
};
/**	Associe les callbacks à l'<input> natif */
NInput.prototype.Init = function() {
	this.checkConsistency();
	var items = this._get_dom_elements();
	for (var i in items)
		items[i].ninput = this;
};

/**	Réupère le message d'erreur par default d'un element */
NInput.prototype.getErrorMessage = function() {
	return ('La valeur de '+this.getName()+' n\'est pas valide');
};
/**	Retire un listener de la pile de listeners associé à l'element */
NInput.prototype.removeListener = NForm.prototype.removeListener;
/**	Ajoute un listener de la pile de listeners associé à l'element */
NInput.prototype.addListener = NForm.prototype.addListener;
/**	Associe les fonctions callbacks d'un listener à l'objet */
NInput.prototype.associateListener = NForm.prototype.associateListener;
/**	Appelle les fonction callbacks des listeners d'un objet */
NInput.prototype.fireEvent = NForm.prototype.fireEvent;
NInput.prototype._get_dom_elements = NForm.prototype._get_dom_elements;
/**	Vérifie qu'un objet existe, boucle pour les objets multi-elements */
NInput.prototype.exists = function() {
	var path = this.getPath();
	if (typeof(this._items) == 'object') {					//! Si l'objet contient plusieurs elements (date, rib ...)
		for (var i in this._items) {
			if (typeof(this._form[path+'['+this._items[i]+']']) == 'undefined') {
//				alert('field '+this.getPath()+' does not exists in '+this.getForm()+': '+(path+'['+this._items[i]+']'));
				return (false);
			}
		}
	}
	else if (typeof(this._form[path]) == 'undefined')		//! Si l'objet ne possède qu'un seul element
		return (false);
	return (true);
};
/**	Récupère le chemin complet d'un element
 * 		ex: my_group[my_sub_group][my_element_name]
 */
NInput.prototype.getPath = function() {
	if (this._parent && this._parent._parent) {
		var path = this._parent.getGroupPath();
		path += (path? '['+this._parent.getName()+']': this._parent.getName());
	}
	else
		var path = '';
	return (path+(path? '['+this.getName()+']': this.getName()));
};
NInput.prototype.forceValidate = function(bol) {
	this._force = bol? true: false;
	return (this);
}
/**	Methode de validation d'un element */
NInput.prototype.validate = function() {
	if (!this.exists()) {									//! Vérifie que l'element existe dans la page
		return ([]);
	}
	if (!this._force && this.isDisabled()) {				//! Vérifie que l'element ne soit pas désactivé
		return ([]);
	}
	if (!this._rules.required && !this.getValue()) {		//! Vérifie, si la valeur n'est pas requise et que l'element ne possède pas de valeur. dans ce cas on skip
		return ([]);
	}
	else if (this._rules.required && !this.getValue()) {	//! Vérifie, si l'element n'a pas de valeur et qu'il est requis
		return ([{rule: 'required', message: (!this._rules.required.message? 'Le champ '+this.getName()+' n\'est pas conforme'+(typeof(_debug)!='undefined'? ' (règle \'required\' non satisfaite)': ''): this._rules.required.message)}]);
	}
	if (typeof(this.check) == 'function' && this.getValue() && !this.check()) {		//! Si l'objet dispose d'une methode de validation, on l'appelle
		if (typeof(this._rules[this.className])!='undefined')
			return ([{rule: 'check', message: this._rules[this.className].rule}]);
		else if (typeof(this._rules['default'])!='undefined')
			return ([{rule: 'check', message: this._rules['default'].rule}]);
		else
			return ([{rule: 'check', message: this.getErrorMessage()}]);
	}
	var errors = [];
	for (var j in this._rules) {
		/** On boucle sur les règles de validations */
		
		/** On saute les regles désactivées */
		if (this._rules[j].disabled)
			continue ;

		var rulename = this._rules[j].rule;
		if (typeof(NValidate[rulename]) != 'function')
			throw "La règle de validation '"+rulename+"' n\'est pas définie";

		/** Appel de la règle de validation */
		if (!NValidate[rulename](this, this._rules[j].options)) {		//! Si la règle de validation n'est pas satisfaite ...
			/** Si on a pas de message, on en génère un */
			if (!this._rules[j].message) {
				var str = 'Le champ '+this.getName()+' n\'est pas conforme';
				if (typeof(_debug)!='undefined')
					str += '\n => (règle \''+rulename+'\' non satisfaite'+(this._rules[j].options? ', options: \''+this._rules[j].options+'\'': '')+')';
				errors.push({rule: rulename, message: str});
			}
			else
				errors.push({rule: rulename, message: this._rules[j].message});
//			{
//				console.info('error: ');
//				console.dir(elm_errors);
//			}
				
			break ;
		}
	}
	/** On retourne le tableau des messages d'erreurs (vide si pas d'erreurs) */
	return (errors);
};

/**	Vérifie qu'un champs soit désactivé */
NInput.prototype.isDisabled = function() {
	var path = this.getPath();
	if (typeof(this._items) == 'object') {
		for (var i in this._items)
			if (typeof(this._form[path+'['+this._items[i]+']']) == 'undefined' || this._form[path+'['+this._items[i]+']'].disabled)
				return (true);
	}
	else if (typeof(this._form[path]) == 'undefined' || this._form[path].disabled)
		return (true);
	return (false);
};

/**	Récupère la valeur de l'element */
NInput.prototype.getValue = function() {
	if (!this.exists())						//! Si l'element n'existe pas dans la page, sa valeur est une chaine vide
		return ('');
	var path = this.getPath();
	if (typeof(this._items) == 'object') {	//! Si le NElement est composé de plusieurs elements
		var tab = [];
		var isEmpty = true;
		for (var i in this._items)
			if (this._form[path+'['+this._items[i]+']'].value)
				isEmpty = false;
		if (!isEmpty) {
			for (var i in this._items)
				tab.push(this._form[path+'['+this._items[i]+']'].value);
			return (tab.join('-'));			//! On retourne les valeurs de chaque element, dans l'ordre, séparé par des '-'
		}
	}
	else if (this._form && this._form[path])//! Si le NElement est composé d'un seul element, on retourne sa valeur
		return (this._form[path].value);
	return ('');
};
/**	Applique la valeur à l'element */
NInput.prototype.setValue = function(value) {
	var path = this.getPath();
	if (!this.exists() || value === null)	//! Si l'element n'existe pas et que la valeur à mettre est nulle, on skip
		return ;
	if (typeof(this._items) == 'object') {	//! Si le NElement est composé de plusieurs elements
		var tab = value.split('-');
		for (var i in this._items)
			this._form[path+'['+this._items[i]+']'].value = typeof(tab[i])!='undefined'? tab[i]: '';//! On applique les valeurs de chaque element, dans l'ordre, séparé par des '-'
	}
	else if (this._form && this._form[path])//! Si le NElement est composé d'un seul element, on applique sa valeur
		this._form[path].value = value;
	//alert('NInput' + this._name + 'onChange');
	
	this.fireEvent('onChange');
};
/**	Retire une règle de la pile de règle de l'element */
NInput.prototype.removeRule = function(rulename) {
	this.removeClass(rulename);		//! On retire la règle nommé des class de l'element
	delete (this._rules[rulename]);	//! On retire la règle de la pile
	if (rulename == 'required')
		NInput.toggleEtoile(this, false);
};
NInput.toggleEtoile = function(ninput, required) {
	jQuery('img.NStar', ninput.select('parents', '.item')).each(function() {
		var img_required = jQuery(this);
		var search,replace;
		if (required) {
			search = "etoile_none.gif";
			replace = "etoile.gif";
		}
		else {
			replace = "etoile_none.gif";
			search = "etoile.gif";
		}
		img_required.attr("src",img_required.attr("src").replace(search, replace));
		img_required.attr("alt","facultatif");
	});
}
NInput.prototype.disableRule = function(rulename) {
	if (this._rules[rulename]) {
		this._rules[rulename].disabled = true;
		if (rulename == 'required')
			NInput.toggleEtoile(this, false);
	}
};
NInput.prototype.enableRule = function(rulename) {
	if (this._rules[rulename]) {
		this._rules[rulename].disabled = null;
		if (rulename == 'required')
			NInput.toggleEtoile(this, true);
	}
};
/**	Ajoute une règle de validation à l'element */
NInput.prototype.addRule = function(obj, options) {
	if (typeof(obj)=='string') {		//! Accepte le nom d'une règle à la place d'un objet {rule: 'required', message: ' ... ... '}
		obj = {rule: obj};
		if (typeof(options)!='undefined')	//! Accepte le parametre en second argument
			obj.options = options;
	}
	var path = this.getPath();
	this._rules[obj.rule] = obj;
	if (obj.rule == 'numeric' && this._form && this._form[path])		//! Si la règle est 'numeric', on associe 'limitNumericKeyPress' au onkeydown
		jQuery(this._form[path]).keydown(NForm.limitNumericKeyPress);
	if (obj.rule == 'required')
		NInput.toggleEtoile(this, true);
	this.appendClass(obj.rule);		//! On ajoute la règle nommé aux class de l'element
	return (this);
};
NInput.prototype.getRules = function() {
	return (this._rules);
}
/**	Ajoute une class à l'element */
NInput.prototype.appendClass = function(className) {
	if (!this.exists())						//! Si l'element n'existe pas dans la page
		return ;
	var path = this.getPath();
	if (typeof(this._items) == 'object')	//! Si le NElement est composé de plusieurs elements
		for (var i in this._items)
			jQuery(this._form[path+'['+this._items[i]+']']).addClass(className);
	else
		jQuery(this._form[path]).addClass(className);//! Si le NElement est composé d'un seul element
};
/**	Retire une class à l'element */
NInput.prototype.removeClass = function(className) {
	if (!this.exists())						//! Si l'element n'existe pas dans la page
		return ;
	var path = this.getPath();
	if (typeof(this._items) == 'object') {	//! Si le NElement est composé de plusieurs elements
		for (var i in this._items)
			jQuery(this._form[path+'['+this._items[i]+']']).removeClass(className);
	}
	else
		jQuery(this._form[path]).removeClass(className);//! Si le NElement est composé d'un seul element
};
/**	Active un element */
NInput.prototype.enable = function() {
	if (!this.exists())						//! Si l'element n'existe pas dans la page
		return ;
	var path = this.getPath();
	if (typeof(this._items) == 'object') {	//! Si le NElement est composé de plusieurs elements
		for (var i in this._items)
			this._form[path+'['+this._items[i]+']'].disabled = false;
	}
	else
		this._form[path].disabled = false;	//! Si le NElement est composé d'un seul element
	return (this);
};
/**	Désactive un element */
NInput.prototype.disable = function() {
	if (!this.exists())
		return ;
	var path = this.getPath();
	if (typeof(this._items) == 'object') {	//! Si le NElement est composé de plusieurs elements
		for (var i in this._items)
			this._form[path+'['+this._items[i]+']'].disabled = true;
	}
	else
		this._form[path].disabled = true;	//! Si le NElement est composé d'un seul element
	return (this);
};

/***************************************************************************************************************************/
/**	Implementation des Elements ...
 * 
 * 	
 * 
 */
 
/**	NText */
function	NText(name, options) {
	this._name = name;
	this._options = options;
	this._rules = [];
	this._form = null;
	this._locked = false;
};
/** Heritage de NInput */
NText.prototype = new NInput();
/**	Nommage de la classe */
NText.prototype.className = 'text';
NText._completion_loading = false;

/**	Association des callbacks */
NText.sliderWaiting = [];
NText.prototype.Init = function() {
	if (!this.exists())
		return ;
	NInput.prototype.Init.call(this);
	var input = this._form[this.getPath()];
	jQuery(input).keydown(function(e) {
		if (this.ninput._locked)
			return (false);
	});
	
	/** traitement des options de rendering */
	/** Champ sans auto-completion */
	if (this._options && this._options.autocomplete) {
		input.setAttribute('autocomplete', this._options.autocomplete);
	}
	/** Champ avec auto-completion ajax */
	if (this._options && this._options.ajaxcomplete) {
		input.setAttribute('ajaxcomplete', this._options.ajaxcomplete);
		input.setAttribute('autocomplete', 'off');
		if (!NText._completion_loading && typeof(NCompletion) == 'undefined') {
			NText._completion_loading = true;
			jQuery.getScript(Resources.autoCompletion);
		}
	}
	/** Champ Slider */
	if (this._options && this._options.render == 'slider' && jQuery.iSlider) {


		if (!NText.sliderLoading) {
			NText.sliderLoading = true;
			NText.sliderWaiting.push(this);
			jQuery.ajax({
				url: Resources.sliderComponent,
				dataType: 'script',
				error: function() {
					throw 'Unable to load '+this.url;
				},
				success: function() {
					for (var i in NText.sliderWaiting)
						NText.sliderWaiting[i].initSlider();
					NText.sliderWaiting = [];
				}
			});
		}
		else if (jQuery(this._nslider).Slider)
			this.initSlider();


	}
};
NText.prototype.lock = function() {
	this._locked = true;
	if (this._nslider)
		jQuery(this._nslider).SliderLock();
}
NText.prototype.unlock = function() {
	this._locked = false;
	if (this._nslider)
		jQuery(this._nslider).SliderUnlock();
}
NText.prototype.initSlider = function() {
	var input = this._form[this.getPath()];
	/**	Create the Slider parameters */
	var obj = {
		accept: '.Mover',
		opacity: 0.8,
		onSlide: function(cordx, cordy, x, y) {
			
			if (this.clientWidth && this.parentNode._ninput._sliderbutton_width != this.clientWidth)
				this.parentNode._ninput._sliderbutton_width = this.clientWidth;

			var value = this.parentNode._ninput.slider_to_value(x);
			if (typeof(this.parentNode._ninput._options.precision) != 'undefined') {
				var pow = Math.pow(10, this.parentNode._ninput._options.precision);
				value = Math.round(pow*value)/pow;
			}
			if (this.parentNode._ninput._locked)
				return ;
			if (this.parentNode._ninput._inited)
				this.parentNode._ninput._form[this.parentNode._ninput.getPath()].value = value;
			this.parentNode._ninput.fireEvent('onChange');
		}
	};
	/**	Implement fractions */
	if (this._options.fractions)
		obj.fractions = this._options.fractions;

	/**	go get the .Slider within the cage */
	var cage = jQuery(input).prev('div')[0];
	var slider = jQuery('.Slider', cage)[0];

	/** Add the + and - buttons dynamically	 */
	if (this._options.buttons == 'plusminus') {
		var div = cage.parentNode.insertBefore(dc('div'), cage.nextSibling);
		div.className = 'buttons_precision';
		var plus = div.appendChild(dc('a'));
		plus.className = 'plus';
		var minus = div.appendChild(dc('a'));
		minus.className = 'minus';
		plus._ninput = minus._ninput = this;
		
		plus.onclick = function() {
			if (this._ninput._locked)
				return (false);
			this._ninput.setValue(parseFloat(this._ninput.getValue()) + 0.01); 
			return false;
		};
		minus.onclick = function() {
			if (this._ninput._locked)
				return (false);
			this._ninput.setValue(parseFloat(this._ninput.getValue()) - 0.01); 
			return false;
		};
	}

	if (!slider)
		throw "Cannot find Slider bar for element '"+this.getName()+"'";
	this._nslider = slider;
	this._nslider._ninput = this;

	/** Override the cage padding (javascript cannot retreive border or margin while it's set in css) */
	cage.style.padding = 0;

	/** Run the Slider */
	if (jQuery(this._nslider).Slider)
		jQuery(this._nslider).Slider(obj);

	/** Apply the value once loaded */
	if (input && ''+parseFloat(input.value) != ''+NaN)
		this.setValue(parseFloat(input.value));
	input._ninput = this;
	jQuery(input).change(NText._updateSlider).keyup(NText._updateSlider);
	
	this._inited = true;
};
NText._updateSlider = function() {
//	console.info('hey hey: '+this.value+' ('+this._ninput+')');
//	console.info('this._ninput: '+this._ninput);
//	console.info('this.parentNode: '+this.parentNode);
//	console.info('this.parentNode._ninput: '+this.parentNode._ninput);
//	if (this._ninput)
//		this._ninput._updateSlider(this.value);
}
NText.prototype._updateSlider = function(value) {
	if (value.charAt(0) == '.' || value.charAt(value.length-1) == '.') {
		
	}
	else if (value !== '') {
		value = parseFloat(value);
//		console.info('show if '+parseFloat(this.getValue())+' / '+value);
		if (parseFloat(this.getValue()) !== value)
			this.setValue(parseFloat(value));
	}
	
}
/**	Calcul la valeur de la case en fonction de l'emplacement du slider
 */
NText.prototype.slider_to_value = function(x) {
	var min = this._rules.minvalue.options;
	var max = this._rules.maxvalue.options;
	var width = this._nslider.clientWidth - (this._sliderbutton_width || 0);
	var value = ((x * (max-min)) / width)+min;
	return (value);
};
/**	Calcul la position du slider en fonction de la valeur de la case
 */
NText.prototype.value_to_slider = function(value) {
	var max = this._rules.maxvalue.options;
	var min = this._rules.minvalue.options;
	var width = this._nslider.clientWidth - (this._sliderbutton_width || 0);
	var x = (value-min)*(width)/(max-min);
	return (x);	
};
NText.prototype.set_slider_value = function(value) {
	var path = this.getPath();
	var input = this._form[path];
	var cage = jQuery(input).parents('div.slide_couple').children('div.cage')[0];

	var displayed = cage.clientWidth!=0;
	if (!displayed) {
		var parent = cage.parentNode;
		var next = cage.nextSibling;
		document.body.appendChild(cage);
	}
	var offset = this.value_to_slider(value);
	var olds = jQuery(this._nslider).SliderGetValues();
	var newoffset = offset - olds[0][0][2];
//	console.info('setting value: '+value+', old: '+olds[0][0][2]+', offset: '+offset+', new: '+newoffset+', (tovalue: '+this.value_to_slider(offset)+')');
	jQuery(this._nslider).SliderSetValues([[newoffset]]);
	if (!displayed) {
		if (!next)	parent.appendChild(cage);
		else		parent.insertBefore(cage, next);
	}
}
/**	Change la valeur du champ
 */
NText.prototype.setValue = function(value) {
	var path = this.getPath();
	if (!this.exists() || value === null)
		return ;

	if (this._nslider) {
		this.set_slider_value(value);
		this._form[path].value = value;
	}
	else {
		this._form[path].value = value;
	}
	if (!this._locked)
		this.fireEvent('onChange');
};


/*******************************************************************************************************************/

function	NPassword(name, options) {
	this._name = name;
	this._options = options;
	this._rules = [];
	this._form = null;
};
/** Heritage de NText */
NPassword.prototype = new NText();
/**	Nommage de la classe */
NPassword.prototype.className = 'password';

/**	NHidden
 */
function	NHidden(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
};
/**	Heritage de NInput 
 */
NHidden.prototype = new NInput();
/**	Nommage de la classe
 */
NHidden.prototype.className = 'hidden';


/**	NRadio
 */
function	NRadio(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
};
/**	Heritage de NInput 
 */
NRadio.prototype = new NInput;
/**	Nommage de la classe
 */
NRadio.prototype.className = 'radio';
/**	Recupere la valeur du champ
 */
NRadio.prototype.getValue = function() {
	return (NRadio.getValue(this._form[this.getPath()]));
//	return (jQuery(this._form[this.getPath()]).val());
//	var els=this._form[this.getPath()];
//	for(var i=0;i<els.length;i++)
//		if(els[i].checked||els[i].selected)
//			return(els[i].value);
//	return (null);
};
/**	Change la valeur du champ
 */
NRadio.prototype.setValue = function(value) {
	var els=this._form[this.getPath()];
	for(var i=0;i<els.length;i++)
		if(els[i].value == value)
			els[i].checked = true;
			
	this.fireEvent('onChange');
	
	return (null);
};
/**	Recupere la valeur du champ passé en parametre
 */
NRadio.getValue = function(itm) {
//	return (jQuery(itm).val());
	if (!itm.form && itm.length && itm[0].form)
		itm = itm[0];
	var els = itm.form[itm.name];
	if (els.tagName)
		els=[els];
	for(var i=0;i<els.length;i++)
		if(els[i].checked||els[i].selected) {
//			console.info('found: NRadio().getValue: '+els[i].value);
			return(els[i].value);
		}
//	console.info('not found: NRadio().getValue: null');
	return (null);
};
/**	Change la valeur du champ passé en parametre
 */
NRadio.setValue = function(itm, value) {
	var els = itm.tagName && itm.tagName == 'RADIO'? itm.form[itm.name]: itm;
	for(var i=0;i<els.length;i++)
		if (els[i].value == value)
			els[i].checked = true;
};



/**	NCheckbox
 */
function	NCheckbox(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
};
/**	Heritage de NInput 
 */
NCheckbox.prototype = new NInput;
/**	Nommage de la classe
 */
NCheckbox.prototype.className = 'checkbox';
/**	Recupere la valeur du champ
 */
NCheckbox.prototype.getValue = function() {
	var itm=this._form[this.getPath()];
	return (itm.checked);
/*	var els=this._form[this.getPath()];
	for(var i=0;i<els.length;i++)
		if(els[i].checked||els[i].selected)
			return(els[i].value);
	return (null);*/
};
/**	Change la valeur du champ passé
 */
NCheckbox.prototype.setValue = function(value) {
	var itm=this._form[this.getPath()];
	itm.checked = value? true: false;
	return (itm.checked);
/*	var els=this._form[this.getPath()];
	for(var i=0;i<els.length;i++)
		if(els[i].value == value)
			els[i].checked = true;
	return (null);*/
};
NCheckbox.prototype.Init = function() {
	if (!this.exists())
		return ;
	NInput.prototype.Init.call(this);
	var itm=this._form[this.getPath()];
	function	update_hidden() {
		if (itm.checked && itm.nextSibling && itm.nextSibling.tagName == 'INPUT' && itm.nextSibling.name == itm.name) {
			itm.parentNode.removeChild(itm.nextSibling);
		}
		else if (!itm.checked && (!itm.nextSibling || itm.nextSibling.tagName != 'INPUT' || itm.nextSibling.name != itm.name)) {
			jQuery(itm).after('<input type=hidden />');
			itm.nextSibling.name = itm.name;
		}
	};
	jQuery(itm).click(update_hidden).change(update_hidden).keyup(update_hidden);
	update_hidden();
}

/**	Recupere la valeur du champ en parametre
 */
NCheckbox.getValue = function(itm) {
	return (itm.checked);
};
/**	Change la valeur du champ passé en parametre
 */
NCheckbox.setValue = function(itm, value) {
	var els = itm.tagName && itm.tagName == 'CHECKBOX'? itm.form[itm.name]: itm;
	for(var i=0;i<els.length;i++)
		if (els[i].value == value)
			els[i].checked = true;
};


/**	NRib
 */
function	NRib(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
	this._custom = '';
	this._items = ['Banque', 'Guichet', 'Compte', 'Cle'];
};
/**	Heritage de NInput 
 */
NRib.prototype = new NInput;
/**	Nommage de la classe
 */
NRib.prototype.className = 'rib';
NRib.prototype.Init = function() {
	for (i in this._items) {
		this._form[this.getPath()+'['+this._items[i]+']'].setAttribute("autocomplete","off");
		NForm.addCallback(this._form[this.getPath()+'['+this._items[i]+']'], 'onkeydown', NForm.limitNumericKeyPress);
	}
	if (!jQuery.browser.msie) {
		this._form[this.getPath()+'[Banque]'].nextone = this._form[this.getPath()+'[Guichet]'];
		this._form[this.getPath()+'[Guichet]'].nextone = this._form[this.getPath()+'[Compte]'];
		this._form[this.getPath()+'[Compte]'].nextone = this._form[this.getPath()+'[Cle]'];
		this._form[this.getPath()+'[Cle]'].prevone = this._form[this.getPath()+'[Compte]'];
		this._form[this.getPath()+'[Compte]'].prevone = this._form[this.getPath()+'[Guichet]'];
		this._form[this.getPath()+'[Guichet]'].prevone = this._form[this.getPath()+'[Banque]'];
		NForm.addCallback(this._form[this.getPath()+'[Banque]'], 'onkeyup', NRib.gotoNext);
		NForm.addCallback(this._form[this.getPath()+'[Guichet]'], 'onkeyup', NRib.gotoNext);
		NForm.addCallback(this._form[this.getPath()+'[Compte]'], 'onkeyup', NRib.gotoNext);
		NForm.addCallback(this._form[this.getPath()+'[Cle]'], 'onkeyup', NRib.gotoNext);
	}
};
NRib.gotoNext = function(e) {
	e = e? e: window.event;
	var k = e.keyCode? e.keyCode: e.which;
	var max = this.getAttribute('maxlength');
	var cur = Cursor.GetPos(this);
	if (k == 8 && cur==0 && this.prevone) {
		this.prevone.focus();
		Cursor.SetPos(this.prevone, this.prevone.value.length);
		return (false);
	}
	if (this.value.length == max && cur >= 0 && cur == max && this.nextone) {
		this.nextone.focus();
		Cursor.SetPos(this.nextone, 0, this.nextone.value.length);
		return (false);
	}
	return (true);
};
NRib.prototype.check = function() {
	function	getKey(banque, guichet, compte) {
		if (5 != banque.length || 5 != guichet.length || 11 != compte.length)
			return ('N/A');
		function	replaceAlpha(alpha) {
			return '12345678912345678923456789'.charAt(alpha.charCodeAt(0) - 65);
		}
		compte = parseInt(compte.toUpperCase().replace(/[A-Z]/g, replaceAlpha), 10);
		return (97 - (((parseInt(banque, 10)% 97 * 100000 + parseFloat(guichet)) % 97 * 100000000000 + compte) % 97) * 100 % 97);
	}
	var banque = this._form[this.getPath()+'[Banque]'].value;
	var guichet = this._form[this.getPath()+'[Guichet]'].value;
	var compte = this._form[this.getPath()+'[Compte]'].value;
	var cle = getKey(banque, guichet, compte);
	if (typeof(FloatToolbar) != 'undefined')
		this._custom = '\n\n-------------------------------------------------------------\nMessage de dev => La clef devrait être: \''+cle+'\'';
//	alert(cle+' <=> '+this._form[this._name+'[Cle]'].value);
	return (cle == this._form[this.getPath()+'[Cle]'].value);
};
NRib.prototype.getErrorMessage = function() {
	return ('Le RIB n\'est pas valide'+this._custom);
};



/**	NSecu
 */
function	NSecu(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
	this._custom = '';
	this._items = ['Numero', 'Clef'];
};
/**	Heritage de NInput 
 */
NSecu.prototype = new NInput;
/**	Nommage de la classe
 */
NSecu.prototype.className = 'secu';
NSecu.prototype.Init = function() {
	for (i in this._items) {
		this._form[this.getPath()+'['+this._items[i]+']'].setAttribute("autocomplete","off");
		NForm.addCallback(this._form[this.getPath()+'['+this._items[i]+']'], 'onkeydown', NForm.limitNumericKeyPress);
	}
};

NSecu.prototype.associateListener = function(listener) {
	for (var j in listener)
		if (j.indexOf('on')===0 && typeof(listener[j]) == 'function') {
			for (i in this._items)
				this._form[this.getPath()+'['+this._items[i]+']']._nFormObj = this;
			NForm.addListener(this._form[this.getPath()+'[Numero]'], j.toLowerCase(), new Function('e', 'this._nFormObj.fireEvent("'+j+'", e)'));
		}
};
NSecu.prototype.check = function() {
	if (this.getValue().length != 16) {
		return (false);
	}
	return (true);
};
NSecu.prototype.getErrorMessage = function() {
	return ('Le numéro de sécu n\'est pas valide'+this._custom);
};
NSecu.gotoNext = function(e) {};



/**	NAffil
 */
function	NAffil(name) {
	this._name = name;
	this._rules = [];
	this._form = null;
	this._custom = '';
	this._items = ['NumeroCaisse', 'NumeroRegime', 'NumeroCentre', 'RangNaissance'];
};
/**	Heritage de NInput 
 */
NAffil.prototype = new NInput;
/**	Nommage de la classe
 */
NAffil.prototype.className = 'rib';
NAffil.prototype.Init = function() {
	for (i in this._items) {
		this._form[this.getPath()+'['+this._items[i]+']'].setAttribute("autocomplete","off");
		NForm.addCallback(this._form[this.getPath()+'['+this._items[i]+']'], 'onkeydown', NForm.limitNumericKeyPress);
	}
};
NAffil.prototype.associateListener = function(listener) {
	for (i in listener)
		if (i.indexOf('on')===0 && typeof(listener[i]) == 'function') {
			for (i in this._items)
				this._form[this.getPath()+'['+this._items[i]+']']._nFormObj = this;
			NForm.addListener(this._form[this.getPath()+'[NumeroCaisse]'], i.toLowerCase(), new Function('e', 'this._nFormObj.fireEvent("'+i+'", e)'));
			
			
//			this.domObj._xToolObj = this;
//			this.domObj[i.toLowerCase()] = new Function('e', 'this._xToolObj.fireEvent("'+i+'", e)');
		}
};
NAffil.prototype.check = function() {
	if (this.getValue().length != 12) {
		return (false);
	}
	return (true);
};
NAffil.prototype.className = 'secu';
NAffil.prototype.getErrorMessage = function() {
	return ('Le numéro de l\'organisme d\'affiliation n\'est pas valide'+this._custom);
};
NAffil.gotoNext = function(e) {};




/**	NDate
 */
function	NDate(name, options) {
	this._name = name;
	this._rules = [];
	this._form = null;
	this._items = ['y', 'm', 'd'];	
	this._options = options || {};
};
/**	Heritage de NInput 
 */
NDate.prototype = new NInput;
/**	Nommage de la classe
 */
NDate.prototype.className = 'date';
NDate._units = {
	y: 31557100,	// 365 * 24 * 60 * 60 + 1/4 * 86400
//	y: 31536000,
	m: 2678400,
	d: 86400,
	h: 3600,
	i: 60
};
NDate.prototype.associateListener = function(listener) {
	var path = this.getPath();
	for (i in listener)
		if (i.indexOf('on')===0 && typeof(listener[i]) == 'function') {
			NForm.addListener(this._form[path+'[d]'], i.toLowerCase(), new Function('e', 'this._nFormObj.fireEvent("'+i+'", e)'));
			NForm.addListener(this._form[path+'[m]'], i.toLowerCase(), new Function('e', 'this._nFormObj.fireEvent("'+i+'", e)'));
			NForm.addListener(this._form[path+'[y]'], i.toLowerCase(), new Function('e', 'this._nFormObj.fireEvent("'+i+'", e)'));
		}
};
NDate.datePickers = [];
NDate.prototype.Init = function() {
	if (!this.exists())
		return ;
	NInput.prototype.Init.call(this);
	var path = this.getPath();
	this._form[path+'[d]']._nFormObj = this;
	this._form[path+'[m]']._nFormObj = this;
	this._form[path+'[y]']._nFormObj = this;
	this._form[path+'[d]'].setAttribute("autocomplete","off");
	this._form[path+'[m]'].setAttribute("autocomplete","off");
	this._form[path+'[y]'].setAttribute("autocomplete","off");
	NDate.limit_day(this._form[path+'[d]']);
	NDate.limit_month(this._form[path+'[m]']);
	NDate.limit_year(this._form[path+'[y]']);
	
	if (this._options.render == 'datepicker') {

		var yearInput = jQuery(this._form[path+'[y]']);
		if (!NDate.calendarLoading) {
			/** If jquery calendar module is not loaded, push it to a stack
			 *	and load it, once complete, run the calendar on the stack
			 */
			NDate.calendarLoading = true;
			NDate.datePickers.push(yearInput);
			jQuery.ajax({
				dataType: 'script',
				url: Resources.jqueryCalendar,
				error: function() {
					throw 'Unable to load '+this.url;
				},
				success: function() {
					if (typeof(popUpCal)!='undefined') {
						popUpCal.firstDay = 1; //!< Premiere colonne : lundi
						popUpCal.changeFirstDay = false; //!< Jours non cliquables, ne peut plus changer le premier jour
					}
					for (var i in NDate.datePickers)
						jQuery(NDate.datePickers[i]).calendar({autoPopUp: 'button'});
					NDate.datePickers = [];
				}
			});
		}
		else if (yearInput.calendar) {
			/** If jquery calendar module is loaded, run it now */
			yearInput.calendar({autoPopUp: 'button'});
		}
		else
			NDate.datePickers.push(yearInput);
	}
};
NDate.prototype.getNumericValue = function() {
	return (this.toNumericValue(this.getValue()));
};
NDate.parseDate = function(date) {
	if (date.length === 10 && date.split('-').length===3){
		splt=date.split('-');
		var year=parseInt(splt[0], 10);
		var month=parseInt(ltrim(splt[1], '0'), 10);
		var day=parseInt(ltrim(splt[2], '0'), 10);
		date = date.substr(0, 10);
	}
	else if (date.length === 8){
		var year=parseInt(date.substr(0,4), 10);
		var month=parseInt(ltrim(date.substr(4,2), '0'), 10);
		var day=parseInt(ltrim(date.substr(6,2), '0'), 10);
		date = date.substr(0, 8);
	}
	else {
		return (NaN);
	}
//		console.warn("not a valid date: "+date+' ('+year+')');
	year=year<100?1900+year:year;
	var t=new Date(year,month-1,day);
	if (day==t.getDate() && month==t.getMonth()+1 && year==t.getFullYear())
		return (t.getTime());
	return (NaN);
};
NDate.prototype.toString = function(timestamp) {
	var t=new Date();
	t.setTime(timestamp);
	var month = (t.getMonth()+1);
	var day = t.getDate();
	return (t.getFullYear()+'-'+(month<10? '0':'')+month+'-'+(day<10?'0':'')+day);
};
NDate.prototype.getDateElement = function(str) {
	for (var name in this.getGroup()._elements)
		if (str.indexOf(name) === 0)
			return (this.getGroup()._elements[name]);
	for (var name in this.getForm()._form._elements)
		if (str.indexOf(name) === 0)
			return (this.getForm()._form._elements[name]);
	return (null);
};
NDate.prototype.toNumericValue = function(date) {
	var pos = -1;
	var num = 0;
	var op = '+';
	while (date && date.length) {
		if (date.substr(0, 5) == 'NOW()') {
			num += time();
			date = date.substr(5);
		}
		else if (''+(dd = NDate.parseDate(date)) != 'NaN') {
			num += (op=='-'?-1:1)*dd;
			date = date.substr(this.toString(dd).length);
		}
		else if (date.charAt(0) == '+' || date.charAt(0) == '-') {
			op = date.charAt(0);
			date = date.substr(1);
		}
		else if (''+parseInt(date) != 'NaN') {
			var n = parseInt(date);
			var mul = date.charAt((''+n).length);
			num += (op=='-'?-1:1)*(n * NDate._units[mul]) * 1000;
			date = date.substr((''+n).length+1);
		}
		else if ((elm = this.getDateElement(date))) {
			num += (op=='-'?-1:1)*NDate.parseDate(elm.getValue());//elm.getNumericValue();
			date = date.substr(elm.getName().length);
		}
		else {
			throw "unrecognized date format: '"+date+"'\n";
			break ;
		}
	}
	return (num);
};


/**	NSelect
 */
function	NSelect(name, options) {
	this._name = name;
	this._rules = [];
	this._form = null;
	this._options = options;
};
/**	Heritage de NInput 
 */
NSelect.prototype = new NInput;
/**	Nommage de la classe
 */
NSelect.prototype.className = 'select';
NSelect.prototype.Init = function() {
	if (!this.exists())
		return ;
	NInput.prototype.Init.call(this);
	this._form[this.getPath()].ninput = this;
	this._input = this._form[this.getPath()];
	if (this._options && this._options.copyof) {
		var value = this._form[this.getPath()].value;
		var source = this._form[this._options.copyof];
		var dest = this._form[this.getPath()];
		while(dest.firstChild)dest.removeChild(dest.firstChild);
		if (source)
			for (var n=source.firstChild;n;n=n.nextSibling){var m=dest.appendChild(n.cloneNode(true));}
		this.setValue(value);
	}
};
/**	Change la liste des valeurs possibles du Select
 */
NSelect.prototype.setValues = function(values) {
	if (!this.exists())
		return ;
	var value = this.getValue();
	var select = this._form[this.getPath()];
	while (select.firstChild)
		select.removeChild(select.firstChild);
	for (var i in values) {
		var opt = select.appendChild(dc('option'));
		opt.value = i;
		opt.appendChild(dt(values[i]));
	}
	this.setValue(value);
	return (this);
};

NSelect.prototype.getLibelleAt = function(value) {
	for(var i=0;i<select.length;i++)
		if (select[i].value == value)
			return (select[i].firstChild.nodeValue);
	return (null);
}

/**	Recupere la liste des valeurs possibles du Select
 */
NSelect.prototype.getValues = function() {
	if (!this.exists())
		return ;
	var select = this._form[this.getPath()];
	var values = [];
	for(var i=0;i<select.length;i++)
		values[select[i].value] = select[i].firstChild.nodeValue;
	return (values);
};
/**	Change la valeur selectionnee du champ
 */
NSelect.prototype.setValue = function(value) {
	if (typeof(value)=='undefined' || value == 'undefined')
		value = '';
	if (!this.exists())
		return ;
	var select=this._form[this.getPath()];
	if (value === null) {
		for(var i=0;i<select.length;i++)
			select[i].selected = false;
		return ;
	}
	for(var i=0;i<select.length;i++) {
		try {
			select[i].selected = select[i].value == value? true: false;
		}catch(e){}
	}
//	this.fireEvent('onChange');
	return (this);
};


//required', 'minvalue', 'maxvalue', 'minlength', 'maxlength', 'rangevalue', 'numeric', 'rib

function	NValidate(){}
NValidate.required = function(elm) {
	return (elm.getValue());
};
NValidate.minvalue = function(elm, option) {
	var min = Number(typeof(elm.toNumericValue)=='function'? elm.toNumericValue(option): option);
	var value = Number(typeof(elm.getNumericValue)=='function'? elm.getNumericValue(): elm.getValue() /*.replace(',', '.')*/ );
	if (''+min == 'NaN' || ''+value == 'NaN')
		throw "La validation d\'une valeur minimum requiert un chiffre de référence ("+typeof(option)+": "+option+") pour l'élément "+elm.getName();
	return (min <= value);
};
NValidate.maxvalue = function(elm, option) {
	var max = Number(typeof(elm.toNumericValue)=='function'? elm.toNumericValue(option): option);
	var value = Number(typeof(elm.getNumericValue)=='function'? elm.getNumericValue(): elm.getValue() /*.replace(',', '.')*/ );
	if (''+max == 'NaN' || ''+value == 'NaN')
		throw "La validation d\'une valeur maximum requiert un chiffre de référence ("+typeof(option)+": "+option+") pour l'élément "+elm.getName();
	return (value <= max);
};
NValidate.minlength = function(elm, option) {
	var length = Number(option);
	var value = String(elm.getValue());
	if (''+length == 'NaN' || length < 0)
		throw "La validation d\'une longueur requiert un chiffre entier positif ("+typeof(option)+": "+option+")";
	return (value.length >= length);
};
NValidate.maxlength = function(elm, option) {
	var length = Number(option);
	var value = String(elm.getValue());
	if (''+length == 'NaN' || length < 0)
		throw "La validation d\'une longueur requiert un chiffre entier positif ("+typeof(option)+": "+option+")";
	return (value.length <= length);
};
NValidate.rangevalue = function(elm, options) {
	var min = Number(typeof(elm.constructor.toNumericValue)=='function'? elm.constructor.toNumericValue(options[0]): options[0]);
	var max = Number(typeof(elm.constructor.toNumericValue)=='function'? elm.constructor.toNumericValue(options[1]): options[1]);
	var value = Number(typeof(elm.getNumericValue)=='function'? elm.getNumericValue(): elm.getValue());
	if (''+min == 'NaN' || ''+max == 'NaN' || min < 0 || min > max || ''+value == 'NaN')
		throw "La validation d\'un plage de value requiert deux chiffres positifs ordonnés ("+typeof(min)+": "+min+" < X < "+typeof(max)+": "+max+") lors de la validation de l'élément "+elm.getName();
	return (min <= value && value <= max);
};
NValidate.alphanumeric = function(elm) {
	if (elm.getValue() == '')
		return (true);
	var regex = /^[a-zA-Z0-9]+$/;
	return (regex.test(elm.getValue()));
};
NValidate.nopunctuation = function(elm) {
	if (elm.getValue() == '')
		return (true);
	var regex = /^[^()\/\*\^\?#!@$%+=;|\"><~\[\]{}]+$/;
	return (regex.test(elm.getValue()));
};
NValidate.numeric = function(elm) {
	if (elm.getValue() == 0)
		return (true);
	var value = ltrim(elm.getValue(), '0');
	if (!value)
		value = '0';
	value = value;//.replace(',', '.');
	return (parseInt(value)==value || parseFloat(value)==value);
};
NValidate['float'] = function(elm) {
	if (elm.getValue() === 0 || elm.getValue() === '0')
		return (true);
	var value = ltrim(elm.getValue(), '0');
	return (parseFloat(value)==value);
};
NValidate.email = function(elm) {
	if (elm.getValue() == '')
		return (true);
	var regex = /^((\"[^\"\f\n\r\t\v\b]+\")|([\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+(\.[\w\!\#\$\%\&\'\*\+\-\~\/\^\`\|\{\}]+)*))@((\[(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))\])|(((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9]))\.((25[0-5])|(2[0-4][0-9])|([0-1]?[0-9]?[0-9])))|((([A-Za-z0-9\-])+\.)+[A-Za-z\-]{2,}))$/;
	return (regex.test(elm.getValue()));
};
NValidate.date = function(elm) {
	if (elm.getValue() == '')
		return (false);
	return (''+elm.getNumericValue() != 'NaN');
};




/****************************************************************
 * 				Fonctions pour les champs Date					*
 ****************************************************************/

/** Association des callbacks */

NDate.limit_day = function(input) {
	var name = input.name.substr(0, input.name.lastIndexOf('[d]'));
	input.maxlength = 2;
	input.gonextone = input.form[name+'[m]'];
	jQuery(input).keydown(NForm.limitNumericKeyPress);
	jQuery(input).keyup(NDate.onkeyup);
};
NDate.limit_month = function(input) {
	var name = input.name.substr(0, input.name.lastIndexOf('[m]'));
	input.maxlength = 2;
	input.goprevone = input.form[name+'[d]'];
	input.gonextone = input.form[name+'[y]'];
	jQuery(input).keydown(NForm.limitNumericKeyPress);
	jQuery(input).keyup(NDate.onkeyup);
};
NDate.limit_year = function(input) {
	var name = input.name.substr(0, input.name.lastIndexOf('[y]'));
	input.maxlength = 4;
	input.goprevone = input.form[name+'[m]'];
	jQuery(input).keydown(NForm.limitNumericKeyPress);
	jQuery(input).keyup(NDate.onkeyup);
	jQuery(input).blur(NDate.bluryear);
};

/**	Quand on relache une touche
 * 		- si on est a la fin de la case, on passe au champ suivant
 * 		- si on est au debut de la case, on passe au champ precedent
 */
NDate.onkeyup = function(e) {
	if (!this.tagName && this.tagName != 'INPUT')
		return ;
	var e = e? e: window.event;
	var k = e.keyCode ? e.keyCode : e.which;

	if (k == 8) {
		if (this.goprevone && this.value.length == 0)
			Cursor.SetPos(this.goprevone,this.goprevone.value.length);
	}
	else if (k >= 96 && k <= 105 && this.value.length == this.maxlength) {
		if (this.gonextone) {
			try {
				Cursor.SetPos(this.gonextone, 0, this.gonextone.value.length);
			}catch(e){}
		}
	}
};

/** Quand on quitte la case d'une année, ajouter 20xx pour les dates a 2 chiffres */
NDate.bluryear = function() {
	if (this.value.length <= 2 && parseInt(this.value, 10) == this.value) {
		var cur = parseInt(this.value, 10);
		this.value = (cur > NConf.datePivot? 1900 : 2000) + cur;
		jQuery(this).trigger('change');
	}
};


/****************************************************************
 * 						Global functions						*
 ****************************************************************/

function	time(date) {
	var t=new Date();
	return(t.getTime());
}
function	ltrim(value, chars) {
	while (value.length && chars.indexOf(value.charAt(0)) != -1)
		value = value.substr(1);
	return (value);
}
function	GetNodeAttribute(n,p){
	if(n&&typeof(n[p])!='undefined')
		return(n[p]);
	if(!n||!n.attributes)
		return;
	var a=n.attributes.getNamedItem(p);
	return(a?a.nodeValue:undefined);
}
function	dirname(path) {
	var last = path.lastIndexOf('/');
	return (last!=-1? path.substr(0, last): path);
}
function	hosturl(url) {
	var p=url.indexOf('://');
	if (p==-1)
		return ('');
	var t=url.indexOf('/', p);
	if (t>0)
		return (url);
	return (url.substr(0, p+3));
}
/**	Positionnement du curseur dans les INPUT
 */

var Cursor = {
	Get_NbrCR: function(txt) {
		var len = 0;
		for (var pos = txt.indexOf("\r\n"); pos > -1; len++)
			pos = txt.indexOf("\r\n", pos+2);
		return (len);
	},
	GetPos: function(input) {
		input.focus();
		if(typeof input.selectionStart != "undefined")
			return input.selectionStart;
		else { // IE
			var szMark = "~~";
			var str = input.value;
			var szTmp = document.selection.createRange();
			szTmp.text = szMark;
			var beg = input.value.search(szMark);
			var szAvant  = str.substring( 0 , beg);
			beg -= Cursor.Get_NbrCR( szAvant);
			input.value = str;
			str = input.createTextRange();
			str.moveStart('character', beg);
			str.collapse();
			str.select();
			return (beg);
		}
	},
	GetPosEnd: function(input) {
		input.focus();
		if(typeof input.selectionEnd != "undefined")
			return input.selectionEnd;
		else { // IE
			var szMark = "~~";
			var str = input.value;
			var szTmp = document.selection.createRange();
			szTmp.text = szMark;
			var beg = input.value.search(szMark);
			var szAvant  = str.substring( 0 , beg);
			beg -= Cursor.Get_NbrCR( szAvant);
			input.value = str;
			str = input.createTextRange();
			str.moveStart('character', beg);
			str.collapse();
			str.select();
			return (beg);
		}
	},
	ClearSelection: function(input) {
		var beg = Cursor.GetPos(input);
	},
	SetPos: function(input, pos, end) {
		if (typeof(end)=='undefined')
			end=pos;
		input.focus();
		if (typeof input.selectionStart != "undefined"){
			input.setSelectionRange(pos, end);
		}
		else { // IE
			var str = input.createTextRange();
			str.moveStart('character', pos);
			str.moveEnd('character', end);
			str.collapse(true);
			str.select();
		}
		return (Cursor.GetPos( input, pos));
	},
	AddTexte: function(input, txt) {
		input.focus();
		if (typeof input.selectionStart != "undefined"){
			var beg  = input.selectionStart;
			var end  = input.selectionEnd;
			var str  = input.value;
			var szAvant = str.substring(0, beg);
			var szApres = str.substring(end, input.textLength );
			var szSelect = str.substring(beg, end);
			input.value = szAvant + txt + szApres;
			input.setSelectionRange(szAvant.length + txt.length, szAvant.length + txt.length );
			input.focus();
		}
		else { // IE
			var szSelect = document.selection.createRange().text;
			if (szSelect.length > 0){
				var str = document.selection.createRange();
				str.text = txt ;
				str.collapse();
				str.select();
			}
			else {
				var str = input.value;
				var szMark ="~~";
				var szTmp = document.selection.createRange().duplicate();
				szTmp.text = szMark;
				var beg = input.value.search(szMark);
				var szAvant = str.substring( 0 , beg);
				var szApres = str.substring( beg, input.textLength );
				input.value = szAvant + txt + szSelect + szApres;
				beg += txt.length;
				beg -= Cursor.Get_NbrCR( szAvant);
				str = input.createTextRange();
				str.moveStart('character', beg);
				str.collapse();
				str.select();
			}
		}
	}
};
function	array_search(arry, value) {
	for (var i=0;i<arry.length; i++)
		if (arry[i]===value)
			return (i);
	return (-1);
}
