/***********************************************************************
Objet ARBRE.JS
BUT : Crée un arbre HTML/JavaScript
ENTREE :
- L'arbre a une "liste de noeuds" associée.
- L'arbre va être dessiné dans un "conteneur" HTML
SORTIE :
- Un "arbre"
CONTRAINTES :
- une "liste de noeuds" construite suivant les contraintes de l'objet "noeud"
RISQUES :
Si le "conteneur" n'existe pas, l'arbre ne sera pas affiché.
Si la "liste de noeuds" est mal construite, l'arbre ne pourra pas être
construit, il sera vide.
EXEMPLE
************************************************************************/

/***********************************************************************
CONSTANTES POUR L'OBJET ARBRE
***********************************************************************/
// Indique le nombre d'informations de l'arbre situées avant la liste des noeuds
var TAILLE_ARBRE = 2;





function Arbre (arbre_nom)
/***********************************************************************
BUT : Crée l'objet Arbre
ENTREE :
- arbre_nom : nom de l'objet "arbre" utilisé dans le script
SORTIE :
Retourne un objet "Arbre" non initialisé.
Un arbre est
	constitué
		de plusieurs objets "noeud".
		d'un "myself" qui fait référence à lui-même
		d'un "id"
		d'un "conteneur" qui va contenir le code HTML de l'arbre afin de l'afficher
		d'un "contenu_debut" qui contient le debut du code HTML de l'arbre à afficher
		d'un "contenu_fin" qui contient la fin du code HTML de l'arbre à afficher
		d'un "unealafois" qui indique si on peut ouvrir plusieurs branches a la fois ou pas
		de méthodes
			"Construire" : Remplit le contenu HTML de l'arbre (TABLE + DIV) en utilisant sa liste de noeuds
			"Afficher" : Insère le code HTML de l'arbre dans le conteneur prévu
			"CodeSource" : Affiche dans une fenetre alert le contenu HTML de l'arbre pour vérification
CONTRAINTES :
RISQUES :
************************************************************************/
{
	this.id = 0;
	this.nom = arbre_nom;
	this.myself = this;
	this.noeuds = new Array(0);
	this.conteneur = '';
	this.contenu = '';
	this.unealafois = 0;



	this.Init = function (arbre, conteneur)
	/***********************************************************************
	BUT : Initialise l'objet Arbre
	ENTREE :
	- arbre : "liste des noeuds" de l'arbre sous forme de tableau (cf. objet "noeud")
	- conteneur : ID html du conteneur qui doit contenir l'arbre
	SORTIE :
	Retourne l'objet "Arbre" construit
	CONTRAINTES :
	- La liste des noeuds doit être un tableau de tableau construit suivant les contraintes de l'objet "noeud".
	- Chacun de ces sous-tableaux est un futur objet "noeud" qui contient lui-même des objets "feuille"
	RISQUES :
	Si le conteneur n'existe pas, l'arbre ne peut pas être affiché.
	Si le tableau de noeuds est mal construit, l'arbre ne pourra pas être construit, il sera vide.
	************************************************************************/
	{
		var i;

		this.id = arbre[0];
		this.unealafois = arbre[1];
		this.conteneur = conteneur;

		for (i=TAILLE_ARBRE;i<arbre.length;i++)
		{
			var noeud = new Noeud();
			noeud.Init (this, arbre, i);
			this.AjouterNoeud (noeud);
		}
	}



	this.AjouterNoeud = function (n)
	/***********************************************************************
	BUT : Ajoute un noeud donné à l'arbre
	ENTREE :
	- n : le noeud à rajouter
	SORTIE :
	CONTRAINTES :
	- Le noeud doit être un "Noeud"
	RISQUES :
	Si le noeud n'est pas un "Noeud", l'arbre peut planter
	************************************************************************/
	{
		this.noeuds[this.noeuds.length] = n;
	}



	this.Construire = function (parent,niveau)
	/***********************************************************************
	BUT : Construit le code HTML de l'arbre suivant ses informations.
	ENTREE :
	SORTIE :
	Remplit les "contenus" de l'arbre, puis lance la construction de chaque
	noeud. A son tour chaque noeud doit lancer la construction de chacune de
	ses feuilles.
	L'arbre est un TABLE HTML.
	CONTRAINTES :
	RISQUES :
	Si la liste de noeuds est vide, l'arbre sera vide. Si elle est mal
	construite, l'arbre peut planter.
	************************************************************************/
	{
		var i;

		for (i=0;i<this.noeuds.length;i++)
		{
			if (this.noeuds[i].parent == parent)
			{
				this.noeuds[i].niveau = niveau;
				this.noeuds[i].classe = 'arbre_lvl_' + niveau;
				this.noeuds[i].Construire();
				niveau ++;
				this.Construire(this.noeuds[i].id, niveau);
				niveau --;
			}
		}
	}



	this.Afficher = function ()
	/***********************************************************************
	BUT : Affiche l'arbre
	ENTREE :
	SORTIE :
	Remplit le "conteneur" de l'arbre avec les "contenu"
	CONTRAINTES :
	RISQUES :
	Si le "contenu" ne contient rien, rien n'est affiché
	Si le "conteneur" n'existe pas, l'arbre ne sera pas	affiché
	************************************************************************/
	{
		this.contenu = '<DIV id="a_' + this.id + '">';
		this.AfficherNoeuds(0);
		this.contenu = this.contenu + '</DIV>';

		var c = document.getElementById(this.conteneur);
		if (c!=null)
		{
			c.innerHTML = this.contenu;
		}
	}



	this.AfficherNoeuds = function (parent)
	/***********************************************************************
	BUT : Affiche les noeuds
	ENTREE :
	SORTIE :
	Retourne le code HTML de tous les noeuds
	CONTRAINTES :
	RISQUES :
	************************************************************************/
	{
		var i;

		for (i=0;i<this.noeuds.length;i++)
		{
			if (this.noeuds[i].parent == parent)
			{
				this.noeuds[i].Afficher();
			}
		}
	}



	this.CodeSource = function ()
	/***********************************************************************
	BUT : Affiche le code source de l'arbre dans une alert
	ENTREE :
	SORTIE :
	Affiche le code source de l'arbre
	CONTRAINTES :
	RISQUES :
	************************************************************************/
	{
		var c = document.getElementById(this.conteneur);
		if (c!=null)
		{
			alert (c.innerHTML);
		}
	}



	this.ChangerNoeud = function (id)
	/***********************************************************************
	BUT : Change l'état du noeud désigné
	ENTREE :
	- id : identifiant du noeud à modifier
	SORTIE :
	CONTRAINTES :
	RISQUES :
	************************************************************************/
	{
		var i = 0;

		if (!this.unealafois)
		{
			while (this.noeuds[i].id!=id)
			{
				i ++;
			}
			this.noeuds[i].etat = !this.noeuds[i].etat;
			this.noeuds[i].Construire ();
			//Puis on applique le changement
			var c = document.getElementById('a_' + this.id + 's_' + this.noeuds[i].id);
			if (c!=null)
			{
				if (this.noeuds[i].etat)
				{
					c.className = 'arbre_noeud_ouvert';
				}
				else
				{
					c.className = 'arbre_noeud_ferme';
				}
			}
		}
		else
		{
			while (i<this.noeuds.length)
			{
				if (this.noeuds[i].id!=id)
				{
					if (this.noeuds[i].etat)
					{
						this.noeuds[i].etat = false;
						this.noeuds[i].Construire ();
						//Puis on applique le changement
						var c = document.getElementById('a_' + this.id + 's_' + this.noeuds[i].id);
						if (c!=null)
						{
							c.className = 'arbre_noeud_ferme';
						}
					}
				}
				else
				{
					this.noeuds[i].etat = !this.noeuds[i].etat;
					this.noeuds[i].Construire ();
					//Puis on applique le changement
					var c = document.getElementById('a_' + this.id + 's_' + this.noeuds[i].id);
					if (c!=null)
					{
						if (this.noeuds[i].etat)
						{
							c.className = 'arbre_noeud_ouvert';
						}
						else
						{
							c.className = 'arbre_noeud_ferme';
						}
					}
				}
				i ++;
			}
		}
	}



	this.VoirNoeud = function (id)
	/***********************************************************************
	BUT : Change l'état de visibilité du noeud désigné
	ENTREE :
	- id : identifiant du noeud à modifier
	SORTIE :
	CONTRAINTES :
	RISQUES :
	************************************************************************/
	{
		i = 0;
		while (this.noeuds[i].id!=id)
		{
			i ++;
		}
		this.noeuds[i].VoirNoeud();
		this.Afficher();
	}



	this.EchangerNoeud = function (id, cible, new_classe)
	/***********************************************************************
	BUT : Copie un noeud et le donne à un autre arbre (cible). La feuille
	actuelle change simplement de classe (new_classe).
	L'effet inverse est automatiquement donné au noeud et passe par la
	fonction RetournerNoeud().
	Si la nouvelle classe n'est pas définit, le noeud devient invisible.
	ENTREE :
	- identifiant du noeud à copier
	- nom de l'arbre receveur
	- nouvelle classe à attribuer au noeud
	SORTIE :
	CONTRAINTES :
	RISQUES :
	- Si l'arbre cible n'existe pas, le noeud n'est pas donné
	************************************************************************/
	{
		var i;
		var j;
		var noeud = new Noeud();
		var macible	= eval(cible);

		if (macible!=null)
		{
			//On copie le bon noeud
			i = 0;
			while (this.noeuds[i].id!=id)
			{
				i ++;
			}
			n = this.noeuds[i].Copie();

			//On change le type d'action de la feuille
			for (j=0;j<this.noeuds[i].feuilles.length;j++)
			{
				if (this.noeuds[i].feuilles[j].typeaction==1 && this.noeuds[i].feuilles[j].action==3)
				{
					this.noeuds[i].feuilles[j].action = 5;
				}
			}
			if (new_classe!=undefined)
			{
				//On change la classe du noeud ssi on en a donné une nouvelle
				this.noeuds[i].classe = new_classe;
				//On reconstruit alors le noeud
				this.noeuds[i].Construire();
				//Puis on applique le changement
				var c = document.getElementById('a_' + this.id + 'n_' + this.noeuds[i].id);
				if (c!=null)
				{
					c.className = new_classe;
				}
			}

			//On l'adapte
			n.parent = 0;
			n.tronc = macible;
			//On l'adapte pour le retour
			for (i=0;i<n.feuilles.length;i++)
			{
				if (n.feuilles[i].typeaction==1 && n.feuilles[i].action==3)
				{
					n.feuilles[i].action = 4;
					n.feuilles[i].parametre = [this.nom,n.classe];
				}
			}
			//On le crée dans l'autre arbre
			macible.AjouterNoeud(n);
			macible.Construire(0,0);
			macible.Afficher();
		}
	}



	this.RetournerNoeud = function (id, cible, new_classe)
	/***********************************************************************
	BUT : Inverse de la fonction précédente. Elimine donc le noeud de l'arbre
	et réaffiche l'ancien noeud.
	ENTREE :
	- identifiant du noeud à copier
	- nom de l'arbre receveur
	SORTIE :
	CONTRAINTES :
	RISQUES :
	- Si l'arbre cible n'existe pas, le noeud n'est pas donné
	************************************************************************/
	{
		var i;
		var macible;

		//On détruit le bon noeud
		i = 0;
		while (this.noeuds[i].id!=id)
		{
			i ++;
		}
		while (i<this.noeuds.length-1)
		{
			this.noeuds[i] = this.noeuds[i+1];
			i ++;
		}
		this.noeuds.length --;
		//On fait reapparaitre l'ancien noeud
		macible = eval(cible);
		if (macible!=null)
		{
			i = 0;
			while (macible.noeuds[i].id!=id)
			{
				i ++;
			}
			//On lui rend son ancienne configuration
			for (j=0;j<macible.noeuds[i].feuilles.length;j++)
			{
				if (macible.noeuds[i].feuilles[j].typeaction==1 && macible.noeuds[i].feuilles[j].action==5)
				{
					macible.noeuds[i].feuilles[j].action = 3;
				}
			}

			//On change la classe du noeud
			macible.noeuds[i].classe = new_classe;
			//On reconstruit alors le noeud
			macible.noeuds[i].Construire();
			//Puis on applique le changement
			var c = document.getElementById('a_' + macible.id + 'n_' + macible.noeuds[i].id);
			if (c!=null)
			{
				c.className = new_classe;
			}
		}

		//On réaffiche l'arbre
		this.Construire(0,0);
		this.Afficher();
	}

	return this;
}
