var oFiltre = null;
var bDebug = false;

function RefreshFiltres(_oFiltre)
{
	oFiltre = _oFiltre;
	UpdateFiltreDisplay();
}

function UpdateFiltreDisplay()
{
	if (oFiltre == null)
	{
		oFiltreManager = new FiltreManager();
		oFiltreManager.Init(window.opener.document.getElementById('filtre_data'));
	}
	var oSelection = new FiltreSelection();
	var sDisplay = oSelection.Display(oFiltre);
	var oDiv = window.opener.document.getElementById('filtre_display');
	if (sDisplay.length == 0)
	{
		sDisplay = '<p>Aucun filtre sélectionné.</p>';
	}
	oDiv.innerHTML = sDisplay;
}


function SortedMap()
{
	this.aArray = new Array();

	//=================================================================
	// METHODE : Put(sKey, oValue)
	//-----------------------------------------------------------------
	// DESCRIPTION : Ajoute un élément dans la Map triée
	//-----------------------------------------------------------------
	// PARAM : sKey, clé de l'élément
	// PARAM : oValue, valeur de l'élément
	// RETURN : void
	//=================================================================
	this.Put = function(sKey, oValue)
	{
		var aKey = new String(sKey).split(';;');

		var oNewItem = new Item(sKey, oValue);

		var iIndex = this.Size();
		var oCurrentItem = null;
		var aCurrentKey = null;

		//on fait un premier parcours pour déterminer si on ajoute ou update
		var bUpdate = false;

		for(var j=0; j<iIndex;j++){
			oCurrentItem = this.GetItem(j);
			aCurrentKey = new String(oCurrentItem.sKey).split(';;');
			if (aCurrentKey[0] == aKey[0]){//le code existe c'est un update
				bUpdate = true;
				break;
			}
		}

		// on parcourt la liste en partant de la fin			
		while (iIndex > 0)
		{
			iIndex--;
			oCurrentItem = this.GetItem(iIndex);
			aCurrentKey = new String(oCurrentItem.sKey).split(';;');
			//alert('SortedMap.Put()... item[' + iIndex + '] = ' + oCurrentItem.sKey);
			if (aCurrentKey[0] == aKey[0])
			{
				//alert('SortedMap.Put()... item ' + sKey + ' already in list');
				//return; // l'élément est déjà dans la liste, on ne l'ajoute pas
				//on remplace l'élément
				break;
			}
			else if(!bUpdate){

				if (aCurrentKey[1] > aKey[1])
				{
					// on décale les éléments de la liste pour faire une place pour le petit nouveau
					this.SetItem(iIndex + 1, oCurrentItem);
					//alert('SortedMap.Put()... on decale : new size = '+this.Size());
				}
				else
				{
					// on a trouvé la bonne position, on sort de la boucle
					iIndex++;
					break;
				}
			}
		}

		// on ajoute l'élément à la bonne position
		this.SetItem(iIndex, oNewItem);
		//alert('SortedMap.Put()... setItem(' + iIndex + ', ' + sKey + ')');
	}

	//-----------------------------------------------------------------
	// METHODE : Remove(sKey)
	//-----------------------------------------------------------------
	// DESCRIPTION : Supprime un élément de la Map en fonction de sa clé
	//-----------------------------------------------------------------
	// PARAM : sKey, clé de l'élément à supprimer
	// RETURN : boolean, true si élément supprimé / false si élément non trouvé
	//-----------------------------------------------------------------
	this.Remove = function(sKey)
	{
		//alert('SortedMap.Remove()... sKey = ' + sKey);
		var bFound = false;
		for (var i = 0; i < this.Size(); i++)
		{
			//alert('SortedMap.Remove()... getItem(' + i + ') = ' + this.GetItem(i).sKey);
			if (this.GetItem(i).sKey == sKey)
			{
				// on a trouvé l'élément à supprimer
				bFound = true;
				//alert('SortedMap.Remove()... item found, index = ' + i);
			}
			if (bFound)
			{
				if (i < this.Size() - 1)
				{
					//alert('SortedMap.Remove()... on décale les éléments');
					//alert('SortedMap.Remove()... getItem(' + i + ') = ' + this.GetItem(i).sKey);
					this.SetItem(i, this.GetItem(i + 1));
					//alert('SortedMap.Remove()... getItem(' + i + ') = ' + this.GetItem(i).sKey);
				}
				else
				{
					//alert('SortedMap.Remove()... list size = ' + this.Size());
					this.aArray[i] = null;
					this.aArray.length--;
					//alert('SortedMap.Remove()... list size = ' + this.Size());
				}
			}
		}
		return bFound;
	}

	this.Contains = function(sKey)
	{
		//alert('SortedMap.Remove()... sKey = ' + sKey);
		var bFound = false;
		for (var i = 0; i < this.Size(); i++)
		{
			//alert('SortedMap.Remove()... getItem(' + i + ') = ' + this.GetItem(i).sKey);
			if (this.GetItem(i).sKey == sKey)
			{
				// on a trouvé l'élément à supprimer
				bFound = true;
				//alert('SortedMap.Remove()... item found, index = ' + i);
			}
		}
		return bFound;
	}

	this.Size = function()
	{
		return this.aArray.length;
	}

	this.IsEmpty = function()
	{
		return (this.Size() == 0);
	}

	this.Iterator = function()
	{
		return new IteratorFiltre(this);
	}

	//--- METHODES PRIVEES

	this.GetItem = function(i)
	{
		var oItem = null;
		if (i < this.Size())
		{
			oItem = this.aArray[i];
		}
		return oItem;
	}

	this.SetItem = function(i, oItem)
	{
		if (i <= this.Size())
		{
			this.aArray[i] = oItem;
		}
	}

	this.ToString = function()
	{
		var s = '';
		for(i=0;i<this.Size();i++){
			s += 'Item '+i+': '+ this.GetItem(i).ToString() + '\n';
		}
		return s;
	}
}

function Item(sKey, oValue)
{
	this.sKey = sKey;
	this.oValue = oValue;

	this.ToString = function(){

		return this.oValue.ToString();
	}
}

function IteratorFiltre(oSortedMap)
{
	this.oSortedMap = oSortedMap;
	this.iPos = 0;

	this.HasNext = function()
	{
		return this.iPos < this.oSortedMap.Size();
	}

	this.Next = function()
	{
		return this.oSortedMap.GetItem(this.iPos++).oValue;
	}
}

function FiltreEntry(sId, sCode, sLabel, iType, oParent)
{
	this.sId = sId;
	this.sCode = sCode;

	this.sLabel = sLabel;
	this.iType = iType;
	this.bSelected = (oParent ? oParent.bSelected : false);
	this.oParent = (oParent ? oParent : null);
	this.oChildren = new SortedMap();
	this.oSelectedChildren = new SortedMap();
	this.bIsNiveau = (iType == 'NIV');
	this.bIsDiscipline = (iType == 'DISC');
	this.bIsEntree = (iType == 'ENT');
	this.bIsLibelle2 = (iType == 'LIB2');
	this.bIsLibelle = (this.bIsLibelle2 || (iType == 'LIB1'));

	this.AddChild = function(sId, sCode, sLabel, iType)
	{

		var oEntry = new FiltreEntry(sId, sCode, sLabel, iType, this);
		this.oChildren.Put(oEntry.sCode+';;'+oEntry.sLabel, oEntry);
		if (this.bSelected)
		{
			oEntry.SelectEntry(true);
		}
		//alert('AddChild()... ' + this.sLabel + ' : \n ==> ' + oEntry.ToString());
		return oEntry;
	}

	this.Remove = function()
	{
		var bRemoved = this.oParent.oChildren.Remove(this.sCode+';;'+this.sLabel);
		if (bRemoved)
		{
			this.oParent.oSelectedChildren.Remove(this.sCode+';;'+this.sLabel);
		}
	}

	this.UpdateLabel = function(sLabel)
	{
		this.sLabel = sLabel;
	}

	this.SelectEntry = function(bSelected)
	{
		//alert('ThesaurusEntry.SelectEntry()... ' + this.sLabel);
		this.bSelected = bSelected;
		// on sélectionne/désélectionne tous les fils
		var oIterator = this.oChildren.Iterator();
		while (oIterator.HasNext())
		{
			oIterator.Next().SelectChild(bSelected);
		}
		// on met à jour le père
		var oEntry = this;
		//alert('ThesaurusEntry.SelectEntry()... ' + oEntry.sLabel);
		while (oEntry.oParent != null)
		{
			if (bSelected)
			{
				//alert('ThesaurusEntry.SelectEntry()... '+oEntry.sLabel+' : oParent.oSelectedChildren.Size = '+oEntry.oParent.oSelectedChildren.Size());
				oEntry.oParent.oSelectedChildren.Put(oEntry.sCode+';;'+oEntry.sLabel, oEntry);
				if (oEntry.bSelected && oEntry.oParent.oSelectedChildren.Size() == oEntry.oParent.oChildren.Size())
				{
					oEntry.oParent.bSelected = true;
				}
			}
			else
			{
				//alert('SelectEntry()... '+oEntry.sLabel+' : oParent.oSelectedChildren.Size = '+oEntry.oParent.oSelectedChildren.Size());
				oEntry.oParent.bSelected = false;
				if (oEntry.oSelectedChildren.Size() == 0)
				{
					oEntry.oParent.oSelectedChildren.Remove(oEntry.sCode+';;'+oEntry.sLabel);
				}
			}
			oEntry = oEntry.oParent;
		}
	}

	// sélectionne sans mettre à jour le père
	this.SelectChild = function(bSelected)
	{
		this.bSelected = bSelected;
		if(bSelected)
			this.oParent.oSelectedChildren.Put(this.sCode+';;'+this.sLabel, this);
		else
			this.oParent.oSelectedChildren.Remove(this.sCode+';;'+this.sLabel);
		// on sélectionne/désélectionne tous les fils
		var oIterator = this.oChildren.Iterator();
		while (oIterator.HasNext())
		{
			oIterator.Next().SelectChild(bSelected);
		}
	}

	this.ToString = function()
	{
		var s = '';
		s += '<entry code="' + this.sCode;
		if (this.oParent != null)
			s += '" code-parent="' + this.oParent.sCode;
		s += '" type= "' + this.iType;
		s += '">' + this.sLabel + '</entry>';
		return s;
	}

	this.GetNbChildren = function()
	{
		return this.oChildren.Size();
	}
}

function XmlHttp()
{
	this.oXmlHttp = null;

	this.Init = function()
	{
		try
		{
			this.oXmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); // IE
		}
		catch (e)
		{
			try
			{
				this.oXmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); // IE
			}
			catch (e) {}
		}
		if (this.oXmlHttp == null && typeof XMLHttpRequest != 'undefined')
		{
			this.oXmlHttp = new XMLHttpRequest(); // FF
		}
	}

	// Envoi d'une requete au serveur
	this.SendRequest = function(sUrl, bDebug)
	{
	    this.oXmlHttp.open("GET", sUrl, false); // false = SYNCHRONE / true = ASYNCHRONE
		this.oXmlHttp.send(null);

		var oXmlResponse = null;
		if (this.oXmlHttp.readyState == 4 && this.oXmlHttp.status == 200)
		{
			oXmlResponse = this.oXmlHttp.responseXML;
			if (bDebug)
			{
				alert(this.oXmlHttp.responseText);
			}
		}
		else
		{
			alert('ERREUR : HTTP ' + this.oXmlHttp.status + '\nURL demandée :\n' + sUrl);
		}
		return oXmlResponse;
	}
}


function XmlNodeProcessor()
{
	this.FirstChild = function(oCurrentNode)
	{
		var oNode = oCurrentNode.firstChild; // IE
		if (oNode != null)
		{
			if (oNode.nodeType != 1) // Node.ELEMENT_NODE
			{
				if (oNode.nodeType == 3) // Node.TEXT_NODE
				{
					// FF : on prend le noeud suivant
					oNode = oNode.nextSibling;
				}
				else
				{
					alert('XmlNodeProcessor.FirstChild()...\nEVENEMENT NON PREVU : nodeType = ' + oNode.nodeType);
				}
			}
		}
		return oNode;
	}
	this.LastChild = function(oCurrentNode)
	{
		var oNode = oCurrentNode.lastChild; // IE
		
		if (oNode != null)
		{
			if (oNode.nodeType != 1) // Node.ELEMENT_NODE
			{
				if (oNode.nodeType == 3) // Node.TEXT_NODE
				{
					// FF : on prend le noeud précédent
					
					oNode = oNode.previousSibling;
				}
				else
				{
					alert('XmlNodeProcessor.LastChild()...\nEVENEMENT NON PREVU : nodeType = ' + oNode.nodeType);
				}
			}
		}
		return oNode;
	}
	this.Next = function(oCurrentNode)
	{
		var oNode = oCurrentNode.nextSibling; // IE
		if (oNode != null)
		{
			if (oNode.nodeType != 1) // Node.ELEMENT_NODE
			{
				if (oNode.nodeType == 3) // Node.TEXT_NODE
				{
					// FF : on prend le noeud suivant
					oNode = oNode.nextSibling;
				}
				else
				{
					alert('XmlNodeProcessor.Next()...\nEVENEMENT NON PREVU : nodeType = ' + oNode.nodeType);
				}
			}
		}
		return oNode;
	}
	this.Previous = function(oCurrentNode)
	{
		var oNode = oCurrentNode.previousSibling; // IE
		if (oNode != null)
		{
			if (oNode.nodeType != 1) // Node.ELEMENT_NODE
			{
				if (oNode.nodeType == 3) // Node.TEXT_NODE
				{
					// FF : on prend le noeud suivant
					oNode = oNode.previousSibling;
				}
				else
				{
					alert('XmlNodeProcessor.Next()...\nEVENEMENT NON PREVU : nodeType = ' + oNode.nodeType);
				}
			}
		}
		return oNode;
	}
	this.GetText = function(oCurrentNode)
	{
		if (oCurrentNode == null)
		{
			throw ('XmlNodeProcessor.GetText()... oCurrentNode = null');
		}
		var sText = oCurrentNode.textContent; // FF
		
		if (! sText)
		{
			sText = oCurrentNode.text; // IE
			
			if(!sText)
				return '';
		}
		return sText;
	}
}

function XmlDataProcessor(oParent, oParentEntryNode, bTop)
{
	this.oXmlNodeProcessor = new XmlNodeProcessor();
	this.oParent = oParent;
	this.oFirstEntryNode = this.oXmlNodeProcessor.FirstChild(oParentEntryNode);
	if (! bTop) // il n'y a pas de libellé pour l'élément le plus haut
	{
		this.oFirstEntryNode = this.oXmlNodeProcessor.Next(this.oFirstEntryNode);
	}
	//alert('this.oFirstEntryNode : ' + this.oFirstEntryNode.nodeName + ' = ' + this.oXmlNodeProcessor.GetText(this.oFirstEntryNode));
	this.oLastEntryNode = this.oXmlNodeProcessor.LastChild(oParentEntryNode);
	//alert('this.oLastEntryNode : ' + this.oLastEntryNode.nodeName + ' = ' + this.oXmlNodeProcessor.GetText(this.oLastEntryNode));
	this.oCurrentEntryNode = null;

	this.HasNextEntry = function()
	{
		return (this.oCurrentEntryNode == null ? this.oFirstEntryNode != null : this.oCurrentEntryNode != this.oLastEntryNode);
	}

	this.NextEntry = function()
	{
		if (this.oCurrentEntryNode == null)
		{
			this.oCurrentEntryNode = this.oFirstEntryNode;
		}
		else
		{
			this.oCurrentEntryNode = this.oXmlNodeProcessor.Next(this.oCurrentEntryNode);
		}
		//alert(this.oCurrentEntryNode.nodeName);
		return this.oCurrentEntryNode;
	}
	this.LoadEntries = function()
	{
		var oEntryNode = null;
		var oEntry = null;
		var oEntryChildNode = null;
		var oXmlDataProcessor = null;
		while (this.HasNextEntry())
		{
			// charge l'élément
			oEntryNode = this.NextEntry();
			
			if (oEntryNode.getAttribute('id')!=null) {
			
				oEntry = oParent.AddChild(oEntryNode.getAttribute('id'), oEntryNode.getAttribute('code'), this.GetLibelle(oEntryNode),oEntryNode.getAttribute('type'));
	
				if (this.HasChildEntryNodes(oEntryNode)) {
					// charge ses fils
					oXmlDataProcessor = new XmlDataProcessor(oEntry, oEntryNode, false);
					oXmlDataProcessor.LoadEntries();
				}
			}
		}
	}

	this.HasChildEntryNodes = function(oEntryNode)
	{
		var oChildEntryNode = this.oXmlNodeProcessor.FirstChild(oEntryNode); // libelle
		oChildEntryNode = this.oXmlNodeProcessor.Next(oChildEntryNode); // child
		//alert(this.GetLibelle(oEntryNode) + ': HasChildEntryNodes ? ' + oChildEntryNode != null);
		return (oChildEntryNode != null);
	}

	this.GetLibelle = function(oEntryNode)
	{
		var oLibelleNode = this.oXmlNodeProcessor.FirstChild(oEntryNode);

		//alert(oLibelleNode.nodeName + ' = ' + this.oXmlNodeProcessor.GetText(oLibelleNode));
		return this.oXmlNodeProcessor.GetText(oLibelleNode);
	}
}

function FiltreManager()
{
	this.oFiltre = new FiltreEntry('0', '0', 'Degré d\'enseignement', 'NIV');
	this.sMsg = '';

	//--- Objet XML-HTTP pour gérer les échanges avec le serveur
	this.oXmlHttp = new XmlHttp();
	this.sServletUrl = '/servlet/com.kosmos.ressourcepedagogique.processus.TraitementFiltre';

	this.Init = function(oFiltreSelection)
	{
		this.oFiltreSelection = oFiltreSelection;
		this.oXmlHttp.Init();
		this.LoadData();
		this.LoadSelection();
	}

	// charge le thesaurus

	this.LoadData = function()
	{
		var sUrl = this.sServletUrl + '?action=LOAD';
		this.PerformXmlRequest(sUrl, this.oFiltre);
	}

	// ajoute une entree au thesaurus

	this.AddEntry = function(oParent, sLabel, indice)
	{
		var type = '';oParent.iType;
		if( oParent.iType == 'DISC' )
			type = 'ENT';
		else if( oParent.iType == 'ENT' )
			type = 'LIB1';
		else if( oParent.iType == 'LIB1' )
			type = 'LIB2';

		var sUrl = this.sServletUrl +
			'?action=ADD' +
			'&code_parent=' + oParent.sCode +
			'&type=' + type +
			'&libelle=' + sLabel;
		
		//en cas d'ajout dune Entrée, on doit connaitre son rang (Entrée A ou B)
		if( type == 'ENT' )
			sUrl += '&indice=' + indice;

		this.PerformXmlRequest(sUrl, oParent);
	}

	this.RemoveEntry = function(oEntry)
	{
		var sUrl = this.sServletUrl +
			'?action=REMOVE' +
			'&id=' + oEntry.sId;
		this.PerformXmlRequest(sUrl, oEntry.oParent);
		oEntry.Remove();
	}

	this.UpdateLabel = function(oEntry, sLabel, oParent, indice)
	{
		var sUrl = this.sServletUrl + '?action=UPDATE';
		if( oEntry )
			sUrl += '&id=' + oEntry.sId;
		else
			sUrl += '&id=0' + '&code_parent=' + oParent.sCode + '&indice='+ indice;
		sUrl +=	'&libelle=' + sLabel;
		this.PerformXmlRequest(sUrl, oParent);
		oEntry.sLabel = sLabel;
	}

	this.LoadSelection = function()
	{
		// récupère les données dans le champ caché de la page appelante
		var sData = this.oFiltreSelection.value;

		var oSelection = new FiltreSelection();
		var iNbSelected = 0;
		var aSelectedEntries = sData.split(oSelection.sEntrySep);
		var sEntry = null;
		for (var i = 0; i < aSelectedEntries.length; i++)
		{
			sEntry = aSelectedEntries[i];
			iNbSelected += oSelection.Load(this.oFiltre, sEntry);
		}
		//alert('this.LoadSelection()... nbSelected = ' + iNbSelected);
	}

	// exécute la requête et met a jour le thesaurus coté client
	this.PerformXmlRequest = function(sUrl, oParent)
	{
		// lance la requête
		var oXmlResponse = this.oXmlHttp.SendRequest(sUrl, bDebug); // true = mode debug / false = mode normal

		// met a jour le thesaurus coté client
		if (oXmlResponse)
		{
			var oXmlNodeProcessor = new XmlNodeProcessor();
			var oCurrentNode = null;
			try
			{
				// récupère l'action effectuée
				oCurrentNode = oXmlNodeProcessor.FirstChild(oXmlResponse.documentElement); // action
				var sAction = oXmlNodeProcessor.GetText(oCurrentNode);
				//alert(oCurrentNode.nodeName + ' = ' + sAction);

				// récupère le code de retour (nb d'éléments affectés)
				oCurrentNode = oXmlNodeProcessor.Next(oCurrentNode); // return-code
				var sReturnCode = oXmlNodeProcessor.GetText(oCurrentNode);
				//alert(oCurrentNode.nodeName + ' = ' + sReturnCode);

				// gère un message d'erreur (si code retour = -1)
				this.SetMsg(sAction, sReturnCode);

				// met a jour le thesaurus coté client (ajout des nouveaux éléments)
				if (sAction != 'REMOVE')
				{
					// récupère les nouvelles données
					oCurrentNode = oXmlNodeProcessor.LastChild(oXmlResponse.documentElement); // data
					//alert(oCurrentNode.nodeName);

					var oXmlDataProcessor = new XmlDataProcessor(oParent, oCurrentNode, true);
					if( sAction != 'UPDATE')
						oXmlDataProcessor.LoadEntries();
				}
			}
			catch (e)
			{
				alert('Exception : ' + e + '\n ==> oXmlResponse.documentElement = \n' + oXmlResponse.documentElement.textContent);
			}
		}
	}

	// gère l'affichage d'un message
	this.SetMsg = function(sAction, sReturnCode)
	{
		this.sMsg = '[' + sAction + '] ';
		if (sReturnCode != -1)
		{
			var sMsgAdj = '';
			if (sAction == 'LOAD')
			{
				sMsgAdj += 'chargé';
			}
			else if (sAction == 'ADD')
			{
				sMsgAdj += 'ajouté';
			}
			else if (sAction == 'REMOVE')
			{
				sMsgAdj += 'supprimé';
			}
			this.sMsg += sReturnCode + (sReturnCode > 1 ? ' éléments ' + sMsgAdj + 's' : ' élément ' + sMsgAdj);
		}
		else
		{
			this.sMsg += 'Une erreur est survenue';
		}
	}
}

function FiltreGUI()
{
	// thesaurus
	this.oFiltreManager = new FiltreManager();

	// données de manipulation du thesaurus
	this.aParentItems = null;
	this.aChildItems = null;
	this.iSelectedItem = 0; // élément sélectionné

	// initialise l'observer
	this.Init = function(oParentDiv, oChildDiv, oAddEntryDiv, oParentTitle, oChildTitle, oOneLevelUpBtn, oNewEntryInput, oMsgSpan, oFiltreSelection, bModifiable)
	{
		// éléments d'affichage
		this.oParentDiv = oParentDiv;
		this.oChildDiv = oChildDiv;
		this.oAddEntryDiv = oAddEntryDiv;
		this.oParentTitle = oParentTitle;
		this.oChildTitle = oChildTitle;
		this.oOneLevelUpBtn = oOneLevelUpBtn;
		this.oNewEntryInput = oNewEntryInput;
		this.oMsgSpan = oMsgSpan;
		this.oFiltreSelection = oFiltreSelection;

		// initialisation du thesaurus
		this.oFiltreManager.Init(oFiltreSelection);
		this.bModifiable = bModifiable;
		if (this.bModifiable)
		{
			this.oAddEntryDiv.style.display = 'block';
		}
		this.PrintMsg(this.oFiltreManager.sMsg);
		this.LoadParentItems(this.oFiltreManager.oFiltre);
	}

	//=================================================================
	// METHODE : LoadParentItems(oEntry)
	//-----------------------------------------------------------------
	// DESCRIPTION : Charge les éléments de la liste de gauche
	//-----------------------------------------------------------------
	// PARAM : iLineId, id de l'élément dans la liste de gauche
	//=================================================================
	this.LoadParentItems = function(oEntry)
	{
		this.aParentItems = new Array();
		var iSelectedItem = 0;
		if (oEntry.oParent == null)
		{
			this.aParentItems[0] = oEntry;
			//alert('LoadParentItems :\nthis.aParentItems[0] ==> ' + oEntry.sLabel);
		}
		else
		{
			var oIterator = oEntry.oParent.oChildren.Iterator();
			var i = 0;
			while (oIterator.HasNext())
			{
				this.aParentItems[i] = oIterator.Next();
				//alert('LoadParentItems :\nthis.aParentItems['+i+'] ==> ' + this.aParentItems[i].sLabel);
				if (this.aParentItems[i] == oEntry)
				{
					iSelectedItem = i;
					//alert('LoadParentItems :\nSelectedItem ==> ' + this.aParentItems[i].sLabel);
				}
				i++;
			}
		}
		this.OpenParentEntry(iSelectedItem);
	}

	//=================================================================
	// METHODE : OpenParentEntry(iLineId)
	//-----------------------------------------------------------------
	// DESCRIPTION : Sélectionne un élément de gauche et rafraichit la liste
	//               de droite en conséquence
	//-----------------------------------------------------------------
	// PARAM : iLineId, id de l'élément dans la liste de gauche
	//=================================================================
	this.OpenParentEntry = function(iLineId)
	{
		// sélectionne l'élément de gauche
		this.iSelectedItem = iLineId;

		// rafraichit l'affichage de la div parente
		this.RefreshParentDiv();

		// rafraichit l'affichage de la div fille
		this.RefreshChildDisplay();
	}

	// rafraichit l'affichage à droite
	this.RefreshChildDisplay = function()
	{
		// met à jour la liste des éléments de droite en fonction de l'élément sélectionné à gauche
		this.aChildItems = new Array();
		var oIterator = this.GetSelectedEntry().oChildren.Iterator();
		//alert('RefreshChildDisplay : ' + this.GetSelectedEntry().sLabel + '\nthis.GetSelectedEntry().GetNbChildren() = ' + this.GetSelectedEntry().GetNbChildren());
		var i = 0;
		while (oIterator.HasNext())
		{
			this.aChildItems[i] = oIterator.Next();
			//alert('RefreshChildDisplay : ' + this.GetSelectedEntry().sLabel + '\nthis.aChildItems['+i+'] ==> ' + this.aChildItems[i].sLabel);
			i++;
		}
		//alert('ThesaurusGUI.RefreshChildDisplay()... nbChildSelected = ' + this.GetSelectedEntry().oSelectedChildren.Size());

		// rafraichit l'affichage
		this.RefreshChildDiv();
	}

	//=================================================================
	// METHODE : OpenChildEntry(iLineId)
	//-----------------------------------------------------------------
	// DESCRIPTION : Descend d'un niveau dans le thésaurus
	//-----------------------------------------------------------------
	// PARAM : iLineId, id de l'élément dans la liste de droite
	//=================================================================
	this.OpenChildEntry = function(iLineId)
	{
		// met à jour la liste de gauche
		this.aParentItems = this.aChildItems;

		// sélectionne l'élément de gauche et met à jour la liste de droite
		this.OpenParentEntry(iLineId);

		this.PrintMsg('');		
	}

	//=================================================================
	// METHODE : AddEntry(sLabel)
	//-----------------------------------------------------------------
	// DESCRIPTION : Ajoute une entrée pour l'élément sélectionné
	//-----------------------------------------------------------------
	// PARAM : sLabel, le nouveau libellé
	//=================================================================
	this.AddEntry = function()
	{
		this.oNewEntryInput = document.getElementById('new-entry');

		var sLabel = this.oNewEntryInput.value;

		if (sLabel.length > 0)
		{
			// ajoute l'élément au thesaurus
			this.oFiltreManager.AddEntry(this.GetSelectedEntry(), sLabel, -1);

			// rafraichit l'affichage à droite
			this.RefreshChildDisplay();
			this.PrintMsg(this.oFiltreManager.sMsg);
		}
		else
		{
			this.PrintMsg('ERREUR : Veuillez saisir un libellé pour cette nouvelle entrée !');
		}
		this.oNewEntryInput.value = '';
	}

	this.UpdateLabel = function() {

		//sélection des entrées
		var oEntryA = null;
		var oEntryB = null;
		var indiceA = null;
		var indiceB = null;
		
		for(i=0; i<=1; i++){

			var oEntry = this.aChildItems[i];

			if( oEntry ) {

				var code = new String(oEntry.sCode);
				var indice = code.substring( code.length-1, code.length);

				if( indice == 'A')
					oEntryA = oEntry;
				else if( indice == 'B')
					oEntryB = oEntry;
			}			
		}

		//Update enbtréeA
		var sLabel = document.getElementById('new-entry-0').value;

		if(oEntryA)
			//modif		
			this.oFiltreManager.UpdateLabel(oEntryA, sLabel,this.GetSelectedEntry(),0);
		else {
			//ajout
			// ajoute l'élément au thesaurus
			this.oFiltreManager.AddEntry(this.GetSelectedEntry(), sLabel, 0);
		}

		//Update enbtréeB
		var sLabel = document.getElementById('new-entry-1').value;

		if(oEntryA)
			//modif		
			this.oFiltreManager.UpdateLabel(oEntryB, sLabel,this.GetSelectedEntry(),1);
		else {
			//ajout
			// ajoute l'élément au thesaurus
			this.oFiltreManager.AddEntry(this.GetSelectedEntry(), sLabel, 1);
		}

		// rafraichit l'affichage à droite
		this.RefreshChildDisplay();
		this.PrintMsg(this.oFiltreManager.sMsg);
	}

	//=================================================================
	// METHODE : RemoveEntry(iLineId)
	//-----------------------------------------------------------------
	// DESCRIPTION : Supprime l'élément sélectionné
	//-----------------------------------------------------------------
	// PARAM : iLineId, le numéro de la ligne à supprimer
	//=================================================================
	this.RemoveEntry = function(iLineId, child)
	{
		var bConfirm = (confirm('Voulez vous supprimer l\'élément sélectionné ainsi que tous ses fils ?'));
		if (bConfirm)
		{
			// supprime l'élément et ses fils
			var oEntry = this.aChildItems[iLineId];

			if(child) {
				this.oFiltreManager.RemoveEntry(oEntry);
				this.RefreshChildDisplay();
			}
			else {
				oEntry = this.aParentItems[iLineId];
				this.oFiltreManager.RemoveEntry(oEntry);

				// rafraichit l'affichage
				if (iLineId == this.iSelectedItem) // on supprime l'élément sélectionné
				{
					if (this.aParentItems.length == 1) // un seul élément dans la liste
					{
						this.MoveOneLevelUp(oEntry);
					}
					else
					{
						if (iLineId == this.aParentItems.length - 1) // dernier élément de la liste
						{
							this.iSelectedItem--; // on sélectionne le précédent
						}
						else
						{
							this.iSelectedItem++; // on sélectionne le suivant
						}
						this.LoadParentItems(this.aParentItems[this.iSelectedItem]);
					}
				}
				else
				{
					this.LoadParentItems(this.GetSelectedEntry());
				}
			}
		}
		this.PrintMsg(this.oFiltreManager.sMsg);
	}

	//=================================================================
	// METHODE : MoveOneLevelUp(sLabel)
	//-----------------------------------------------------------------
	// DESCRIPTION : Ajoute une entrée pour l'élément sélectionné
	//-----------------------------------------------------------------
	// PARAM : sLabel, le nouveau libellé
	//=================================================================
	this.MoveOneLevelUp = function(oEntry)
	{
		if (! oEntry)
		{
			oEntry = this.GetSelectedEntry();
		}
		this.LoadParentItems(oEntry.oParent);
		this.PrintMsg('');
	}

	//=================================================================
	// METHODE : SelectEntry(sLabel)
	//-----------------------------------------------------------------
	// DESCRIPTION : Sélectionne un élément
	//-----------------------------------------------------------------
	// PARAM : sLabel, le nouveau libellé
	//=================================================================
	this.SelectEntry = function(bParent, iLineId, bChecked)
	{
		var oEntry = null;
		if (bParent)
		{
			oEntry = this.aParentItems[iLineId];
			oEntry.SelectEntry(bChecked);
			this.RefreshChildDiv();
		}
		else
		{
			oEntry = this.aChildItems[iLineId];
			oEntry.SelectEntry(bChecked);
			this.RefreshParentDiv();
		}
	}

	//=================================================================
	// METHODE : ReturnSelection()
	//-----------------------------------------------------------------
	// DESCRIPTION : Sélectionne un élément
	//-----------------------------------------------------------------
	// RETURN : la liste des éléments sélectionnés au format :
	//             ENTRY1##ENTRY2##ENTRY3##
	//          ou chaque entrée ENTRY est au format :
	//             racine__noeud1__noeud12__noeud123
	//=================================================================
	this.ReturnSelection = function()
	{
		var oSelection = new FiltreSelection();
		var sResult = oSelection.Print(this.oFiltreManager.oFiltre, '');

		// stocke le resultat dans le champ caché de la page appelante
		this.oFiltreSelection.value = sResult;

		// rafraichit l'affichage de la liste
		RefreshFiltres(this.oFiltreManager.oFiltre);

		// ferme le thesaurus
		window.close();
	}

	this.GetSelectedEntry = function()
	{
		return this.aParentItems[this.iSelectedItem];
	}

	this.RefreshParentDiv = function()
	{
		var top = (this.aParentItems[0] == this.oFiltreManager.oFiltre);
		this.oParentTitle.innerHTML = (top ? '' : this.aParentItems[0].oParent.sLabel);
		this.oOneLevelUpBtn.disabled = (top ? 'disabled' : '');
		var s = '';
		if (top)
		{
			s += '<p>Vous êtes au sommet de l\'arborescence.<br /><br />S&eacute;lectionnez une discipline dans la liste de droite pour acc&eacute;der aux différentes entr&eacute;es</p>';
		}
		else
		{
			s += '<ul>\n';			
			for (var i = 0; i < this.aParentItems.length; i++)
			{
				s += this.DisplayParentLine(i);
			}
			s += '</ul>\n';
		}
		this.oParentDiv.innerHTML = s;
	}

	this.DisplayParentLine = function(iLineId)
	{
		var oEntry = this.aParentItems[iLineId];

		var oSubEntry
		
		var isNotFinalNode = false
		var isSubNodeSelected = false
		
		isNotFinalNode = oEntry.oChildren.Iterator().HasNext();

		// Si l'item n'est pas selectionné on regarde si un de ses sous-noeuds est selectionné
		if ( ! oEntry.bSelected ) {
			var nbsselem = 0
			var oIterator = oEntry.oChildren.Iterator();
			while ( oIterator.HasNext()){
				oSubEntry = oIterator.Next();
				if ( oSubEntry.bSelected ) {
					isSubNodeSelected = true
					nbsselem ++;
				}
			}
		}

		var s = '';

		if(oEntry.sLabel != '') {
			s += '<li ';
			if (isNotFinalNode )
			{
				 s+= ' class=\'cliquable\'  '
			}
			s += ' >';

			if( oEntry.bIsLibelle) {

				s += '<input type="checkbox"';
				if (oEntry.bSelected)
				{
					s += ' checked="checked"';
				}
				s += ' onClick="oFiltreGUI.SelectEntry(true, ';
				s += iLineId;
				s += ', this.checked)" />';
			}

			s += '<span onClick="oFiltreGUI.OpenParentEntry(';
			s += iLineId;
			s += ')">';
			
			if (oEntry.bIsLibelle && !oEntry.bSelected &&  isSubNodeSelected)
			{
				s += '(+) ';
			}

			s += oEntry.sLabel;
			s += '</span>';

			//FBO
			//if (this.bModifiable && oEntry.bIsLibelle)
			//{
			//	s += '<img src="/kosmos/template/img/remove_icon.gif" alt="Supprimer" title="Supprimer" onclick="oFiltreGUI.RemoveEntry(';
			//	s += iLineId;
			//	s += ',false)">';
			//}
			s += '</li>\n';
		}
		return s;
	}

	this.RefreshChildDiv = function()
	{
		var end = (this.aChildItems.length == 0);
		this.oChildTitle.innerHTML = this.GetSelectedEntry().sLabel;
		var s = '';
		
		//FBO
		if (end && (this.GetSelectedEntry().bIsLibelle || this.GetSelectedEntry().bIsEntree))
		{
			s += '<p>Cet élément est vide.';
			if (false && this.bModifiable)
			{
				s += '<br /><br />Saisissez un libellé et cliquez sur [Ajouter] pour créer une nouvelle entrée.</p>';
			}
		}
		else
		{
			s += '<ul>\n';
			
			if( this.GetSelectedEntry().bIsDiscipline && this.GetSelectedEntry().oParent && (this.GetSelectedEntry().oParent.sCode != "0000"))
				s += this.DisplayChildEntree();
			else {
				for (var i = 0; i < this.aChildItems.length; i++)
					s += this.DisplayChildLine(i);
			}
			s += '</ul>\n';
		}
		this.oChildDiv.innerHTML = s;

		//FBO
		if( false &&  (this.GetSelectedEntry().bIsEntree || this.GetSelectedEntry().bIsLibelle )){
			this.oAddEntryDiv.innerHTML = '<input type="text" id="new-entry" /><input type="button" value="Ajouter" onClick="oFiltreGUI.AddEntry()" />';
		}
		else
			this.oAddEntryDiv.innerHTML = '';
	}

	this.DisplayChildEntree = function()
	{		
		//sélection des entrées
		var oEntryA = null;
		var oEntryB = null;
		var indiceA = null;
		var indiceB = null;
		
		for(i=0; i<=1; i++){

			var oEntry = this.aChildItems[i];

			if( oEntry ) {

				var code = new String(oEntry.sCode);
				var indice = code.substring( code.length-1, code.length);

				if( indice == 'A'){
					oEntryA = oEntry;
					indiceA = i;
				}
				else if( indice == 'B'){
					oEntryB = oEntry;
					indiceB = i;
				}
			}			
		}

	//affichage
		//entrée A
		var s = '<li class=\'cliquable\'>';

		// if l'entrée A est alimenté on la met en label sinon on met un EDIT
		if(oEntryA && oEntryA.sLabel) {
			s += '<span';
			s += ' onClick="oFiltreGUI.OpenChildEntry('+ indiceA +')"';
			s += '>';
			s += oEntryA.sLabel;
			s += '</span>';
		} else {
			s += '<span';
			if(oEntryA && oEntryA.sLabel)
				s += ' onClick="oFiltreGUI.OpenChildEntry('+ indiceA +')"';

			s += '>Libellé Entrée A : </span>';		

			s += '<input type="text" id="new-entry-1"';
			if(oEntryA && oEntryA.sLabel)
				s += 'value="'+ oEntryA.sLabel + '"';
				
			s += ' onChange="oFiltreGUI.UpdateLabel()" />';
		
		}
		s += '</li>\n';

	
		// if l'entrée B est alimenté on la met en label sinon on met un EDIT
		s += '<li class=\'cliquable\'>';
		if(oEntryB && oEntryB.sLabel) {
			s += '<span';
			s += ' onClick="oFiltreGUI.OpenChildEntry('+ indiceB +')"';
			s += '>';
			s += oEntryB.sLabel;
			s += '</span>';
		} else {
			s += '<span';
			if(oEntryB && oEntryB.sLabel)
				s += ' onClick="oFiltreGUI.OpenChildEntry('+ indiceB +')"';

			s += '>Libellé Entrée B : </span>';		

			s += '<input type="text" id="new-entry-1"';
			if(oEntryB && oEntryB.sLabel)
				s += 'value="'+ oEntryB.sLabel + '"';
				
			s += ' onChange="oFiltreGUI.UpdateLabel()" />';
		
		}
		s += '</li>\n';

		return s;
	}

	this.DisplayChildLine = function(iLineId, isEntree)
	{	

		var oEntry = this.aChildItems[iLineId]
		var oSubEntry
		
		var isNotFinalNode = false
		var isSubNodeSelected = false
		
		isNotFinalNode = oEntry.oChildren.Iterator().HasNext();

		// Si l'item n'est pas selectionné on regarde si un de ses sous-noeuds est selectionné
		if ( ! oEntry.bSelected ) {
			var nbsselem = 0
			var oIterator = oEntry.oChildren.Iterator();
			while ( oIterator.HasNext()){
				oSubEntry = oIterator.Next();
				if ( oSubEntry.bSelected ) {
					isSubNodeSelected = true
					nbsselem ++;
				}
			}
		}
	
		var s = '<li ';
		if (isNotFinalNode )
		{
			 s+= ' class=\'cliquable\'  '
		}
		s += ' >';

		if( oEntry.bIsLibelle) {
			
			s += '<input type="checkbox"';
			if (oEntry.bSelected)
			{
				s += ' checked="checked"';
			} 
			s += ' onClick="oFiltreGUI.SelectEntry(false, ';
			s += iLineId;
			s += ', this.checked)" />';
		}

		//affichage du libellé avec lien ou non
		if( !oEntry.bIsLibelle2 ) {
			s += '<span onClick="oFiltreGUI.OpenChildEntry(';
			s += iLineId;
			s += ')">';
		}

		if (oEntry.bIsLibelle && !oEntry.bSelected &&  isSubNodeSelected)
		{
			s += '(+) ';
		}

		s += oEntry.sLabel;

		if(  !oEntry.bIsLibelle2 )
			s += '</span>';

		// FBO
		//if (this.bModifiable && oEntry.bIsLibelle)
		//{
		//	s += '<img src="/kosmos/template/img/remove_icon.gif" alt="Supprimer" title="Supprimer" onclick="oFiltreGUI.RemoveEntry(';
		//	s += iLineId;
		//	s += ',true)">';
		//}

		s += '</li>\n';
		return s;
	}

	

	//=================================================================
	// METHODE : DisplayNewInput()
	//-----------------------------------------------------------------
	// DESCRIPTION : Affiche un champ de saisie pour une nouvelle entrée
	//=================================================================
	this.PrintMsg = function(sMsg)
	{
		if (sMsg.length == 0)
		{
			this.oMsgSpan.innerHTML = '&nbsp;';
		}
		else
		{
			this.oMsgSpan.innerHTML = sMsg;
		}
	}
}

function FiltreSelection()
{
	this.sNodeSep = '__';
	this.sEntrySep = '##';
	
	// sPath est au format : CODE1__CODE12__
	this.Print = function(oEntry, sPath)
	{
		//alert('PrintSelection()... code = ' + oEntry.sLabel + ', path = ' + sPath);
		var s = '';
		if (oEntry.bSelected)
		{
			s += sPath + oEntry.sCode + this.sEntrySep;
		}
		/*else*/ if (! oEntry.oSelectedChildren.IsEmpty())
		{
			//alert('PrintSelection()... oEntry.oSelectedChildren = ' + oEntry.oSelectedChildren.Size());
			var oIterator = oEntry.oSelectedChildren.Iterator();
			while (oIterator.HasNext())
			{
				s += this.Print(oIterator.Next(), sPath + oEntry.sCode + this.sNodeSep);
			}
		}
		return s;
	}

	this.Display = function(oEntry)
	{
		//alert('PrintSelection()... code = ' + oEntry.sLabel + ', path = ' + sPath);
		var s = '';
		if (oEntry.bSelected)
		{
			if (oEntry.sCode != 0)
			{
				s += '<li>' + oEntry.sLabel;
			}
			if (oEntry.oChildren && ! oEntry.oChildren.IsEmpty())
			{
				var oIterator = oEntry.oChildren.Iterator();
				s += '<ul>';
				while (oIterator.HasNext())
				{
					s += '<li>' + oIterator.Next().sLabel + '</li>';
				}
				s += '</ul>';
			}
			if (oEntry.sCode != 0)
			{
				s += '</li>';
			}
		}
		else if (oEntry.oSelectedChildren && ! oEntry.oSelectedChildren.IsEmpty())
		{
			var oIterator = oEntry.oSelectedChildren.Iterator();
			if (oEntry.sCode != 0)
			{
				s += '<li>' + oEntry.sLabel;
			}
			s += '<ul>';
			while (oIterator.HasNext())
			{
				s += this.Display(oIterator.Next());
			}
			s += '</ul>';
			if (oEntry.sCode != 0)
			{
				s += '</li>';
			}
		}
		return s;
	}

	this.Load = function(oEntry, sEntry)
	{
		var iIndSep = 0;
		var sCodeParent = '';
		var sCodeChild = '';
		var oIterator = null;
		var iNbSelected = 0;
		if (sEntry != null && sEntry.length > 0)
		{
			//alert('ThesaurusSelection.Load()... sEntry = ' + sEntry);
			iIndSep = sEntry.indexOf(this.sNodeSep);
			if (iIndSep == -1 && sEntry == oEntry.sCode)
			{
				oEntry.SelectEntry(true);
				iNbSelected ++;
				//alert('ThesaurusSelection.Load()... SelectedEntry = ' + oEntry.sLabel);
			}
			else
			{
				sCodeParent = sEntry.substring(0, iIndSep);
				sCodeChild = sEntry.substring(iIndSep+2);
				//alert('ThesaurusSelection.Load()... [' + sCodeParent + ']/[' + sCodeChild + ']');
				if (sCodeParent == oEntry.sCode)
				{
					oIterator = oEntry.oChildren.Iterator();
					while (oIterator.HasNext())
					{
						iNbSelected += this.Load(oIterator.Next(), sCodeChild);
					}
				}
			}
		}
		return iNbSelected;
	}
}
