/////////////////////////////////////////////////////////////////////////////////////////
//JavaScript Clase TreeItem                                                            //
//                                                                                     //
//Proposit: La clase es el complement de la clase TreeView, s'intenta aquí emular el   //
//          comportament d'un node de la clase treeview de Visual Basic                //
//                                                                                     //
//Autor:  Marc Manzanera Torrens                                                       //
//                                                                                     //
//Versió: 1.0                                                                          //
/////////////////////////////////////////////////////////////////////////////////////////

//Constants utilitzades per la clase
var tvwFirst = 0;
var tvwLast = 1;
var tvwNext = 2;
var tvwPrevious = 3;
var tvwChild = 4;

/////////////////////////////////////////////////////////////////////////////////////////
//Declaració de funcions de l'objecte

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que crea un element com a primer de la seva branca
function TI_f_AddFirst(p_relativa, p_parent)
{
  if (p_relativa.length > 0)
  {
    this.primer = this;
    this.ultim = p_parent.Nodes[p_relativa].ultim;
    this.seguent = p_parent.Nodes[p_relativa].primer;
    this.anterior = null;
    this.pare = p_parent.Nodes[p_relativa].pare;    
    this.nivell = p_parent.Nodes[p_relativa].nivell;
    
    p_parent.Nodes[p_relativa].primer.anterior = this;
    
    if (p_parent.Nodes[p_relativa].pare)
    {
      p_parent.Nodes[p_relativa].pare.fill = this;
      p_parent.Nodes[p_relativa].pare.fills++;
    }
    
    for (LObjNode = p_parent.Nodes[p_relativa].primer; LObjNode; LObjNode = LObjNode.seguent)
    {
      LObjNode.primer = this;
      if (p_parent.DEBUGMODE) p_parent.Debug.print("L'element " + LObjNode.clau + " ara té com a primer " + LObjNode.primer.clau);
    }
  }
  else
  {
    this.primer = this;
    this.nivell = 1;
    
    if (p_parent.Nodes.length > 0) 
    {
      this.ultim = p_parent.Nodes[0].ultim;
      this.seguent = p_parent.Nodes[0].primer;
      p_parent.Nodes[0].primer.anterior = this;
      for (LObjNode = p_parent.Nodes[0].primer; LObjNode; LObjNode = LObjNode.seguent)
      {
        LObjNode.primer = this;
      }
    }
    else
    {
      this.ultim = this;
      this.seguent = null;
    }
    
    this.anterior = null;
    this.pare = null;
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que crea un element com a últim de la seva branca
function TI_f_AddLast(p_relativa, p_parent)
{
  if (p_relativa.length > 0)
  {
    this.primer = p_parent.Nodes[p_relativa].primer;
    this.ultim = this;
    this.seguent = null;
    this.anterior = p_parent.Nodes[p_relativa].ultim;
    this.pare = p_parent.Nodes[p_relativa].pare;
    this.nivell = p_parent.Nodes[p_relativa].nivell;
    
    p_parent.Nodes[p_relativa].ultim.seguent = this;
    
    if (p_parent.Nodes[p_relativa].pare) p_parent.Nodes[p_relativa].pare.fills++;
    
    for (LObjNode = p_parent.Nodes[p_relativa].ultim; LObjNode; LObjNode = LObjNode.anterior)
    {
      LObjNode.ultim = this;
    }
  }
  else
  {
    this.ultim = this;
    this.nivell = 1;
    
    if (p_parent.Nodes.length > 0) 
    {
      this.primer = p_parent.Nodes[0].primer;
      this.anterior = p_parent.Nodes[0].ultim;
      p_parent.Nodes[0].ultim.seguent = this;
      for (LObjNode = p_parent.Nodes[0].ultim; LObjNode; LObjNode = LObjNode.anterior)
      {
        LObjNode.ultim = this;
      }
    }
    else
    {
      this.primer = this;
      this.anterior = null;
    }
    
    this.seguent = null;
    this.pare = null;
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que crea un element com a anterior del node passat
function TI_f_AddPrevious(p_relativa, p_parent)
{
  
  if (p_relativa.length > 0)
  {
    //Si el node passat és el primer dels nodes de la branca 
    //La funció farà el mateix que la funció AddFirst
    if (p_parent.Nodes[p_relativa].primer.clau == p_relativa)
    {
      if (p_parent.DEBUGMODE) p_parent.Debug.print ("El node passat és el primer de la branca");
      this.AddFirst(p_relativa, p_parent);
      return;
    }
    
    
    this.primer = p_parent.Nodes[p_relativa].primer;
    this.ultim = p_parent.Nodes[p_relativa].ultim;
    this.seguent = p_parent.Nodes[p_relativa];
    this.anterior = p_parent.Nodes[p_relativa].anterior;
    this.pare = p_parent.Nodes[p_relativa].pare;
    this.nivell = p_parent.Nodes[p_relativa].nivell;
    
    this.anterior.seguent = this;
    this.seguent.anterior = this;
    
    if (p_parent.Nodes[p_relativa].pare) p_parent.Nodes[p_relativa].pare.fills++;
  }
  else
  {
    //Si no ens passem el node afegirem el nou node com a últim de la branca
    if (p_parent.DEBUGMODE) p_parent.Debug.print ("No s'ha passat el node posterior al nou element '" + this.clau + "', aquest s'inclourà com a últim" );
    this.AddLast(p_relativa, p_parent);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que crea un element com a seguent del node passat
function TI_f_AddNext(p_relativa, p_parent)
{
  if (p_parent.DEBUGMODE) p_parent.Debug.print ("El node");
  if (p_relativa.length > 0)
  {
    //Si el node passat és l'últim dels nodes de la branca 
    //La funció farà el mateix que la funció AddLast
    if (p_parent.Nodes[p_relativa].ultim.clau == p_relativa)
    {
      if (p_parent.DEBUGMODE) p_parent.Debug.print ("El node passat és l'últim de la branca");
      this.AddLast(p_relativa, p_parent);
      return;
    }
    
    this.primer = p_parent.Nodes[p_relativa].primer;
    this.ultim = p_parent.Nodes[p_relativa].ultim;
    this.seguent = p_parent.Nodes[p_relativa].seguent;
    this.anterior = p_parent.Nodes[p_relativa];
    this.pare = p_parent.Nodes[p_relativa].pare;
    this.nivell = p_parent.Nodes[p_relativa].nivell;
    
    this.anterior.seguent = this;
    this.seguent.anterior = this;
    
    if (p_parent.Nodes[p_relativa].pare) p_parent.Nodes[p_relativa].pare.fills++;
  }
  else
  {
    //Si no ens passem el node afegirem el nou node com a últim de la branca
    if (p_parent.DEBUGMODE) p_parent.Debug.print ("No s'ha passat el node previ al nou element '" + this.clau + "', aquest s'inclourà com a últim" );
    this.AddLast(p_relativa, p_parent);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que crea un element com a fill del node passat
function TI_f_AddChild(p_relativa, p_parent)
{
  if (p_parent.Nodes[p_relativa].fills > 0)
  {
    //Afegir un fill es com afegir un node com a últim de la branca del primer fill del
    //node passat
    this.AddLast(p_parent.Nodes[p_relativa].fill.clau, p_parent);
  }
  else
  {
    //Crear un fill 
    this.primer = this;
    this.ultim = this;
    this.pare = p_parent.Nodes[p_relativa];
    this.seguent = null;
    this.anterior = null;
    this.nivell = p_parent.Nodes[p_relativa].nivell + 1;
    
    this.pare.fill = this;
    this.pare.fills++;
    if (p_parent.DEBUGMODE) p_parent.Debug.print ("El node " + this.clau + " s'ha afegit com a fill de " + this.pare.clau);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció de Creació de Clase
//PRE: p_relativa               Clau del TreeItem amb el que el nou es relaciona.
//                              La relació ve indicada pel paràmetre p_relacio.
//     p_relacio                Tipus de relació entre el nou treeitem i l'indicat en el
//                              parametre p_relativa.
//     p_clau                   Clau (ID) del nou treeitem.
//     p_texte                  Texte del nou element treeitem (pot ser texte HTML).
//     p_imatge                 Clau de la imatge asociada que es mostrarà al costat del
//                              nou TreeItem.
//     p_imatgeSeleccionada     Clau de la imatge asociada que es mostrarà al costat del
//                              nou TreeItem quan aquest estigui seleccionat.
//     p_parent                 Referència a la clase TreeView que fa la crida.
function TreeItem(p_relativa, p_relacio, p_clau, p_texte, p_imatge, p_imatgeSeleccionada, p_parent)
{
  
  var LObjNode;
  
  this.AddFirst = TI_f_AddFirst;
  this.AddLast = TI_f_AddLast;
  this.AddPrevious = TI_f_AddPrevious;
  this.AddNext = TI_f_AddNext;
  this.AddChild = TI_f_AddChild;
  
  this.clau = p_clau;
  this.texte = p_texte;
  this.fill = null;
  this.fills = 0;
  this.expandit = false;
  this.seleccionat = false;
  this.imatge = p_imatge;
  this.imatgeseleccionat = p_imatgeSeleccionada;
  this.arrel = (p_relativa.length > 0? p_parent.Nodes[p_relativa].arrel : this);
  
  this.visible = false
  
  switch (p_relacio)
  {
    case 0:
      this.AddFirst(p_relativa, p_parent);
      break;
      
    case 1:
      this.AddLast(p_relativa, p_parent);
      break;
      
    case 3:
      this.AddPrevious(p_relativa, p_parent);
      break;
      
    case 4:
      this.AddChild(p_relativa, p_parent);
      break;
    default:
      this.AddNext(p_relativa, p_parent);
  }
  if (p_parent.DEBUGMODE) p_parent.Debug.print("El nen té com a pare " + (this.pare? this.pare.clau: "<No té pare>"));
}

/////////////////////////////////////////////////////////////////////////////////////////
//JavaScript Clase CrossBrowserLayer                                                   //
//                                                                                     //
//Autor:  Marc Manzanera Torrens                                                       //
//                                                                                     //
//Versió: 1.0                                                                          //
/////////////////////////////////////////////////////////////////////////////////////////

function CLayer_top()
{

  switch (MStrNavegador)
  {
    case "NS":
      if (arguments.length > 0) 
      {
        this.Div.top = arguments[0] + this.layerBorderWidth();
        this.marcDiv.top = arguments[0]
      }
      
      return this.marcDiv.top;

    default:
      if (arguments.length > 0) this.Div.style.pixelTop = arguments[0];
      
      return parseInt(this.Div.style.pixelTop);
  }
}

function CLayer_left()
{

  switch (MStrNavegador)
  {
    case "NS":
      if (arguments.length > 0)
      {
        this.Div.left = arguments[0] + this.layerBorderWidth();
        this.marcDiv.left = arguments[0];
      }
      return this.marcDiv.left;

    default:
      if (arguments.length > 0) this.Div.style.pixelLeft = arguments[0];
      
      return parseInt(this.Div.style.pixelLeft);
  }
}

function CLayer_height()
{

  switch (MStrNavegador)
  {
    case "NS":
      if ((arguments.length > 0) && (!this.layerAutoSize()))
      {
        this.Div.clip.height = arguments[0] - (2 * this.layerBorderWidth());
        this.marcDiv.clip.height = arguments[0];
      }
      
      return this.marcDiv.clip.height;

    default:
      if ((arguments.length > 0) && (!this.layerAutoSize())) this.Div.style.pixelHeight = arguments[0];
      
      return parseInt(this.Div.offsetHeight);
  }
}

function CLayer_width()
{

  switch (MStrNavegador)
  {
    case "NS":
      if ((arguments.length > 0) && (!this.layerAutoSize()))
      {
        this.Div.clip.width = arguments[0] - (2 * this.layerBorderWidth());
        this.marcDiv.clip.width = arguments[0];
      }
      
      return this.marcDiv.clip.width;

    default:
      if ((arguments.length > 0) && (!this.layerAutoSize()))
        this.Div.style.pixelWidth = arguments[0];

      return parseInt(this.Div.offsetWidth);
  }
}

function CLayer_bgColor()
{

  switch (MStrNavegador)
  {
    case "NS":
      if (arguments.length > 0)
      {
        if (arguments[0].toLowerCase() != "none") this.Div.bgColor = arguments[0];
        else this.Div.bgColor = null;
      }
      return (this.Div.bgColor == null? "none": this.Div.bgColor);

    default:
      if (arguments.length > 0) 
      {
        if (arguments[0].toLowerCase() != "none") this.Div.style.backgroundColor = arguments[0];
        else this.Div.style.backgroundColor = "";
      }
      return (this.Div.style.backgroundColor==""? "none": this.Div.style.backgroundColor);
  }
}

function CLayer_visibility()
{

  switch (MStrNavegador)
  {
    case "NS":
      if (arguments.length > 0) 
      {
        //this.marcDiv.visibility = (arguments[0]=="show"? "show" : (arguments[0]=="hide"? "hide" : "inherit"));
        this.marcDiv.visibility = (arguments[0]=="hide"? "hide" : "inherit");
        this.Div.visibility = this.marcDiv.visibility;
      }
      
      return this.marcDiv.visibility;

    default:
      if (arguments.length > 0) 
      {
        //this.Div.style.visibility = (arguments[0]=="show"? "visible" : (arguments[0]=="hide"? "hidden" : "inherit"));
        this.Div.style.visibility = (arguments[0]=="hide"? "hidden" : "inherit");
      }
      
      return (this.Div.style.visibility == "visible"?  "show" : (this.Div.style.visibility == "hidden"? "hide" : "inherit"));
  }
}

function CLayer_borderWidth()
{

  switch (MStrNavegador)
  {
    case "NS":
      
      if (arguments.length > 0) 
      {
        this.Div.top = this.marcDiv.top + arguments[0];
        this.Div.left = this.marcDiv.left + arguments[0];
        this.Div.clip.height = this.Div.clip.height - (2 * arguments[0]);
        this.Div.clip.width = this.Div.clip.width - (2 * arguments[0]);
        
        if (this.layerAutoSize())
        {
          if (this.Div.clip.height < this.Div.document.height)
          {
            this.Div.clip.height = this.Div.document.height;
            this.marcDiv.clip.height = this.Div.clip.height + (2 *  arguments[0]);
          }
          if (this.Div.clip.width < this.Div.document.width)
          {
            this.Div.clip.width = this.Div.document.width;
            this.marcDiv.clip.width = this.Div.clip.width + (2 *  arguments[0]);
          }
        }
      }
      
      return (this.Div.top - this.marcDiv.top);

    default:
      if (arguments.length > 0) 
      {
        this.Div.style.borderWidth = arguments[0];
        if (this.layerAutoSize()) this.adjustSize();
      }

      return parseInt(this.Div.style.borderWidth);
  }
}

function CLayer_borderColor()
{

  switch (MStrNavegador)
  {
    case "NS":
     
      if (arguments.length > 0)
      {
        if (arguments[0].toLowerCase() != "none") this.marcDiv.bgColor = arguments[0];
        else this.Div.bgColor = null;
      }
      return (this.marcDiv.bgColor == null? "none": this.marcDiv.bgColor);

    default:
      if (arguments.length > 0) 
      {
        if (arguments[0].toLowerCase() != "none") this.Div.style.borderColor = arguments[0];
        else this.Div.style.borderColor = "";
      }
      return (this.Div.style.borderColor == ""? "none":this.Div.style.borderColor);
  }
}

function CLayer_borderStyle()
{

  switch (MStrNavegador)
  {
    case "NS":
      return null;
      break;

    default:
 
      if (arguments.length > 0) 
        this.Div.style.borderStyle = arguments[0];
      else
        this.Div.style.borderStyle = "none";
      
      return this.Div.style.borderStyle;
  }
}

function CLayer_adjustSize()
{
  switch (MStrNavegador)
  {
    case "NS":
      if (this.layerWidth() != this.Div.document.width)
      {
        this.Div.clip.width = this.Div.document.width;
        this.marcDiv.clip.width = this.Div.clip.width + (2 * this.layerBorderWidth());
      }
      if (this.layerHeight() != this.Div.document.height)
      {
        this.Div.clip.height = this.Div.document.height;
        this.marcDiv.clip.height = this.Div.clip.height + (2 * this.layerBorderWidth());
      }
      break;
      
    default:
      
      this.Div.style.height="auto";
      this.Div.style.width="auto";
      //this.layerHeight(this.layerHeight());
      //this.layerWidth(this.layerWidth());
      break;
  }
}

function CLayer_autoSize()
{
  if (arguments.length > 0)
    this.AutoSize = arguments[0];

  if (this.AutoSize) this.adjustSize();
    
  return this.AutoSize;
}

function CLayer_setText(PStrText)
{

  switch (MStrNavegador)
  {
    case "NS":
      //this.Div.document.open();
      this.Div.document.write(PStrText);
      this.Div.document.close();
      
      if (this.layerAutoSize()) this.adjustSize()
        
      break;

    default:
      this.Div.innerHTML = PStrText; 
  }
}


function CLayer(PStrNom)
{

  /*Arguments:
      arguments[0]: PStrNom: nom de la layer (requerit)
      arguments[1]: Layer pare de la nova layer (opcional)
      arguments[2]: posició Top de la layer (opcional)
      arguments[3]: posició Left de la layer (opcional)
      arguments[4]: Amplada de la layer (opcional)
      arguments[5]: Alçada de la layer (opcional)
      arguments[6]: Color de fons de la layer (opcional)
      arguments[7]: Visibilitat de la capa (opcional) per defecte heredat del pare
      arguments[8]: Amplada del marc de la layer (opcional)
      arguments[9]: Color del marc de la layer (opcional)
      arguments[10]: Estil del marc de la layer (opcional) (només suportat per explorer)*/

  switch (MStrNavegador)
  {
    case "NS":
     {
        if (arguments[1])
        {
          this.Div = arguments[1].document.layers[PStrNom] = new Layer((arguments[4]? arguments[4]: 0), arguments[1]);
          this.marcDiv = arguments[1].document.layers["marc" + PStrNom] = new Layer((arguments[4]? arguments[4]: 0), arguments[1]);
        }
        else
        {
          this.Div = document.layers[PStrNom] = new Layer((arguments[4]? arguments[4]: 0));
          this.marcDiv = document.layers["marc" + PStrNom] = new Layer((arguments[4]? arguments[4]: 0));
        }
        eval ("document." + PStrNom + " = this.Div");
        eval ("document.marc" + PStrNom + " = this.marcDiv");
        
        this.marcDiv.moveBelow (this.Div);
        break;
      }
    case "IE":
      {
        this.Div = document.createElement("DIV");
        
        if (arguments[1])
          arguments[1].appendChild(this.Div);
        else
          document.body.appendChild (this.Div);
        this.Div.style.position = "absolute";
        this.Div.style.overflow = "hidden";
        break;
      }
  }
  
  this.Div.id = PStrNom;
  this.Div.name = PStrNom;
 
  //Funcions
  this.setText = CLayer_setText;
  this.adjustSize = CLayer_adjustSize;
  
  
  //Altres
  this.AutoSize;
  this.layerAutoSize = CLayer_autoSize;
  
  //Propietats
  this.parentLayer = (arguments[1]? arguments[1]: null)
  this.layerTop = CLayer_top;
  this.layerLeft = CLayer_left;
  this.layerWidth = CLayer_width;
  this.layerHeight = CLayer_height;
  this.layerBgColor = CLayer_bgColor;
  this.layerVisible = CLayer_visibility;
  this.layerBorderWidth = CLayer_borderWidth;
  this.layerBorderColor = CLayer_borderColor;
  this.layerBorderStyle = CLayer_borderStyle;
 
  //Inicialitzacions
  this.layerAutoSize(false);
  this.layerTop((arguments[2]? arguments[2] : 0));
  this.layerLeft((arguments[3]? arguments[3] : 0));
  this.layerWidth((arguments[4]? arguments[4] : 0));
  this.layerHeight((arguments[5]? arguments[5] : 0));
  this.layerBgColor((arguments[6]? arguments[6] : "none"));
  this.layerVisible((arguments[7]? arguments[7] : "inherit"));
  this.layerBorderWidth((arguments[8]? arguments[8] : 0));
  this.layerBorderColor((arguments[9]? arguments[9] : "none"));
  this.layerBorderStyle((arguments[10]? arguments[10] : "solid"));

}

/////////////////////////////////////////////////////////////////////////////////////////
//JavaScript Clase TreeView                                                            //
//                                                                                     //
//Autor:  Marc Manzanera Torrens                                                       //
//                                                                                     //
//Versió: 2.0                                                                          //
/////////////////////////////////////////////////////////////////////////////////////////

var MObjTV_TreeView;

var tv_el_Arbre = 1;
var tv_el_Arrel = 2;

var tv_ea_MesMenys = 1;
var tv_ea_LineasArbre  = 2;
var tv_ea_Imatge = 4;

var tv_em_cap = 0;
var tv_em_solid = 1;
var tv_em_guions = 2;
var tv_em_punts = 3;
var tv_em_doble = 4;
var tv_em_array_IE = new Array("none", "solid", "dashed", "dotted", "double")

function TV_f_ColapsaNodesFills(PStrClauNode)
{
  var LObjNode;
  
  if (!MObjTV_TreeView.Nodes[PStrClauNode].expandit) return;
  
  for (LObjNode = MObjTV_TreeView.Nodes[PStrClauNode].fill; LObjNode; LObjNode = LObjNode.seguent)
  {
    if (LObjNode.expandit)
      TV_f_ColapsaNodesFills(LObjNode.clau);
  }
  
  MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerVisible("hide");
  
  switch (MObjTV_TreeView.estil)
  {
    case 1:
      if (MObjTV_TreeView.Nodes[PStrClauNode].PlusMinusDiv) MObjTV_TreeView.Nodes[PStrClauNode].PlusMinusDiv.VLine.layerVisible("show");
      break;
    default:
  }
  
  MObjTV_TreeView.Nodes[PStrClauNode].expandit = false;
  
  for (LObjNodeTemp = MObjTV_TreeView.Nodes[PStrClauNode]; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.pare)
  {
    for (LObjNodeTemp2 = LObjNodeTemp.seguent; LObjNodeTemp2; LObjNodeTemp2 = LObjNodeTemp2.seguent)
    {
      LObjNodeTemp2.Div.layerTop(LObjNodeTemp2.Div.layerTop() - MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerHeight());
      if (LObjNodeTemp2.SubMenuDiv) 
        LObjNodeTemp2.SubMenuDiv.layerTop(LObjNodeTemp2.SubMenuDiv.layerTop() - MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerHeight());
      if (LObjNodeTemp2.PlusMinusDiv)
        LObjNodeTemp2.PlusMinusDiv.layerTop(LObjNodeTemp2.PlusMinusDiv.layerTop() - MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerHeight());
    }
  }
  
  if (MObjTV_TreeView.Nodes[PStrClauNode].pare)
  {
    for (LObjNodeTemp = MObjTV_TreeView.Nodes[PStrClauNode].pare; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.pare)
      LObjNodeTemp.SubMenuDiv.layerHeight(LObjNodeTemp.SubMenuDiv.layerHeight() - MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerHeight());
  }
  MObjTV_TreeView.menuDiv.layerHeight(MObjTV_TreeView.menuDiv.layerHeight() - MObjTV_TreeView.Nodes[PStrClauNode].SubMenuDiv.layerHeight());
}

function TV_f_ColapsaNodesArrel_Excepte()
{
  var LObjNode;
  var LIntCounter;
  var LBoolColapsa;
  
  for (LObjNode = MObjTV_TreeView.Nodes[0].arrel.primer; LObjNode; LObjNode = LObjNode.seguent)
  {
    LBoolColapsa = true;
    for (LIntCounter = 0; LIntCounter < arguments.length; LIntCounter++)
    {
      if(arguments[LIntCounter] == LObjNode.clau) LBoolColapsa = false;
    }
    if (LBoolColapsa) TV_f_ColapsaNodesFills(LObjNode.clau);
  }
  TV_f_verifyMenuHeight();  
}


function expandMenu(e)
{
  var LObjNode = eval("MObjTV_TreeView." + this.id);
  var LObjNodeTemp;
  var LObjNodeTemp2;

  if (LObjNode.expandit) 
  {
    TV_f_ColapsaNodesFills(LObjNode.clau)
    MObjTV_TreeView.SelectedNode = "";
  }
  else
  {
    if (MObjTV_TreeView.SelectedNode.length > 0)
    {
      if (MObjTV_TreeView.Nodes[MObjTV_TreeView.SelectedNode].arrel.clau != LObjNode.arrel.clau)
        TV_f_ColapsaNodesFills(MObjTV_TreeView.Nodes[MObjTV_TreeView.SelectedNode].arrel.clau)
      else
      {
        for (LObjNodeTemp = LObjNode.primer; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.seguent)
          if (LObjNodeTemp.clau != LObjNode.clau) TV_f_ColapsaNodesFills(LObjNodeTemp.clau);
      }
    }
    
    if (LObjNode.fills > 0)
    {
      LObjNode.SubMenuDiv.layerVisible("show");
      
      switch (MObjTV_TreeView.estil)
      {
        case 1:
          if (LObjNode.PlusMinusDiv) LObjNode.PlusMinusDiv.VLine.layerVisible("hide");
          break;
        default:
      }
      LObjNode.expandit = true;
      
      for (LObjNodeTemp = LObjNode; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.pare)
      {
        for (LObjNodeTemp2 = LObjNodeTemp.seguent; LObjNodeTemp2; LObjNodeTemp2 = LObjNodeTemp2.seguent)
        {
          LObjNodeTemp2.Div.layerTop(LObjNodeTemp2.Div.layerTop() + LObjNode.SubMenuDiv.layerHeight());
          if (LObjNodeTemp2.SubMenuDiv) 
            LObjNodeTemp2.SubMenuDiv.layerTop(LObjNodeTemp2.SubMenuDiv.layerTop() + LObjNode.SubMenuDiv.layerHeight());
          if (LObjNodeTemp2.PlusMinusDiv)
            LObjNodeTemp2.PlusMinusDiv.layerTop(LObjNodeTemp2.PlusMinusDiv.layerTop() + LObjNode.SubMenuDiv.layerHeight());
        }
      }
    
      for (LObjNodeTemp = LObjNode.pare; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.pare)
      {
        LObjNodeTemp.SubMenuDiv.layerHeight(LObjNodeTemp.SubMenuDiv.layerHeight() + LObjNode.SubMenuDiv.layerHeight());
      }

      MObjTV_TreeView.menuDiv.layerHeight(MObjTV_TreeView.menuDiv.layerHeight() + LObjNode.SubMenuDiv.layerHeight())
    }
    MObjTV_TreeView.SelectedNode = LObjNode.clau;
  }
  
  TV_f_verifyMenuHeight();
  if (MBoolNS) routeEvent(e);
}


/////////////////////////////////////////////////////////////////////////////////////////
//Funció per afegir una nova opció de menú
//PRE: p_relativa               Clau del TreeItem amb el que el nou es relaciona.
//                              La relació ve indicada pel paràmetre p_relacio.
//     p_relacio                Tipus de relació entre el nou treeitem i l'indicat en el
//                              parametre p_relativa.
//     p_clau                   Clau (ID) del nou treeitem.
//     p_texte                  Texte del nou element treeitem (pot ser texte HTML).
//     p_imatge                 Clau de la imatge asociada que es mostrarà al costat del
//                              nou TreeItem.
//     p_imatgeSeleccionada     Clau de la imatge asociada que es mostrarà al costat del
//                              nou TreeItem quan aquest estigui seleccionat.
function TV_f_AddItem(p_relativa, p_relacio, p_clau, p_texte, p_imatge, p_imatgeSeleccionada)
{
  LIntCountTreeItems = this.Nodes.length;
  if (this.DEBUGMODE)
  {
    this.Debug.print("Itentem afegir un nou element a la colecció de nodes amb clau " + p_clau);
  }
  
  if (this.Nodes[p_clau])
  {
    if (this.DEBUGMODE) this.Debug.print("La clau " + p_clau + " del nou element ja està sent utilitzada");
    else alert("La clau " + p_clau + " del nou element ja està sent utilitzada");
    return;
  }
  
  this.Nodes[LIntCountTreeItems] = new TreeItem(p_relativa, p_relacio, p_clau, p_texte, p_imatge, p_imatgeSeleccionada, this);
  eval("this.Nodes." + p_clau + "= this.Nodes[LIntCountTreeItems]");
  if (this.DEBUGMODE)
  {
    this.Debug.print("Hem afegit un nou element a la colecció de nodes amb clau " + p_clau);
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que comproba la necesitat de l'ScrollBar
function TV_f_verifyMenuHeight()
{

  if (MObjTV_TreeView.clipDiv.layerHeight() < MObjTV_TreeView.menuDiv.layerHeight())
  {
    if (MObjTV_TreeView.scrollDiv.layerVisible() == "hide")
    {
      MObjTV_TreeView.scrollDiv.layerVisible("show");
      MObjTV_TreeView.menuDiv.layerTop(MObjTV_TreeView.scrollDiv.layerTop() + MObjTV_TreeView.scrollDiv.layerHeight());
    }
  }
  else
  {
    if (MObjTV_TreeView.scrollDiv.layerVisible() != "hide")
    {
      MObjTV_TreeView.scrollDiv.layerVisible("hide");
      MObjTV_TreeView.menuDiv.layerTop(MObjTV_TreeView.scrollDiv.layerTop());
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Puja el menu un pas
function TV_f_ScrollUpStep()
{  
  if (MObjTV_TreeView.pujant)
  {
    if (MObjTV_TreeView.menuDiv.layerTop() < (MObjTV_TreeView.scrollDiv.layerTop() + MObjTV_TreeView.scrollDiv.layerHeight()))
    {
      MObjTV_TreeView.menuDiv.layerTop(MObjTV_TreeView.menuDiv.layerTop() + 10);
      setTimeout ("TV_f_ScrollUpStep()", 100);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que puja el menu en apretar el botó de VScroll up
function TV_f_ScrollUp()
{

  this.pujant = true;
  TV_f_ScrollUpStep();
}

function TV_f_ScrollDown()
{

  this.baixant = true;
  TV_f_ScrollDownStep();
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció que baixa el menú en apretar el botó de VScroll down
function TV_f_ScrollDownStep()
{

  if (MObjTV_TreeView.baixant)
  {
    if (MObjTV_TreeView.menuDiv.layerTop() + MObjTV_TreeView.menuDiv.layerHeight() > MObjTV_TreeView.clipDiv.layerHeight())
    {
      MObjTV_TreeView.menuDiv.layerTop(MObjTV_TreeView.menuDiv.layerTop() - 10);
      setTimeout ("TV_f_ScrollDownStep()", 100);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Para de pujar o baixar el menú
function TV_f_ScrollStop()
{

  this.pujant = false;
  this.baixant = false;
}

function TV_f_SetNodeText(PStrNodeName, PStrText)
{
  var LObjNode = eval("this.Nodes." + PStrNodeName);
  var LObjNodeTemp;
  var LIntTopNextItem;
  var LIntOldDivHeight;
  var LIntNewDivHeight;

  if (LObjNode)
  {
    LObjNode.texte = PStrText
    LObjNode.Div.setText(LObjNode.texte);
    LIntTopNextItem = LObjNode.Div.layerTop();
    LIntOldDivHeight = LObjNode.Div.layerHeight();
    LIntNewDivHeight = LObjNode.Div.layerHeight();
    LIntTopNextItem = LIntTopNextItem + LIntNewDivHeight;
  
    if (LObjNode.pare)
    {
      LObjNode.pare.SubMenuDiv.layerHeight(LObjNode.pare.SubMenuDiv.layerHeight() - LIntOldDivHeight + LIntNewDivHeight);
    }
  
    for (LObjNodeTemp = LObjNode.seguent; LObjNodeTemp; LObjNodeTemp = LObjNodeTemp.seguent)
    {
      LObjNodeTemp.Div.layerTop(LIntTopNextItem);
      LIntTopNextItem = LIntTopNextItem + LObjNodeTemp.Div.layerHeight();
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////
//Render dels nodes del menu
function TV_f_PintaBranca(PObjNode, PObjTreeView, PIntNivell, PDivPare)
{
  var LIntTopNewItem = 0;
  var LIntLeftStart = PObjTreeView.indentacio * (PIntNivell - 1) ;
  
  var LObjNode;
  
  for (LObjNode = PObjNode; LObjNode; LObjNode = LObjNode.seguent)
  {
    
    if ((LObjNode.fills > 0) && (PIntNivell > 1))
    {
      switch (PObjTreeView.estil)
      {
        case 1: 
          LObjNode.PlusMinusDiv = new CLayer("PlusMinus" + LObjNode.clau, PDivPare.Div, LIntTopNewItem + 4, (PObjTreeView.indentacio / 2) - 4, 6, 6, "lightsteelblue", "inherit", 1, "darkgray");
          LObjNode.PlusMinusDiv.layerAutoSize(false);
          LObjNode.PlusMinusDiv.layerWidth(9);
          LObjNode.PlusMinusDiv.layerHeight(9);
          LObjNode.PlusMinusDiv.HLine = new CLayer("HLine" + LObjNode.clau, LObjNode.PlusMinusDiv.Div, ((LObjNode.PlusMinusDiv.layerHeight() - 1) / 2) -1, 1, LObjNode.PlusMinusDiv.layerWidth() - 2, 1, "midnightblue");
          LObjNode.PlusMinusDiv.HLine.layerAutoSize(false);
          LObjNode.PlusMinusDiv.HLine.layerWidth(LObjNode.PlusMinusDiv.layerWidth() - 4);
          LObjNode.PlusMinusDiv.HLine.layerHeight(1);
          LObjNode.PlusMinusDiv.VLine = new CLayer("VLine" + LObjNode.clau, LObjNode.PlusMinusDiv.Div, 1,((LObjNode.PlusMinusDiv.layerWidth() - 1) / 2) -1, 1, LObjNode.PlusMinusDiv.layerHeight() - 2, "midnightblue");
          LObjNode.PlusMinusDiv.VLine.layerAutoSize(false);
          LObjNode.PlusMinusDiv.VLine.layerHeight(LObjNode.PlusMinusDiv.layerHeight() - 4);
          LObjNode.PlusMinusDiv.VLine.layerWidth(1);

          switch (MStrNavegador)
          {
            case "NS":
              {
                LObjNode.PlusMinusDiv.Div.captureEvents(Event.MOUSEUP);
                LObjNode.PlusMinusDiv.Div.onMouseUp = expandMenu;
                break;
              }
            case "IE":
              { 
                LObjNode.PlusMinusDiv.Div.onmouseup = expandMenu;
                break;
              }
          }
          eval("PObjTreeView." + LObjNode.PlusMinusDiv.Div.id + " = LObjNode");
          break;
      }
    }  
    
    LObjNode.Div = new CLayer(LObjNode.clau, PDivPare.Div, LIntTopNewItem, LIntLeftStart, PDivPare.layerWidth() - LIntLeftStart)
    eval("PObjTreeView." + LObjNode.Div.Div.id + " = LObjNode");
    LObjNode.Div.layerVisible("inherit");
    LObjNode.Div.setText(LObjNode.texte);

    switch (MStrNavegador)
    {
      case "NS":
        {
          LObjNode.Div.layerAutoSize(true)
          LObjNode.Div.Div.captureEvents(Event.MOUSEUP);
          LObjNode.Div.Div.onMouseUp = expandMenu;
          break;
        }
      case "IE":
        { 
          LObjNode.Div.layerAutoSize(false);
          LObjNode.Div.layerWidth(PDivPare.layerWidth() - LIntLeftStart);
          LObjNode.Div.Div.onmouseup = expandMenu;
          break;
        }
    }

    LIntTopNewItem += LObjNode.Div.layerHeight();
    
    PDivPare.layerHeight(LIntTopNewItem);
    
    if (LObjNode.fills > 0) 
    {
      LObjNode.SubMenuDiv = new CLayer("SubMenu" + LObjNode.clau, PDivPare.Div, LIntTopNewItem, 0, PDivPare.layerWidth());
      LObjNode.SubMenuDiv.layerAutoSize(false);
      LObjNode.SubMenuDiv.layerVisible("hide");
      LObjNode.SubMenuDiv.layerWidth(PDivPare.layerWidth());
      TV_f_PintaBranca(LObjNode.fill, PObjTreeView, PIntNivell + 1, LObjNode.SubMenuDiv);
    }
  }
  
  //PDivPare.layerHeight(PDivPare.layerHeight() + 300);
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció per pintar l'arbre a la plana
function TV_f_render()
{
  
  var LStrScroll;

  this.clipDiv = new CLayer("Clip_" + this.Nom);
  this.clipDiv.layerAutoSize(false);
  this.clipDiv.layerVisible((this.visible? "show" : "hide"));
  this.clipDiv.layerTop(this.Top);
  this.clipDiv.layerLeft(this.Left);
  this.clipDiv.layerHeight(this.Height);
  this.clipDiv.layerWidth(this.Width);
  
  if (this.estilMarc != tv_em_cap)
  {
    if (this.colorFons > 0) this.clipDiv.layerBgColor(this.colorFons);
    if (this.colorMarc.length > 0) this.clipDiv.layerBorderColor(this.colorMarc);
    if (this.ampladaMarc.length > 0) this.clipDiv.layerBorderWidth(this.ampladaMarc); 
  }
  this.clipDiv.layerBorderStyle(tv_em_array_IE[this.estilMarc]);
  
  this.menuDiv = new CLayer(this.Nom, this.clipDiv.Div, 0, 0, this.clipDiv.layerWidth());
  this.menuDiv.layerVisible("inherit");

  if (this.wrap) 
  {
    this.menuDiv.layerAutoSize(false);
    this.menuDiv.layerWidth(this.Width);
  }
  else this.menuDiv.layerAutoSize(true);

  this.scrollDiv = new CLayer("Scroll_" + this.Nom, this.clipDiv.Div, 0, 0, this.clipDiv.layerWidth(), null, null, "hide");
  this.scrollDiv.layerAutoSize(true);
  
  
  //MMT: En properes versions crearem una ScrollBar a partir d'un objecte Scrollbar personalitzable
  LStrScroll = "<Table Width='100%' Bgcolor='#000000' Height='20' Cellspacing='0' Cellpadding='1' border='0'><Tr><Td><TABLE width='100%' Bgcolor='#FFFFFF' height='19' cellspacing='0' cellpadding='0' border='0'>";
  LStrScroll += "<TR>";
  LStrScroll += "<TD width='20' height='19'><a href='javascript:void(0);' onMouseDown='MObjTV_TreeView.scrollUp(); return false;' onMouseUp='MObjTV_TreeView.scrollStop(); return false;' onMouseOut='MObjTV_TreeView.scrollStop(); return false;'><img src='" + this.directoriImatges + "up_arrow.gif' border='0' width='20' height='19'></a></TD>";
  LStrScroll += "<TD width='143' height='19'><IMG src='" + this.directoriImatges + "espacio.gif' width='1' height='1'></TD>";
  LStrScroll += "<TD width='20' height='19'><a href='javascript:void(0);' onMouseDown='MObjTV_TreeView.scrollDown(); return false;' onMouseUp='MObjTV_TreeView.scrollStop(); return false;' onMouseOut='MObjTV_TreeView.scrollStop(); return false;'><img src='" + this.directoriImatges + "down_arrow.gif' border='0' width='20' height='19'></a></TD>";
  LStrScroll += "</TR>";
  LStrScroll += "<TR>";
  LStrScroll += "<TD colspan=3><IMG src='" + this.directoriImatges + "espacio.gif' border=0></TD>";
  LStrScroll += "</TR>";
  LStrScroll += "</TABLE></Td></Tr></Table>";
  
  this.scrollDiv.setText(LStrScroll);  
    
  TV_f_PintaBranca(this.Nodes[0].arrel.primer, this, 1, this.menuDiv);
  
  TV_f_verifyMenuHeight();
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció per cambiar el tamany de la capa de clip
function TV_f_ResizeClip(p_Left, p_Top, p_Width, p_Height)
{

  this.Left = p_Left;
  this.Height = p_Height;
  this.Top = p_Top;
  this.Width = p_Width;

  this.clipDiv.layerLeft(p_Left);
  this.clipDiv.layerTop(p_Top);
  this.clipDiv.layerHeight(p_Height);
  this.clipDiv.layerWidth(p_Width);
  TV_f_verifyMenuHeight();
}

/////////////////////////////////////////////////////////////////////////////////////////
//Funció per amagar o mostrar l'arbre
function TV_f_ShowHide(p_Show)
{
  this.clipDiv.layerVisible((p_Show?"show":"hide"))
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Constructor de l'objecte TreeView
function TreeView()
{
  
  //Aparença
  this.estilLinea = tv_el_Arbre       //No implementat: Estil de representació de les líneas de l'arbre.
                                      //                estils valids són:
                                      //                          -tv_el_Arbre, les líneas ssurten dels items del menú
                                      //                           arrel cap als seus fills i d'aquests als fills 
                                      //                           corresponents
                                      //                          -tv_el_Arrel, les líneas acompanyen també als items
                                      //                           del menú arrel de l'arbre.
  this.indentacio = 22;               //No implementat: Separació entre la posició esquerra d'una capa i la posició
                                      //esquerra dels menus "fills".
  
  //Comportament
  this.scroll = true;                 //No implementat: Estableix si s'han de mostrar o no scrollbars quan el contingut
                                      //de l'arbre sobrepassi els marges del marc de la capa contenedora
  this.seleccioUnica = true;          //No implementat: Estableix que quan es selecciona un element els demes es 
                                      //contrauen automàticament
  this.ordenat = true;                //No implementat: Estableix que s'ordenin els elements de cada menú alfabèticament
  this.estil = tv_ea_MesMenys;        //No implementat: Estil de l'arbre, pot ser una combinació d'estils amb
                                      //                estils valids son: 
                                      //                          -tv_ea_MesMenys, els items de l'arbre que tinguin
                                      //                           fills tindran un signe més al costat que es convertirá
                                      //                           en un signe menys quan es desplegui el submenú
                                      //                          -tv_ea_LineasArbre cada item d'unsubmenu tindrá
                                      //                           una linea que l'unirá amb el pare.
                                      //                          -tv_ea_Imatge, els items podran tenir una icona al
                                      //                           costat sempre que es defineixin a l'hora d'afegir
                                      //                           el item. Les imatges poden ser diferents per elements
                                      //                           seleccionats i per elements no seleccionats
  this.visible = true;                //Estableix si l'arbre és o no és visible

  //Altres
  this.Nom = "Menu";                  //Nom del TreeView en principi no podrien haver-hi dos treeviews en el document
                                      //amb noms iguals per tant es recomana cambiar el nom avans de fer el render del 
                                      //treeview
  this.estilControl;                  //No implementat: Estil del Control.
                                      //                estils valids son:
                                      //                          -tv_ec_3D
                                      //                          -tv_ec_Pla
  this.colorFons = "#FFFFFF";         //Color de fons de la capa contenedora de l'arbre.
  this.ampladaMarc = 0;               //Amplada del marc en pixels de la capa contenedora de l'arbre.
  this.colorMarc = "";                //Color del marc en pixels de la capa contenedora de l'arbre.
  this.estilMarc = tv_em_cap;         //Estil del marc en pixels de la capa contenedora de l'arbre.
                                      //                estils valids son: 
                                      //                          -tv_em_cap, sense linea
                                      //                          -tv_em_solid, una sola linea solida 
                                      //                          -tv_em_guions, una sola linea de guions
                                      //                          -tv_em_punts, una sola linea de punts
                                      //                          -tv_em_doble, dues línees sòlides paral.leles
  this.tooltipText = ""               //No implementat: en cas d'especificar una cadena, aquesta es mostrará quan el 
                                      //cursor es mogui per sobre de l'arbre.
                                      
  //Posició
  switch (MStrNavegador)
  {
    case "NS":
      {
        this.Height = Math.ceil(window.innerHeight / 4);
        this.Left = 3 * Math.ceil(window.innerWidth / 8);
        this.Top = 3 * Math.ceil(window.innerHeight  / 8);
        this.Width = Math.ceil(window.innerWidth / 4);
        break;
      }
    case "IE":
      {
        this.Height = Math.ceil(window.screen.availHeight / 4);
        this.Left = 3 * Math.ceil(window.screen.availWidth / 8);
        this.Top = 3 * Math.ceil(window.screen.availHeight / 8);
        this.Width = Math.ceil(window.screen.availWidth / 4);
      }
  }

  //Altres
  this.baixant = false;
  this.Nom = "TV_Menu";
  this.pujant = false;
  this.SelectedNode = "";
  this.VScroll = "VScroll";
  this.wrap = true;
  
  this.directoriImatges = ""; //Directori on el control pot trobar les imatges necessaries

  //Funcions
  this.Render = TV_f_render;
  this.AddItem = TV_f_AddItem;
  
  this.setNodeText = TV_f_SetNodeText;
  this.colapsaNodesExcepte = TV_f_ColapsaNodesArrel_Excepte;
  
  this.resize = TV_f_ResizeClip;
  this.scrollDown = TV_f_ScrollDown;
  this.scrollStop = TV_f_ScrollStop;
  this.scrollUp = TV_f_ScrollUp;
  this.setVisibility = TV_f_ShowHide;
  this.DEBUGMODE = false;
  this.Nodes = new Array();

  MObjTV_TreeView = this;
}