// retourne un objet xmlHttpRequest.
// méthode compatible entre tous les navigateurs (IE/Firefox/Opera)
function getXMLHTTP(){
	var xhr=null;
	if(window.XMLHttpRequest) // Firefox et autres
	xhr = new XMLHttpRequest();
	else if(window.ActiveXObject){ // Internet Explorer
		try {
			xhr = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xhr = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e1) {
				xhr = null;
			}
		}
	}
	else { // XMLHttpRequest non supporté par le navigateur
		alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest...");
	}
	return xhr;
}


var _inputField=new Array(); // le champ texte lui-même
var _inputType = new Array();
var _nbSuggestions=0; //Nombre de champs texte 
	
function initAutoComplete(field, type){
	_inputField.push(field);
	_inputField[_nbSuggestions].autocomplete="off";
	_inputType.push(type);
	creeAutocompletionDiv(_nbSuggestions);
	_currentInputFieldValue.push(_inputField.value);
	_oldInputFieldValue.push(_currentInputFieldValue[_nbSuggestions]);
	cacheResults("",new Array())
	document.onkeydown=onKeyDownHandler;
	_inputField[_nbSuggestions].onkeyup=onKeyUpHandler;
	_inputField[_nbSuggestions].onblur=onBlurHandler;
	window.onresize=onResizeHandler;
	_nbSuggestions++;
	// Premier déclenchement de la fonction dans 200 millisecondes
	setTimeout("mainLoop()",200)
}

var _oldInputFieldValue=new Array(); // valeur précédente du champ texte
var _currentInputFieldValue=new Array(); // valeur actuelle du champ texte
var _resultCache=new Object(); // mécanisme de cache des requetes

// tourne en permanence pour suggerer suite à un changement du champ texte
function mainLoop(){
	for(i=0; i<_nbSuggestions; i++)
	{
		if(_oldInputFieldValue[i]!=_currentInputFieldValue[i]){
			var valeur=escapeURI(_currentInputFieldValue[i]);
			var suggestions=_resultCache[_currentInputFieldValue[i]];
			if(suggestions){ // la réponse était encore dans le cache
				metsEnPlace(valeur,suggestions,i)
			}else{
				callSuggestions(valeur,i) // appel distant
			}
			_inputField[i].focus();
			_oldInputFieldValue[i]=_currentInputFieldValue[i];
		}
	}	
	setTimeout("mainLoop()",200); // la fonction se redéclenchera dans 200 ms
	return true
}

function reInitCache()
{
	_resultCache=new Object();
	cacheResults("",new Array());
}

// echappe les caractère spéciaux
function escapeURI(La){
	if(encodeURIComponent) {
		return encodeURIComponent(La);
	}
	if(escape) {
		return escape(La)
	}
}

var _xmlHttp = new Array(); //l'objet xmlHttpRequest utilisé pour contacter le serveur

function callSuggestions(valeur, i){
	if(_xmlHttp[i]&&_xmlHttp[i].readyState!=0){
		_xmlHttp[i].abort()
	}
	_xmlHttp[i]=getXMLHTTP();
	if(_xmlHttp[i]){
		//appel à l'url distante
		if(_inputType[i] == 'A')
			_xmlHttp[i].open("GET","ajax/suggestion.ajax.php?debut="+valeur+"&type=alliance&serveur="+document.getElementsByName('serveur')[0].value,true);
		else if(_inputType[i] == 'J')
			_xmlHttp[i].open("GET","ajax/suggestion.ajax.php?debut="+valeur+"&type=joueur&serveur="+document.getElementsByName('serveur')[0].value,true);
		else if(_inputType[i] == 'V')
			_xmlHttp[i].open("GET","ajax/suggestion.ajax.php?debut="+valeur+"&type=village&serveur="+document.getElementsByName('serveur')[0].value,true);
		_xmlHttp[i].onreadystatechange=function() {
			if(_xmlHttp[i].readyState==4&&_xmlHttp[i].responseXML) {
				var liste = traiteXmlSuggestions(_xmlHttp[i].responseXML)
				cacheResults(valeur,liste)
				metsEnPlace(valeur,liste,i)
			}
		};
		// envoi de la requete
		_xmlHttp[i].send(null)
	}
}

// Mecanisme de caching des réponses
function cacheResults(debut,suggestions){
	_resultCache[debut]=suggestions
}

// Transformation XML en tableau
function traiteXmlSuggestions(xmlDoc) {
	var options = xmlDoc.getElementsByTagName('option');
	var optionsListe = new Array();
	for (var i=0; i < options.length; ++i) {
		optionsListe.push(options[i].firstChild.data);
	}
	return optionsListe;
}

function setStylePourElement(c,name){
	c.className=name;
}

// calcule le décalage à gauche
function calculateOffsetLeft(r){
	return calculateOffset(r,"offsetLeft")
}

// calcule le décalage vertical
function calculateOffsetTop(r){
	return calculateOffset(r,"offsetTop")
}

function calculateOffset(r,attr){
	var kb=0;
	while(r){
		kb+=r[attr];
		r=r.offsetParent
	}
	return kb
}

// calcule la largeur du champ
function calculateWidth(i){
	return _inputField[i].offsetWidth-2*1
}

var _completeDiv = new Array();

function setCompleteDivSize(i){
	if(_completeDiv[i]){
		_completeDiv[i].style.left=calculateOffsetLeft(_inputField[i])+"px";
		_completeDiv[i].style.top=calculateOffsetTop(_inputField[i])+_inputField[i].offsetHeight-1+"px";
		_completeDiv[i].style.width=calculateWidth(i)+"px"
	}
}

function creeAutocompletionDiv(i) {
	_completeDiv[i]=document.createElement("DIV");
	_completeDiv[i].id="completeDiv";
	var borderLeftRight=1;
	var borderTopBottom=1;
	_completeDiv[i].style.borderRight="black "+borderLeftRight+"px solid";
	_completeDiv[i].style.borderLeft="black "+borderLeftRight+"px solid";
	_completeDiv[i].style.borderTop="black "+borderTopBottom+"px solid";
	_completeDiv[i].style.borderBottom="black "+borderTopBottom+"px solid";
	_completeDiv[i].style.zIndex="1";
	_completeDiv[i].style.paddingRight="0";
	_completeDiv[i].style.paddingLeft="0";
	_completeDiv[i].style.paddingTop="0";
	_completeDiv[i].style.paddingBottom="0";
	setCompleteDivSize(i);
	_completeDiv[i].style.visibility="hidden";
	_completeDiv[i].style.position="absolute";
	_completeDiv[i].style.backgroundColor="white";
	document.body.appendChild(_completeDiv[i]);
	setStylePourElement(_completeDiv[i],"AutoCompleteDivListeStyle");
}

function metsEnPlace(valeur, liste, i){
	while(_completeDiv[i].childNodes.length>0) {
		_completeDiv[i].removeChild(_completeDiv[i].childNodes[0]);
	}
	// mise en place des suggestions
	for(var f=0; f<liste.length; ++f){
		var nouveauDiv=document.createElement("DIV");
		nouveauDiv.onmousedown=divOnMouseDown;
		nouveauDiv.onmouseover=divOnMouseOver;
		nouveauDiv.onmouseout=divOnMouseOut;
		nouveauDiv.name = i;
		setStylePourElement(nouveauDiv,"AutoCompleteDiv");
		var nouveauSpan=document.createElement("SPAN");
		nouveauSpan.innerHTML=liste[f]; // le texte de la suggestion
		nouveauDiv.appendChild(nouveauSpan);
		_completeDiv[i].appendChild(nouveauDiv)
	}
	PressAction(i);
	if(_completeDivRows[i]>0) {
		_completeDiv[i].height=16*_completeDivRows[i]+4;
	} else {
		hideCompleteDiv(i);
	}

}

var _lastKeyCode=null;

// Handler pour le keydown du document
var onKeyDownHandler=function(event){
	// accès evenement compatible IE/Firefox
	if(!event&&window.event) {
		event=window.event;
	}
	// on enregistre la touche ayant déclenché l'evenement
	if(event) {
		_lastKeyCode=event.keyCode;
	}
}

var _eventKeycode = null;

// Handler pour le keyup de lu champ texte
var onKeyUpHandler=function(event){
	for(i=0; i<=_nbSuggestions; i++)
	{
		if(_inputField[i] == this)
			break;
	}
	
	// accès evenement compatible IE/Firefox
	if(!event&&window.event) {
		event=window.event;
	}
	_eventKeycode=event.keyCode;
	// Dans les cas touches touche haute(38) ou touche basse (40)
	if(_eventKeycode==40||_eventKeycode==38) {
		// on autorise le blur du champ (traitement dans onblur)
		blurThenGetFocus();
	}
	// taille de la selection
	var N=rangeSize(_inputField[i]);
	// taille du texte avant la selection (selection = suggestion d'autocomplétion)
	var v=beforeRangeSize(_inputField[i]);
	// contenu du champ texte
	var V=_inputField[i].value;
	if(_eventKeycode!=0){
		if(N>0&&v!=-1) {
			// on recupere uniquement le champ texte tapé par l'utilisateur
			V=V.substring(0,v);
		}
		// 13 = touche entrée
		if(_eventKeycode==13||_eventKeycode==3){
			var d=_inputField[i];
			// on mets en place l'ensemble du champ texte en repoussant la selection
			if(_inputField[i].createTextRange){
				var t=_inputField[i].createTextRange();
				t.moveStart("character",_inputField[i].value.length);
				_inputField[i].select()
			} else if (d.setSelectionRange){
				_inputField[i].setSelectionRange(_inputField[i].value.length,_inputField[i].value.length)
			}
		} else {
			// si on a pas pu agrandir le champ non selectionné, on le mets en place violemment.
			if(_inputField[i].value!=V) {
				_inputField[i].value=V
			}
		}
	}
	// si la touche n'est ni haut, ni bas, on stocke la valeur utilisateur du champ
	if(_eventKeycode!=40&&_eventKeycode!=38) {
		// le champ courant n est pas change si key Up ou key Down
		_currentInputFieldValue[i]=V;
	}
	if(handleCursorUpDownEnter(_eventKeycode, i)&&_eventKeycode!=0) {
		// si on a préssé une touche autre que haut/bas/enter
		PressAction(i);
	}
}

// Change la suggestion selectionné.
// cette méthode traite les touches haut, bas et enter
function handleCursorUpDownEnter(eventCode, i){
	if(eventCode==40){
		highlightNewValue(_highlightedSuggestionIndex[i]+1, i);
		return false
	}else if(eventCode==38){
		highlightNewValue(_highlightedSuggestionIndex[i]-1, i);
		return false
	}else if(eventCode==13||eventCode==3){
		return false
	}
	return true
}

var _completeDivRows = new Array();
var _completeDivDivList = new Array();
var _highlightedSuggestionIndex = new Array();
var _highlightedSuggestionDiv = new Array();

// gère une touche pressée autre que haut/bas/enter
function PressAction(i){
	_highlightedSuggestionIndex[i]=-1;
	var suggestionList=_completeDiv[i].getElementsByTagName("div");
	var suggestionLongueur=suggestionList.length;
	// on stocke les valeurs précédentes
	// nombre de possibilités de complétion
	_completeDivRows[i]=suggestionLongueur;
	// possiblités de complétion
	_completeDivDivList[i]=suggestionList;
	// si le champ est vide, on cache les propositions de complétion
	if(_currentInputFieldValue[i]==""||suggestionLongueur==0){
		hideCompleteDiv(i)
	}else{
		showCompleteDiv(i)
	}
	var trouve=false;
	// si on a du texte sur lequel travailler
	if(_currentInputFieldValue[i].length>0){
		var indice;
		// T vaut true si on a dans la liste de suggestions un mot commencant comme l'entrée utilisateur
		for(indice=0; indice<suggestionLongueur; indice++){
			if(getSuggestion(suggestionList.item(indice)).toUpperCase().indexOf(_currentInputFieldValue[i].toUpperCase())==0) {
				trouve=true;
				break
			}
		}
	}
	// on désélectionne toutes les suggestions
	for(var j=0; j<suggestionLongueur; j++) {
		setStylePourElement(suggestionList.item(j),"AutoCompleteDiv");
	}
	// si l'entrée utilisateur (n) est le début d'une suggestion (n-1) on sélectionne cette suggestion avant de continuer
	if(trouve){
		_highlightedSuggestionIndex[i]=indice;
		_highlightedSuggestionDiv[i]=suggestionList.item(_highlightedSuggestionIndex[i]);
	}else{
		_highlightedSuggestionIndex[i]=-1;
		_highlightedSuggestionDiv[i]=null
	}
	var supprSelection=false;
	switch(_eventKeycode){
		// cursor left, cursor right, page up, page down, others??
		case 8:
		case 33:
		case 34:
		case 35:
		case 35:
		case 36:
		case 37:
		case 39:
		case 45:
		case 46:
			// on supprime la suggestion du texte utilisateur
			supprSelection=true;
			break;
		default:
			break
	}
	// si on a une suggestion (n-1) sélectionnée
	if(!supprSelection&&_highlightedSuggestionDiv[i]){
		setStylePourElement(_highlightedSuggestionDiv[i],"AutoCompleteDivAct");
		var z;
		if(trouve) {
			z=getSuggestion(_highlightedSuggestionDiv[i]).substr(0);
		} else {
			z=_currentInputFieldValue[i];
		}
		
		if(z!=_inputField[i].value){
			if(_inputField[i].value!=_currentInputFieldValue[i]) {
				return;
			}
			// si on peut créer des range dans le document
			if(_inputField[i].createTextRange||_inputField[i].setSelectionRange) {
				_inputField[i].value=z;
			}
			// on sélectionne la fin de la suggestion
			if(_inputField[i].createTextRange){
				var t=_inputField[i].createTextRange();
				t.moveStart("character",_currentInputFieldValue[i].length);
				t.select()
			}else if(_inputField[i].setSelectionRange){
				_inputField[i].setSelectionRange(_currentInputFieldValue[i].length,_inputField[i].value.length)
			}
		}
	}else{
		// sinon, plus aucune suggestion de sélectionnée
		_highlightedSuggestionIndex[i]=-1;
	}
}

var _cursorUpDownPressed = new Array();

// permet le blur du champ texte après que la touche haut/bas ai été pressé.
// le focus est récupéré après traitement (via le timeout).
function blurThenGetFocus(){
	_cursorUpDownPressed[i]=true;
	_inputField[i].blur();
	setTimeout("_inputField.focus();",10);
	return
}

// taille de la selection dans le champ input
function rangeSize(n){
	var N=-1;
	if(n.createTextRange){
		var fa=document.selection.createRange().duplicate();
		N=fa.text.length
	}else if(n.setSelectionRange){
		N=n.selectionEnd-n.selectionStart
	}
	return N
}

// taille du champ input non selectionne
function beforeRangeSize(n){
	var v=0;
	if(n.createTextRange){
		var fa=document.selection.createRange().duplicate();
		fa.moveEnd("textedit",1);
		v=n.value.length-fa.text.length
	}else if(n.setSelectionRange){
		v=n.selectionStart
	}else{
		v=-1
	}
	return v
}

// Place le curseur à la fin du champ
function cursorAfterValue(n){
	if(n.createTextRange){
		var t=n.createTextRange();
		t.moveStart("character",n.value.length);
		t.select()
	} else if(n.setSelectionRange) {
		n.setSelectionRange(n.value.length,n.value.length)
	}
}


// Retourne la valeur de la possibilite (texte) contenu dans une div de possibilite
function getSuggestion(uneDiv){
	if(!uneDiv) {
		return null;
	}
	return trimCR(uneDiv.getElementsByTagName('span')[0].firstChild.data)
}

// supprime les caractères retour chariot et line feed d'une chaine de caractères
function trimCR(chaine){
	for(var f=0,nChaine="",zb="\n\r"; f<chaine.length; f++) {
		if (zb.indexOf(chaine.charAt(f))==-1) {
			nChaine+=chaine.charAt(f);
		}
	}
	return nChaine
}

// Cache completement les choix de completion
function hideCompleteDiv(i){
	_completeDiv[i].style.visibility="hidden"
}

// Rends les choix de completion visibles
function showCompleteDiv(i){
	_completeDiv[i].style.visibility="visible";
	setCompleteDivSize(i)
}

// Change la suggestion en surbrillance
function highlightNewValue(C, i){
	if(!_completeDivDivList[i]||_completeDivRows[i]<=0) {
		return;
	}
	showCompleteDiv();
	if(C>=_completeDivRows[i]){
		C=_completeDivRows[i]-1
	}
	if(_highlightedSuggestionIndex[i]!=-1&&C!=_highlightedSuggestionIndex[i]){
		setStylePourElement(_highlightedSuggestionDiv[i],"AutoCompleteDiv");
		_highlightedSuggestionIndex[i]=-1
	}
	if(C<0){
		_highlightedSuggestionIndex[i]=-1;
		_inputField[i].focus();
		return
	}
	_highlightedSuggestionIndex[i]=C;
	_highlightedSuggestionDiv[i]=_completeDivDivList[i].item(C);
	setStylePourElement(_highlightedSuggestionDiv[i],"AutoCompleteDivAct");
	_inputField[i].value=getSuggestion(_highlightedSuggestionDiv[i]);
}

// Handler de resize de la fenetre
var onResizeHandler=function(event){
	// recalcule la taille des suggestions
	setCompleteDivSize(this.name);
}

// Handler de blur sur le champ texte
var onBlurHandler=function(event){
	for(i=0; i<=_nbSuggestions; i++)
	{
		if(_inputField[i] == this)
			break;
	}
	if(!_cursorUpDownPressed[i]){
		// si le blur n'est pas causé par la touche haut/bas
		hideCompleteDiv(i);
	}
	_cursorUpDownPressed[i]=false
};

// declenchee quand on clique sur une div contenant une possibilite
var divOnMouseDown=function(){
	_inputField[this.name].value=getSuggestion(this);
	hideCompleteDiv(this.name);
};

// declenchee quand on passe sur une div de possibilite. La div précédente est passee en style normal
var divOnMouseOver=function(){
	if(_highlightedSuggestionDiv[this.name]) {
		setStylePourElement(_highlightedSuggestionDiv[this.name],"AutoCompleteDiv");
	}
	setStylePourElement(this,"AutoCompleteDivAct")
};

// declenchee quand la sourie quitte une div de possiblite. La div repasse a l'etat normal
var divOnMouseOut = function(){
	setStylePourElement(this,"AutoCompleteDiv");
};