/*
Copyright (C) 2004-2010  Copyright MICHAEL CULTURE AISBL
See LICENCE file.
*/

var suggestCurrent=false;
var listSize = 0;
/**displaying a criterion**/
function criterePlus(num) {
	if(document.getElementById){
		var o1=document.getElementById("tr-c" + num);
		if (o1!=null) if(o1.style.display=='none') o1.style.display='';
		return null;
	} else return null;
}

/**hiding a criterion**/
function critereMoins(num) {
	if(document.getElementById){
			var o1=document.getElementById("tr-c" + num);
			if (o1!=null) if(o1.style.display!='none') o1.style.display='none';

			o1=document.getElementById("query0" + num);
			if (o1!=null) o1.value='';
			o1=document.getElementById("hquery0" + num);
			if (o1!=null) o1.value='';
			o1=document.getElementById("champ" + num+"_cop");
			if (o1!=null) o1.selectedIndex=0;
			var cpt=0;
			var l=document.getElementsByTagName('SELECT');
			while (cpt!=l.length){
				if (l[cpt].id.indexOf("sel0"+num)==0){
					l[cpt].selectedIndex=-1;
				}
				cpt = cpt + 1
			}
			cpt=0;
			l=document.getElementsByTagName('INPUT');
			while (cpt!=l.length){
				if (l[cpt].id.indexOf("text0"+num)==0){
					l[cpt].value='';
				}
				cpt = cpt + 1
			}
			return null;
	} else return null;
}

/*emptying all the fields of a row*/
function emptyAllfields(nb){
	/*on vide les listes normales*/
	var cpt=0;
	var l=document.getElementsByTagName('SELECT');
	while (cpt!=l.length){
		if (l[cpt].id.indexOf("sel0"+nb)==0){
			l[cpt].selectedIndex=-1;
		}
		cpt = cpt + 1
	}

	/*on vide les input de type text*/
	 cpt=0;
	l=document.getElementsByTagName('INPUT');
	while (cpt!=l.length){
		if (l[cpt].id.indexOf("text0"+nb)==0){
			l[cpt].value='';
		}
		cpt = cpt + 1
	}
	/*on vide les suggest*/
	var o1=document.getElementById("query0" + nb);
	if (o1!=null) o1.value='';
	o1=document.getElementById("hquery0" + nb);
	if (o1!=null) o1.value='';
}

/*on affiche la bonne liste deroulante*/
function makeNewList(_champ,nb,width){
	var vchamp = _champ.substring(7,_champ.length);
	var thelist = document.getElementById("sel0::::"+vchamp);
	var thediv = document.getElementById("div-sel0"+nb);
	if (thediv!=null && thelist!=null){
		var divchild = thediv.firstChild;
		if (divchild!=null){
			thediv.removeChild(divchild);
		}
		var newsel = document.createElement("select");
		newsel.setAttribute("name","sel0"+nb);
		newsel.setAttribute("id","sel0"+nb+"::::"+vchamp);
		newsel.setAttribute("style","width:"+width+";");
		if (thelist.childNodes.length > 0){
			for (var cpt = 0 ; cpt < thelist.childNodes.length; cpt++){
				var item = thelist.childNodes.item(cpt);
				if(item!=null){
					var value = item.getAttribute("value");
					var label = (item.firstChild.nodeValue);
					var newItem = new Option(label);
					newItem.value = value;
					newsel.options[newsel.length] = newItem;
				}
			}
		}
		thediv.appendChild(newsel);
	}
}

function checkUrlValues(form){
	var cpt = 0;
	var tab = form.elements;
	while (cpt!=tab.length){
		var el = tab[cpt];
		if (el.tagName=="INPUT" || el.tagName=="SELECT"){
			if (el.value==null ||trimString(el.value)=='' ){
				el.name="";
				if (el.getAttribute("name")!=null){
					el.removeAttributeNode(el.getAttributeNode("name"));
				}
			}
		}
		cpt = cpt + 1;
	}
	form.submit();
}

/*reloading a page*/
function reloadPage(url){
	date = new Date();
	var curDate = null;
	do {
		var curDate = new Date();
	}
	while(curDate-date < 2000);
	window.location.href=url;
}

function trimString (str) {
  str = this != window? this : str;
  return str.replace(/^\s+/g, '').replace(/\s+$/g, '');
}

// La fenêtre courante, sert à fixer des variables globales, peut au cas où être modifiée
var win=window;

var logger;
// Pas très js object standard, mais bon, on fera mieux un autre jour
newLogger();
function newLogger() {
	logger=win.logger=new Object();
	logger.QUIET=0;
	logger.ERROR=1;
	logger.WARN=2;
	logger.INFO=3;
	logger.DEBUG=4;
	logger.banner=new Array();
	logger.banner[logger.QUIET]="";
	logger.banner[logger.ERROR]=" [!!!] ";
	logger.banner[logger.WARN]=" ! ";
	logger.banner[logger.INFO]="";
	logger.banner[logger.DEBUG]="	";
}

/*
Initialisation des contrôles de suggestion
*/
function suggestInit(t) {
	//on initialize la taille des listes
	listSize = t;
	// pas de methodes DOM, autant eviter d'embeter ce navigateur
	if (!document.getElementsByTagName) return;
	// On prends tous les input
	var fields=document.getElementsByTagName('INPUT');
	for (var i=0;i<fields.length;i++) {
		if(fields[i].id.indexOf("query0")==0){
			// si ce n'est pas un champ texte avec une URI interrogeable, cela ne peut pas etre un suggest
			if (!fields[i].type == "text" || !fields[i].src) continue;
			// on essaie d'initialiser cet input comme un champ lien
			initLink(fields[i]);
			// on initialise le suggest apres (attention, boluscule l'ordre des controles)
			fieldInit(fields[i]);
			//on initilase ce qui va contenir la valeur
			var obj = document.getElementById("h"+fields[i].id);
			if (obj == null  || obj.className.indexOf("suggestValue") == -1 ) return;
			fields[i].suggestValue=obj;
			log("suggestInit()\t Initialisation de <input name=\""+fields[i].name + "\">", logger.INFO);
		}
	}

}

/*
dans le cas d'un champ lien, l'input à côté porte la valeur, le suivant l'identifiant de document
*/
function initLink(input) {
	// évite d'augmenter les tests
	if (input.className.indexOf("link") == -1) return;
	var i= formIndex(input);
	var obj=input.form.elements[i+1];
	// on voit s'il on peut faire quelque chose du contrôle suivant
	if (obj == null || obj.style == null || obj.value == null || obj.className.indexOf("suggestValue") == -1 ) return;
	// on lie le suggest à son champ valeur cachée et on affiche la valeur
	input.suggestValue=obj;
	input.value=obj.value;
	// on regarde si le champ suivant est destiné à porter un identifiant, si oui, on l'attache au suggest
	obj=input.form.elements[i+2];
	if (obj == null || obj.style == null || obj.value == null || obj.className.indexOf("suggestId") == -1) return;
	input.suggestId=obj;
}


// efface les contrôles d'un formulaire
function clearForm(node) {
	var controls;
	// TODO, tester les input text
	controls=node.getElementsByTagName('INPUT');
	for (var i=0;i<controls.length;i++) {
		controls[i].value="";
	}
	controls=node.getElementsByTagName('SELECT');
	for (var i=0;i<controls.length;i++) {
		controls[i].selectedIndex=-1;
	}
	controls=node.getElementsByTagName('TEXTAREA');
	for (var i=0;i<controls.length;i++) {
		controls[i].value="";
	}
}


// On fixe ici le niveau de log voulu (par défaut rien)
logger.level=logger.QUIET;
// On peut fixer une aire d'écriture des logs
logger.area;

/* à appeler quand le document a été chargé */
function logInit() {
	logger.area=document.getElementById("logger_area");
	if (!logger.area || !logger.area.value) logger.area=null;
	logger.init=true;
}
/*
De quoi journaliser les opérations
Retourne vrai par défaut pour continuer les événements
*/
function log( text, level ) {
	level=(level)?level:logger.INFO;
	if (level > logger.level) return true;
	if (!logger.init) logInit();
	// ça coûte pas de passer une ligne de status
	window.status=logger.banner[level]+text;
	if (!logger.area) return true;
	var old=logger.area.value;
	logger.area.value=logger.banner[level]+text+"\n"+old;
	return true;
}


// see http://developer.apple.com/internet/webcontent/XMLHttpRequestExample/example.html
// global request and XML document objects
var req;

// retrieve XML document (reusable generic function);
// parameter is URL string (relative or complete) to
// an .xml file whose Content-Type is a valid XML
// type, such as text/xml; XML source must be from
// same domain as HTML file
function loadXMLDoc(url) {
	while (url.indexOf("\u0026amp;")!=-1){
		url = url.replace("\u0026amp;","&");
	}
	log("loadXMLDoc()\t "+url, logger.INFO);
	window.lastUrl=url;
	// Attention, il est interdit d'appeler une URI dans un autre domaine
	// branch for native XMLHttpRequest object
	if (window.XMLHttpRequest) {
			req = new XMLHttpRequest();
			req.onreadystatechange = processReqChange;
			req.open("GET", url, true);
			req.send(null);
	// branch for IE/Windows ActiveX version
	} else if (window.ActiveXObject) {
			isIE = true;
			req = new ActiveXObject("Microsoft.XMLHTTP");
			if (req) {
					req.onreadystatechange = processReqChange;
					req.open("GET", url, true);
					req.send();
			}
	}
}

var errorCount=0;
var lastUrl;

// handle onreadystatechange event of req object
// this means that only one doc could be loaded at a time ?
function processReqChange() {
	log("processReqChange()\t "+lastUrl, logger.DEBUG);
		// only if req shows "loaded"
		if (req.readyState == 4) {
				if (req.status == 200) {
						// marche donc remplir
						// trouver moyen d'obtenir le select à renseigner
						suggestPopulate(suggestCurrent);
				 } else {
						// For debug, TODO unplug
						log("processReqChange()\t "+req.status+"\n"+lastUrl, logger.ERROR);
				 }
		}

		/*
		else {
		// strange bug under Firefox, resend action
		// Attention à un catch, revient ici, si le populate() déconne
						alert("Problème de récupération de la liste de termes:\n" +
							 lastUrl + " " + req.statusText);
		// DO nothing
		}*/
}

// devrait charger les options du select
function suggestPopulate(select) {
	if (!select || !select.options) return log("suggestPopulate()\t no select provide to populate", logger.ERROR);
	// text=req.responseText.replace(/<\?[^?]*\?>/gi, "").replace(/<\/?pre[^>]*>/gi, "");
	// suggest.innerHTML=html;
	// innerHTML ne marche pas avec un select :o(
	// du coup on passe une ligne value:::text apr option
	clearSelect(select);
	text=req.responseText;
	var sep="::::";
	var i=0;
	// il y a un max ici pour le nombre d'options dans le select
	while (text.indexOf(sep) != -1 && i < 1000 ) {
		line=text.substring(0, text.indexOf("\n"));
		if (line.indexOf(sep) != -1) {
			// on ajoute le séparateur en fin pour sécuriser
			line=line+sep;
			value=line.substring(0, line.indexOf(sep))
			line=line.substring(line.indexOf(sep) + sep.length);
			label=line.substring(0, line.indexOf(sep));
			// la troisième colonne peut porter un identifiant de doc
			line=line.substring(line.indexOf(sep) + sep.length);
			id=line.substring(0, line.indexOf(sep));
			if (!label) label=value;
			label = trimString(label);
			var option=new Option(label, value);
			option.suggestId=id;
			select.options[i]=option;
			i++;
		}
		if (line.indexOf("request.getCharacterEncoding") != -1) {
			select.options[i]=new Option(line, line);
			i++;
		}
		text=text.substring(text.indexOf("\n")+1);
	}
}
/*
Une méthode pour retrouver l'index d'un contrôle
dans un formulaire pour pouvoir prendre les précédents suivants
*/
function formIndex(control) {
	var form=control.form;
	if (!form || !form.elements) return log("formIndex()\t this control is not in a form", logger.ERROR);
	for (var i=0; i < form.elements.length; i++) {
		if (form.elements[i] == control) return i;
	}
	return -1;
}

/*

Initialisation forcée d'un élément de formulaire dans un champ
avec suggest

*/
function fieldInit(input) {

		if (!input || input.tagName.toLowerCase() != "input" )
			return log("fieldInit()\t "+ input +" n'est pas un input, impossible d'initialiser ce champ.", logger.WARN);
	var button=document.createElement("button");
	button.appendChild(document.createTextNode("v"));
	button.className="suggest";
	// button.style.position="absolute";
	button.style.fontWeight="bold";
	// plus gênant qu'autre chose
	// button.style.marginLeft="-2ex";
	button.style.padding="0";
	// On attribue l'input concerné
	button.input=input;
	// IE n'aime pas qu'on fixe le type comme ça, mais pour Firefox il vaut mieux
	if (button.type != "button") button.type = "button";
    // agir à la fin du clic
	button.onmouseup=fieldClick;

		var suggest=document.createElement("select");
// pas de name à ce select pour éviter de l'envoyer à la soumission de formulaire
		suggest.setAttribute("multiple", "multiple");
		// ici codé en dur, si cela amuse quelqu'un de paramétrer
		suggest.setAttribute("size", "10");
		// permet de gérer en css
		suggest.className="suggest";
		// On prend la largeur de l'input (attention aux champs en display none)
		var disp=input.style.display;
		input.style.display="block";
		var width=listSize;
		input.style.display=disp;
		butWidth = button.offsetWidth;
		if (width > 100) suggest.style.width=width+"px";
		// On met une position à absolute pour éviter de casser une présentation
		suggest.style.position="absolute";
        // une propriété pour bien dire ce que c'est un suggest
        suggest.isSuggest=true;
		// les fonctions attachées à un suggest
        suggest.hide=new Function(
            ""
            + "this.style.display='none';this.hidden=true;"
            + "if (suggestCurrent == this) suggestCurrent == null;"
        );
        suggest.show=new Function(
            ""
            + "if (suggestCurrent == this && !suggestCurrent.hidden) return; "
            + "if (suggestCurrent && suggestCurrent != this) { suggestCurrent.hide(); suggestCurrent=null}"
            + "\nthis.style.display='block';this.hidden=false;suggestCurrent=this;"
        );
        // on vérifie si ça marche;
        suggest.hide();
        // Une sécurisation pour garantir que le select reste affiché
		suggest.onfocus=new Function("this.show();");


		// On affecte un évènement en cas de sélection dans le suggest
		// onclick ne laisse pas le temps à IE de mettre à jour le select
		suggest.onchange=fieldFill;
		// on lie l'input au select
		suggest.input=input;


/*

l'affichage devrait ressembler à

	<input/>
	<button>v</button>
	<br/>
	<select style="display:none;position:absolute" multiple="multiple" size="10">
		<option>option</option>
	</select>


ne marche pas dans firefox, on passe en DOM
div.innerHTML='<select class="suggest" multiple="multiple" size="10"/>';
		Erreur : uncaught exception: [Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIDOMNSHTMLElement.innerHTML]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: file:///d:/notix/dev/src/test/suggest.js :: fieldInit :: line 188"  data: no]

*/

	//var div=document.createElement("span");
	// on met tout de suite le div juste avant l'input
	// input.parentNode.insertBefore(div, input)
	// et on met l'input dans le div
	//div.appendChild(input);
	// on met après l'input
	// div.appendChild(button);
	// float, left, pour laisser les inlines à côté d'un input
	// IE ne prends pas
	// div.style.cssFloat="left";
	if (input.nextSibling) input.parentNode.insertBefore(suggest, input.nextSibling);
	else input.parentNode.appendChild(suggest);
	suggest.parentNode.insertBefore(button, suggest)
	// un br pour IE
	suggest.parentNode.insertBefore(document.createElement("br") , suggest)



// on lie le select à l'input pour qu'il retrouve son suggest
		input.suggest=suggest;

		/* Maintenant les événements
<input
							class="suggest"
							src="http://localhost:8050/test/suggest.xml?field="
							onfocus="fieldFocus(this)"
							name="value"
							autocomplete="off"
							size="30"
							onkeyup="fieldKey(event,this);" />
		*/
		// par précaution on débranche l'autocomplete, je crois que cela ne vaut que pour IE
		input.autocomplete="off";
		input.onfocus=fieldFocus;
		// onkeypress ne permet d'avoir toutes les touches dans IE
		// onkeydown n'a pas encore mis à jour l'input
		// input.onkeydown=fieldKeyDown;
		// utilisé pour arrêter la validation du formulaire pour firefox
		input.onkeypress=fieldKeyDown;
		input.onkeyup=fieldKey;
		input.onblur=fieldBlur;
}

/*
Pour un bouton dans un input suggest
Assurer que cela recharge le suggest
*/
function fieldClick(event, button) {
  if(!button) button=getEventTarget(event);
	if(!button.input) return log("fieldClick()\t  no input attached this button field", logger.WARN);
	if(!button.input.suggest) return log("fieldClick()\t no suggest attached to this button field", logger.WARN);
	// TODO un test si cela vient d'un onblur ?
	if(button.input.suggest.hidden) {
		// on force le rechargement
		fieldSuggest(this.input, true);
		this.input.focus();
		return true;
	}
	button.input.suggest.hide();
	return false;
}

/*
Un outil pour savoir qui est appelé dans une méthode
d'événement
*/
function getEventTarget(e) {

	// Au cas où l'on ait passé directement l'élément, on teste on repasse
	if (e && e.style) return e;
	// parfois on est dans le contexte d'un élément, on essaye d'envoyer
	if (this && this.style) return this;
	// Si c'est une chaîne, peut-être est-ce un id ?
	// TODO
	// cas le plus utile ici, c'est un événement
	if (!e) var e = window.event;
	if (e.target) el = e.target;
	else if (e.srcElement) el = e.srcElement;
	// defeat Safari bug
	if (el.nodeType == 3) el = el.parentNode;
	return el;
}

/*
Pour interception du return dans un chmap suggest
*/
function fieldKeyDown(event, input) {
	if (!event) var event = window.event;
  if(!input) input=getEventTarget(event);
	if(!input) return log("fieldKey()\t input manquant", logger.WARN);
	if(!input.suggest) return log("fieldKey()\t input mal initialisé", logger.WARN);
  key=getKey(event);
	if (key == 13) {
		fieldFill(input.suggest);
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		if (event.preventDefault) event.preventDefault();
		return false;
	}
}
/*
Réaction des touches dans un champ lié à un suggest
*/
function fieldKey(event, input) {
	// par précaution, pas de cancelBubble
	var kont=true;
	if (!event) var event = window.event;
    if(!input) input=getEventTarget(event);
	if(!input) return log("fieldKey()\t input manquant", logger.WARN);
	if(!input.suggest) return log("fieldKey()\t input mal initialisé", logger.WARN);
  key=getKey(event);

	// on pourrait logger mieux en cas de de mauvais objet
	log("fieldKey()\t "+key);

	// échap, on efface et s'en va
	if (key == 27) {
		input.suggest.selectedIndex=-1;
		input.suggest.hide();
		// on garde tout de même le focus
		// if (input.blur) input.blur();
		return kont;
	}
	// effacement d'un input vide = cacher ?
	/*
	else if (key == 8 && !input.value) {

    }*/
	// curseur bas
	else if (key == 40) {
		// pas de suggest visible on en raffraîchit un
		if (input.suggest.hidden) {
            // forcer le rechargement
			fieldSuggest(input, true);
			return kont;
		}
		// pas d'option sélectionné, par précaution on affiche, on prends la première
		else if ( input.suggest.selectedIndex == -1) {
			input.suggest.selectedIndex=0;
			return kont;
		}
		// dernière option, on peur sortir et cacher
		else if (input.suggest.selectedIndex == input.suggest.options.length -1) {
			return kont;
		}
		// on descend d'un rang
		else input.suggest.selectedIndex = input.suggest.selectedIndex+1;
		return kont;
	}
	// curseur haut
	else if (key == 38) {
		// première option, on sort on cache
		if (input.suggest.selectedIndex < 1 ) {
			input.suggest.selectedIndex=-1;
			input.suggest.hide();
			return kont;
		}
		// rien de sélectionnné, on passe à la la fin
		else if (input.suggest.selectedIndex == -1) {
			input.suggest.show();
			input.suggest.selectedIndex=input.suggest.options.length -1;
			return kont;
		}
		// sinon, on descends
		else input.suggest.selectedIndex = input.suggest.selectedIndex - 1;
		return true;
	}
	// Entrée, on charge la valeur sélectionnée, on évite de valider le formulaire
	else if (key == 13) {
		fieldFill(input.suggest);
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
		if (event.preventDefault) event.preventDefault();
		return false;
	}
	// Ici on ne remplit le suggest que s'il est affiché ?
	if(input.suggest.hidden) return log("fieldKey()\t suggest fermé", logger.DEBUG);
	// peut-être mieux filtrer les touches ?
	// Ici en cas de pb de perfs, on peut éviter de lancer lancer la requête à chaque fois ?
	fieldSuggest(input);
}


/*
En cas de focus, on ne fait pas grand chose.
*/
function fieldFocus(e) {

	// D'abord on attrape l'élément qui appelle
	var input=getEventTarget(e);
	if (!input && !input.select) return true;

	if (!input || !input.suggest || !input.src ) return log("fieldFocus()\t un élément non initialisé essaye de passer pour un suggest", logger.WARN);
	// S'il on était gentil on pourrait essayer d'initialiser l'élement trouvé, mais on n'est pas gentil
	// un peu d'info
	log("fieldFocus()\t name="+input.name + " src="+input.src, logger.INFO);
/* ergonomie pas géniale */


	// en cas de focus, si la liste est caché, on la montre, et on la remplit (première arrivée)
    // commenté, trop systématique
    //if (input.suggest.hidden) fieldSuggest(input);
	// Faut-il sélectionner au focus ?
	input.select();
}


/*
Une méthode pour des suggestions dès qu'on change le champ
*/
function fieldChange(selectField) {
	if (!selectField || !selectField.options) return log("fieldChange()\t no select passed", logger.WARN);
	log("fieldChange()\t "+selectField.options[selectField.selectedIndex].value, logger.INFO);
	if (selectField.input == null) fieldInit(selectField);
	// s'il on ne trouve pas d'input, il n'y a normalement rien à faire.
	if (!selectField.input) return log("fieldChange()\t no input attached", logger.DEBUG);
	selectField.input.selectField=selectField;
	// là on vérifie que l'input a été initialisé, avant de faire afficher des suggestions
	if( ! selectField.input.selectField) selectField.input.selectField=selectField;
	if (selectField.input.suggest == null) fieldInit(selectField.input);
	if (!selectField.input.suggest) return log("fieldChange()\t input has no suggest attached", logger.WARN);
	fieldSuggest(selectField.input);
}


/* Cacher le select de suggestion ? */
function fieldBlur(event, input) {
	if (!event) var event = window.event;
    if(!input) input=getEventTarget(event);
	if (!input) return log("fieldBlur()\t pas d'input", logger.WARN);
	// s'il on ne trouve pas de select, il n'y a normalement rien à faire.
	if (!input.suggest) return;
	// On ne peut pas cacher la liste déroulant quand on sort de l'input
    // quand c'est pour cliquer le bouton ou sélectionnne dans la liste
	// input.suggest.hide();
}

/* renseigner des champs avec la selection d'un suggest */
function fieldFill(suggest) {
	// si on a passé un évènement on attrape l'élément qui appelle
	if (suggest == null || !suggest.tagName) suggest=getEventTarget(suggest);
	if (!suggest) return log("fieldFill()\t un élément null essaye de passer pour un suggest", logger.WARN);
	if(suggest.tagName.toLowerCase() == "option") suggest=suggest.parentNode;


	if (!suggest.input) return log("fieldFill()\t pas d'input attaché, suggest incorrectement initialisé", logger.WARN);

	// si pas de valeur, au revoir
	if (suggest.selectedIndex == -1) return log("fieldFill()\t no value selected", logger.DEBUG);
	// l'option sélectionnée
	var option=suggest.options[suggest.selectedIndex];
	var value=option.text;
	log("fieldFill()\t "+value +" " + option.suggestId, logger.INFO);
	suggest.input.value=value;
	// S'il y a d'autres champs attaché qui veulent être mis à jour
	if (suggest.input.suggestValue) suggest.input.suggestValue.value=option.value;
	if (suggest.input.suggestId) suggest.input.suggestId.value=option.suggestId;
	suggest.hide();
	suggest.input.focus();
	// on ne cache pas ici, on laisse faire fieldFocus
}

/* Cacher le suggest courant */
function suggestHide(el) {
	if (win.currentSuggest) win.currentSuggest.style.visibility="hidden";
	win.currentSuggest=null;
	if (!el) return;
	if (el.suggest) el.suggest.style.visibility="hidden";
}


/* Variables globales uniques poour la fenêtre */
// La valeur courante de suggestion
var currentValue;
// le champ d'entrée courant
var currentInput;
// l'url courante de suggestion
var currentSrc;
/* Ce qui va lancer l'AJAX */
function fieldSuggest(input, force) {
	if (!input) return log("fieldSuggest()\t il faut passer un input suggestable à cette fonction", logger.WARN);
	if (!input.suggest || !input.src) return log( "fieldSuggest()\t <input"
		+" class=\""+ input.className +"\""
		+" name=\"" + name + "\""
		+" src=\""+input.src+"\""
		+"/>"
		+" n'est pas suggestable"
		, logger.WARN );
    // Une chaîne de tests pour éviter de trop souvent taper sur le serveur
    // si le suggest est vide, on est au moins sûr qu'il faut le remplir
    if(!input.suggest.options.length);
    // si on force, on remplit
    else if (force);
    // s'il est nouvellement ouvert, autant le remplir ?
    else if (win.currentInput != input);
	// si c'est même valeur et même liste, probablement pas grand chose de neuf à attendre
	else if ( input.value== win.currentValue && input.src== win.currentSrc ) return;
	// On met à jour les variables globales
	win.currentInput=input;
	win.currentValue=input.value;
	win.currentSrc=input.src;
	// par précaution on force l'affichage du suggest
	input.suggest.show();
	// par précaution, on ajuste la taille
	if(!input.suggest.style.width) {
			var width=input.offsetWidth;
			if (width > 100) input.suggest.style.width=input.offsetWidth+"px";
    }
	// On construit l'URL et on la demande
	// ne pas oublier d'encoder
	var url=input.src+escape(input.value);
	log("fieldSuggest()\t "+url, logger.DEBUG);
	loadXMLDoc(url);
}


// Clears each select that was passed to this method
// uses Javascripts dynamic argument capability--method isn't declared with args, they are looped through
// in the code using the built-in arguments array
function clearSelect() {
	for (var i = 0; i < arguments.length; i++) {
			var element = arguments[i];

			if (typeof element == 'string')
					element = document.getElementsByName(element)[0];

			if (element && element.options) {
					element.options.length = 0;
					element.selectedIndex = -1;
			}
	}
}

/*
Des méthodes DOM parfois utiles
*/

function rowUp(id) {
	if (!document.getElementById) return true;
	var row=document.getElementById(id);
	if (!row) return log("up()\t "+id+" pas de rang de ce nom", logger.WARN);
	var prev=row.previousSibling;
	// on passe jusqu'à ce qu'on trouve un noeud avec lequel permuter
	while(!prev.id) {
		prev=prev.previousSibling;
		if(!next)break;
	}
	if (prev == null) return false;
	row.parentNode.insertBefore(row, prev);
	log("up()\t "+id +" monté", logger.INFO);
	return false;

}
function rowDown(id) {
	if (!document.getElementById) return true;
	var row=document.getElementById(id);
	if (!row) return log("down()\t "+id+" pas de rang de ce nom", logger.WARN);
	var next=row.nextSibling;
	// on passe jusqu'à ce qu'on trouve un noeud avec lequel permuter
	while(!next.id) {
		next=next.nextSibling;
		if(!next)break;
	}
	if (next == null) return false;
	row.parentNode.insertBefore(next, row);
	log("down()\t "+id+ " descendu", logger.INFO);
	return false;
}

// si retour true, faire confiance au serveur
function rowRemove(id) {
	if (!document.getElementById) return true;
	var row=document.getElementById(id);
	if (!row) return log("remove()\t "+id+" pas de rang de ce nom", logger.WARN);
	row.parentNode.removeChild(row);
	log("delete()\t "+id+" supprimé", logger.INFO);
	// L'événement est bloqué, on a fait ce qu'il fallait
	return false;
}

/*
Une fonction pour modifier la structure d'un select selon diverses
touches
pour IE à mettre sur onkeyup, et on on exclut les modifieurs shift et control
*/
function selectKey (event, select) {
	if(!event) event=win.event;
	var key=getKey(event);
	log("selectKey()\t "+key);
	if (key==46) return optionDel(select);
	if(!event.altKey) return true;

	if (key==40) return optionDown (select);
	if (key==38) return optionUp (select);
/* haut
else if (K==38) {optionUp(select); return false; }

	}
	else if (K==46) {optionDel(select) }
	else if (K==13) {
		// TODO

	} // return
	// else { this.selectedIndex=selectRank(this, document.buffer); return false };
	if (window.event && window.event.keyCode == 8 && navigator.appName.search('Explorer')!=-1 ) { //backSpace
		window.event.cancelBubble = true;
		window.event.returnValue = false;
		return false;
	}
	*/
	return true;
}

/*
A cette fonction sont passée 2 select
Elle passe les options sélectionnées de l'un à l'autre
*/
function selectMove (src, dest) {
  if (!isSelect(src)) return log("selectMove()\t "+src+" n'est pas un select", logger.WARN);
  if (!isSelect(dest)) return log("selectMove()\t "+dest+" n'est pas un select", logger.WARN);
	var i=0;
	// l'index à laisser sélectionné
	var out;
	while(i<src.options.length) {
		// si l'option est sélectionnée, la copier, l'ajouter à dest, et la supprimer
		if (src.options[i].selected) {
			optionAdd (dest, src.options[i].text, src.options[i].value);
			src.options[i]=null;
			// on note l'index pour la sortie
			out=i;
		}
		// sinon on passe à la suivante
		else i++;
	}
	// TODO, meilleur
  if (out < src.options.length) src.selectedIndex=out;
  return false;
}

/* Attraper une option par une valeur */
function getOptionByValue (select, value) {
  if (!select.options) return false;
  for (var i = 0; (i>-1 && i<select.length); i=i+1) {
		if (select.options[i].value == value) {
			// est-ce utile ?
			select.selectedIndex = i;
			return select.options[i];
		}
  }
  return false;
}


/* Suppression des options sélectionnée */
function optionDel (select) {
  if (!isSelect(select)) return log("optionDel()\t "+select+" n'est pas un select", logger.WARN);
	var i=0;
	var out;
	while(i<select.options.length) {
		// si l'option est sélectionnée, on la supprimé
		if (select.options[i].selected) {
			select.options[i]=null;
			// on note l'index pour la sortie
			out=i;
		}
		// sinon on passe à la suivante
		else i++;
	}
	// TODO, meilleur
  if (out < select.options.length) select.selectedIndex=out;
  return false;
}

/*
Descends les options sélectionnnées d'un rang


*/
function optionDown (select) {
	// remettre le focus sur le select a un effet désagréable
	//select.focus();
  if (!isSelect(select)) return log("optionDown()\t "+select+" n'est pas un select", logger.WARN);
  var i=select.selectedIndex;
	// entrer
	if (i == -1) {select.selectedIndex=0 ;return false;}
	// sortir ?
  // if (i > select.options.length-2) {select.selectedIndex=-1 ;return false;}
	/*
Logique
On prends la liste en commençant par le bas, on arrête 1 avant la fin
Et on permute 2 options quand la suivante est sélectionnée

*/
	var i=select.options.length - 1;
	while (i > 0) {
		// si la dernière option est selectionné, on sort, tant pis s'il y en a d'autres plus haut
		if ( select.options.length - 1 == i && select.options[i].selected) return true;
		// si l'option plus haut est sélectionnée, on permute
		else if (select.options[i - 1].selected) {
			// à voir, peut-être peut-on optimiser ici
			var selected=new Option (select.options[i - 1].text,select.options[i - 1].value) ;
			var current=new Option (select.options[i].text,select.options[i].value) ;
			select.options[i - 1]=current;
			select.options[i]=selected;
			select.options[i].selected=true;
		}
		i--;
	}
	/*
	marche pour une option
	// Créer de nouvelles options sinon gare aux pointeurs
	var option0=new Option (select.options[i].text,select.options[i].value) ;
	var option1=new Option (select.options[i+1].text,select.options[i+1].value);
	select.options[i]=option1;
	select.options[i+1]=option0;
	// conserver le focus sur l'option déplacée
	select.selectedIndex=i+1;
	*/
	log("optionDown()\t ")
	return false;
}

/*
Monte les options sélectionnnées d'un rang
On passe toutes les options
Si la suivante est sélectionnnée, on permute
*/
function optionUp (select) {
  if (!isSelect(select)) return log("optionAdd()\t "+select+" n'est pas un select", logger.WARN);
	win.modified=true;
	var i=select.selectedIndex;
  if (!isSelect(select)) return log("optionUp()\t "+select+" n'est pas un select", logger.WARN);
	// sortir
  if (i < 1) {select.selectedIndex=-1 ;return false;}
	var i=0;
	while (i < select.options.length - 1) {
		// si l'option plus bas est sélectionnée, on permute
		if (select.options[i + 1].selected) {
			// à voir, peut-être peut-on optimiser ici
			var selected=new Option (select.options[i + 1].text,select.options[i + 1].value) ;
			var current=new Option (select.options[i].text,select.options[i].value) ;
			select.options[i + 1]=current;
			select.options[i]=selected;
			// on restaure la sélection
			select.options[i].selected=true;
		}
		i++;
	}
/* marche pour un,
	var option0=new Option (select.options[i].text,select.options[i].value) ;
	var option1=new Option (select.options[i-1].text,select.options[i-1].value);
	select.options[i]=option1;
	select.options[i-1]=option0;
	// conserver le focus sur l'option déplacée
	select.selectedIndex=i-1;
*/
	log("optionUp()\t ")
  return false;
}

/* Une fonction pour insérer une option en repoussant les autres */
function optionAdd (select, text, value) {
  if (!isSelect(select)) return log("optionAdd()\t "+select+" n'est pas un select", logger.WARN);
  // TODO, à vérifier
	var opt
	opt=getOptionByValue(select, value);
	var confirm=true;
	if (opt) confirm = window.confirm("l'option \""+value+"\" existe déjà. Etes vous certain de vouloir l'ajouter ?");
	if (!confirm) return;

	var opt= new Option (text, value);
  var I=select.selectedIndex;
  I=(I<0)?select.options.length:I+1;
  for (var i=I; i<select.options.length + 1; i++) {
		var tmp=select.options[i];
		select.options[i]=opt;
		opt=tmp;
  }
	select.selectedIndex = I;
	return false;
}


/* Un test pour vérifier qu'un objet est un select */
function isSelect (select) {
  if (select && select.options) return true
  return false
}

/* Sélectionne toutes les options d'un select, par exemple avant submit */
function selectAll(select) {
	// pas de select, on avertit et on sort
	if (!select) return log("selectAll()\t pas de select passé", logger.WARN);
	//pas d'options, pareil
	if (!select.options || !select.options.length > 0) return log("selectAll()\t pas d'options dans le select passé", logger.WARN);
	// on change le type du select dynamiquement, marche pas sous IE grrr
	select.multiple=true;
	// et on sélectionne tout
	for (var i=0; i<select.options.length; i++) select.options[i].selected=true;
}


/*
Avoir le code d'une touche par un event
*/
function getKey(e) {
  if (document.all) e = window.event;
  if(!e)return;
  if (e.keyCode) return e.keyCode;
  else if (e.which) return e.which;
  else return;
}

function findPosX(obj)
{
	var curleft = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (obj.x)
		curleft += obj.x;
	return curleft;
}

function findPosY(obj)
{
	var curtop = 0;
	if (obj.offsetParent)
	{
		while (obj.offsetParent)
		{
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (obj.y)
		curtop += obj.y;
	return curtop;
}

/*
Pour une fenêtre au survol
*/
function show(evt,id){
	if (!document.getElementById) return;
	obj = document.getElementById(id);
	// pas trouvé l'objet, on laisse couler l'événement
	if(!obj || !obj.style) return true;
	// l'objet à afficher est déjà, on relance l'attente
	if (toHide == obj) {
		toHide.wait=true;
		return;
	}

	// prendre le point du pointeur
	if (evt.pageY) { //Calculates the position for Navigator 4
		y = evt.pageY;
		x = evt.pageX;
	} else if (evt.y) { // Calculates the position for IE4
		y = /* getViewY() + */ evt.y;
		x = /* getViewX() + */ evt.x;
	}


	// prendre la taille générale de la fenêtre
	var width=1000;
	var height=800;
	// all except Explorer
	if (self.innerHeight) {
		width = self.innerWidth - 20; // correctif scrollbar
		height = self.innerHeight - 20;  // correctif scrollbar
	} // Explorer 6 Strict Mode
	else if (document.documentElement && document.documentElement.clientHeight) {
		width = document.documentElement.clientWidth;
		height = document.documentElement.clientHeight;
	} // other Explorers
	else if (document.body) {
		width = document.body.clientWidth;
		height = document.body.clientHeight;
	}
	// horizontal, si trop à droite
	if (x > (width * 0.7)) {
		obj.style.left=x - obj.offsetWidth + 100;
	} // horizontal, dans la première moitié, aligné sur la droite du pointeur
	if (x < (width * 0.5) && x > 200) {
		obj.style.left=10 + "px";
		obj.style.width= (x - 30) ;
	} // si plutôt à gauche
	else obj.style.right = x;

	// vertical, s'il n'y a pas la place d'afficher l'objet, on aligne sur le bas
	if ( obj.offsetHeight > (height - y) ) {
		obj.style.top=y - 20 - obj.offsetHeight + getViewY(); // ne pas oublier la hauteur de scroll
	} // si plutôt haut
	else if (y > (height * 0.7)) {
		obj.style.top=y - obj.offsetHeight - 20 + getViewY(); // ne pas oublier la hauteur de scroll
	} // si plutôt haut
	else {
		obj.style.top = y + getViewY(); // ne pas oublier la hauteur de scroll
	}
	// rendre visible et sécuriser le délai
	setDelay(obj);
	// positionnner au mieux la fenêtre
	window.status= ""+id+ " x="+x+" y="+y+ " width="+width+" height="+height+" left="+obj.style.left+" right="+obj.style.right+" objWidth="+obj.style.width
	return false;
}

/*
var toHide;
function hide(evt,id) {
	if (toHide && toHide.style) toHide.style.visibility = "hidden";
	if (!document.getElementById) return;
	obj = document.getElementById(id);
	if (obj && obj.style) obj.style.visibility = "hidden";
	return false;
}
*/

var toHide;
function setDelay(obj) {
	// s'il y avait un objet en mémoire, on le cache
	if (toHide && toHide != obj && toHide.style) {
		toHide.style.visibility = "hidden";
	}
	obj.style.visibility="visible";
	toHide=obj;
	toHide.wait=true;
}

var delay = 500;
function hide() {
	if(!toHide) return;
	toHide.wait=null;
	setTimeout('if (toHide && !toHide.wait) { toHide.style.visibility="hidden"; toHide=null; }', delay);
}

function getViewX(){
  var offset=0;
  if (window.pageXOffset) offset=window.pageXOffset; // gecko, nn4,opera
  else if (document.documentElement &&
	document.documentElement.scrollLeft)
	offset=document.documentElement.scrollLeft; // ie6 compat mode
  else if (document.body && document.body.scrollLeft)
	offset=document.body.scrollLeft; // ie4up
  return offset;
}

function getViewY(){
  var offset=0;
  if (window.pageYOffset) offset=window.pageYOffset;
  else if (document.documentElement &&
	document.documentElement.scrollTop)
	offset=document.documentElement.scrollTop;
  else if (document.body && document.body.scrollTop)
	offset=document.body.scrollTop;
  return offset;
}




/*
get properties of an object
for debug
*/
function props(o) {
 var result = ""
 var a=new Array();
 var i=0
 for (var prop in o) {
		a[i]= prop  + "\t"; // + " = " + o[prop]
		i++;
 }
 a.sort();
 return a;
}
