/*
 * SvTab - Gestion dynamique des tableaux de listes de choix
 *
 * par Francois Cusson-Lafrenaye, ing.
 *     Seconde Vision [www.sv.qc.ca]
 *
 * Copyright (C) Francois Cusson-Lafrenaye
 *               Tous droits réservés
 * 
 * Veuillez contacter l'auteur si vous désirez utiliser ces fonctions.
 *
 * Octobre 2005 - Licence d'utilisation accordée à CIBLE Solutions d'affaires.
 *

 * UTILISATION
 *
 * 1. Définir un tableau de données (TabData) sous la forme [ID, Nom, Ordre]:
 *        var SvTab_Data = new Array();
 *        SvTab_Data[SvTab_Data.length] = new Array(1, "Type 1", 0, 10, "Valeur 10", 0, 100, "Donnée 100", 0);
 *
 * 2. Définir un tableau de définition des listes (TabDefs), indiquant le nom de chaque liste et
 *    la position de ses données dans TabData:
 *	      var SvTab_Defs = new Array(                   var SvTab_Defs = new Array(
 *            0, "Type",                   - ou -           0, "NomForm.Type",  
 *            1, "Valeur",                                  1, "NomForm.Valeur",  
 *            2, "Donnee");                                 2, "NomForm.Donnee");
 *
 * 3. Appeler la fonction SvTab_InitListes() dans le onLoad du BODY:
 *        <BODY onLoad="SvTab_InitListes(SvTab_Data, SvTab_Defs, new Array(0, 0, 0));">
 *
 * 4. Ajouter un appel à la fonction SvTab_UpdateListes() dans le onChange des SELECT:
 *        <SELECT ID="Type" NAME="Type" onChange="SvTab_UpdateListes(SvTab_Data, SvTab_Defs, this);">
 *
 * RAPPEL -> Utiliser des ID pour les SELECT pour utiliser getElementById() dans Netscape/Mozilla.
 *
 */


/********** FONCTIONS PUBLIQUES ***************************************************/

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_InitListes() - Initialisation des listes
 */
function SvTab_InitListes(iTabData, iTabDefs, iTabFiltre)
{
	// Appel direct à SvTab_FiltreListes
	SvTab_FiltreListes(iTabData, iTabDefs, iTabFiltre);
		
	return true;
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_UpdateListes() - Mise à jour des listes après une sélection
 */
function SvTab_UpdateListes(iTabData, iTabDefs, iObjSelectCourant)
{
	// On crée un filtre général à partir des sélections dans les listes
	var Filtre = new Array();
	var i;
	var IndexListeCourante = -1;
		
	// On accède à chaque liste et on extrait sa sélection
	var oSelect;
		
	for (i = 1; i < iTabDefs.length; i += 2)
	{
		oSelect = SvTab_GetSelectObject(iTabDefs[i]);
			
		// Select non-existant?
		if (!oSelect)
		{
			alert("Erreur! La liste '" + iTabDefs[i] + "' est inaccessible.\n[SvTab]");
			return false;
		}
			
		// Si le premier élément est sélectionné, ou aucun, alors on place 0 dans le filtre
		if (oSelect.selectedIndex <= 0)
		{
			Filtre[Filtre.length] = 0;
		}
			
		// Sinon on place la valeur de l'élément sélectionné
		else
		{
			Filtre[Filtre.length] = oSelect.options[oSelect.selectedIndex].value;
		}
		
		// Si la liste courante est iObjSelectCourant, on conserve son
		// index dans TabDefs
		if (iObjSelectCourant && (oSelect === iObjSelectCourant))
		{
			IndexListeCourante = (i-1)/2;
		}
	}
		
	// Enfin, on appelle SvTab_FiltreListes pour regénérer les listes
	SvTab_FiltreListes(iTabData, iTabDefs, Filtre, IndexListeCourante);
		
	return true;
}








/********** FONCTIONS PRIVÉES *****************************************************/

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_FiltreListes()
 */
function SvTab_FiltreListes(iTabData, iTabDefs, iTabFiltre, iIndexListeCourante)
{
	// Définition de quelques variables
	var TabCorresp;
	var Okay;
	var i;
	var j;
	var k;
	

	// Pour chaque liste définies dans iTabDefs, on filtre pour trouver les 
	// correspondances et on regénère ses choix
	for (i = 0; i < iTabDefs.length; i += 2)
	{
		// On exclue la liste courante, s'il y a lieu
		if (i/2 != iIndexListeCourante)
		{
			// On crée une nouvelle table de correspondances à chaque fois
			TabCorresp  = new Array();
			
			// Pour chaque critère du filtre
			for (j = 0; j < iTabData.length; j++)
			{
				// On tente de trouver une non-correspondance en ignorant les 0
				// ainsi que les choix de la liste courante
				Okay = true;
					
				for (k = 0; k < iTabFiltre.length; k++)
				{
					if (k != i/2
						&& iTabFiltre[k] != 0
						&& iTabData[j][k*3] != iTabFiltre[k])
					{
						Okay = false;
						break;
					}
				}
					
				// Si on a une correspondance, on ajoute l'index dans TabCorresp
				if (Okay)
				{
					TabCorresp[TabCorresp.length] = j;
				}
			}
			
			// On modifie les options présentées dans la liste
			SvTab_OptionsListe(iTabDefs[i+1], iTabDefs[i], iTabFiltre[i/2], 
				iTabData, TabCorresp);
		}
	}
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_OptionsListe()
 */
function SvTab_OptionsListe(iNomListe, iPositionData, iSelection, iTabData, iTabCorresp)
{
    
	// On obtiens une référence à l'objet Select
	var oSelect = SvTab_GetSelectObject(iNomListe);

	// Select non-existant?
	if (!oSelect)
	{
		alert("Erreur! La liste '" + iNomListe + "' est inaccessible.\n[SvTab]");
		return false;
	}
	
	// On se crée un tableau des valeurs correspondantes (avec les duplications)
	var TabOptions = new Array();
	var i;
		
	for (i = 0; i < iTabCorresp.length; i++)
	{
		// ID de l'option suivi du nom de l'option et de son ordre
		TabOptions[TabOptions.length] = new Array(
			iTabData[iTabCorresp[i]][iPositionData*3], 
			iTabData[iTabCorresp[i]][iPositionData*3+1], 
			iTabData[iTabCorresp[i]][iPositionData*3+2]);
	}
		
	// On sort ensuite l'array selon le nom de l'option
	TabOptions.sort(SvTab_CompareOptions);
		
	// On vide toutes ses options excepté la première
	oSelect.options.length = 1;
		
	// On ajoute ensuite les différentes options SANS duplication
	var IdCourant = -1;
		
	for (i = 0; i < TabOptions.length; i++)
	{
		if (TabOptions[i][0] != IdCourant)
		{
			IdCourant = TabOptions[i][0];
				
			// Ajout de l'option au Select
			oSelect.options[oSelect.options.length] = new Option(TabOptions[i][1], TabOptions[i][0]);
				
			// Si l'option est sélectionnée, on le fait ici
			if (TabOptions[i][0] == iSelection)
			{
				oSelect.options[oSelect.options.length-1].selected = true;
			}
		}
	}
	
	return true;
}


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_CompareOptions()
 */
function SvTab_CompareOptions(iOption1, iOption2)
{
	// Selon l'ordre
	if (iOption1[2] < iOption2[2])
		return -1;
	else if (iOption1[2] > iOption2[2])
		return 1;
	
	// Sinon selon le nom
	else if (iOption1[1] < iOption2[1])
		return -1;
	else if (iOption1[1] > iOption2[1])
		return 1;
		
	// Sinon c'est égal
	else
		return 0;
}
	

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * SvTab_GetSelectObject()
 */
function SvTab_GetSelectObject(iNom)
{
	var oSelect = null;
	
	// S'il y a un point (.) dans le nom, alors on a une forme NomForm.NomChamp
	if (iNom.indexOf(".") >= 0)
	{
		oSelect = eval("document." + iNom);
	}
	
	// Sinon, on accède à l'élément directement 
	else
	{
		// Si on a un ID de défini, c'est le mieux
		oSelect = document.getElementById(iNom);
			
		// Sinon, on peut y aller avec le NAME (Netscape)
		if (!oSelect)
		{
			oSelect = document.getElementsByName(iNom)[0];
		}
	}
		
	return oSelect;
}
	
