/**************************************************************************
	Copyright (c) 2001 Geir Landrö (drop@destroydrop.com)
	JavaScript Tree - www.destroydrop.com/hugi/javascript/tree/
	Version 0.96

	This script can be used freely as long as all copyright messages are
	intact.

Modificado por Nelson H. C. Nepomuceno (nelson@integrasoftware.com.br)
Esta versão utiliza indexação e busca binária para otimizar a árvore
Versão 0.96	NN-WL 
**************************************************************************/

// Arrays for nodes and icons
var nodes	= new Array();
var openNodes	= new Array();
var icons	= new Array(6);

// Campos da Árvore
var Arv_Id      = new Array();
var Arv1_Id     = new Array();
var Arv_Nome    = new Array();
var Arv_Link    = new Array();
var Arv_Nivel			= new Array(); // Preenchido em AddNode. Armazena nível da árvore para definir a cor das pastas. 

// Pastas Coloridas
var icoPastaFch = new Array(); // Pastas Fechadas por Nível
var icoPastaAbr = new Array(); // Pastas Abertas por Nível

// Loads all icons that are used in the tree
function preloadIcons() {
  icons[0] = new Image();
  icons[0].src = "images/menu/plus.gif";
  icons[1] = new Image();
  icons[1].src = "images/menu/plusbottom.gif";
  icons[2] = new Image();
  icons[2].src = "images/menu/minus.gif";
  icons[3] = new Image();
  icons[3].src = "images/menu/minusbottom.gif";

  // Pastas Coloridas
  icoPastaFch[0] = new Image();
  icoPastaFch[0].src = "images/menu/folder_n1.gif";
  icoPastaAbr[0] = new Image();
  icoPastaAbr[0].src = "images/menu/folderopen_n1.gif";

  icoPastaFch[1] = new Image();
  icoPastaFch[1].src = "images/menu/folder_n2.gif";
  icoPastaAbr[1] = new Image();
  icoPastaAbr[1].src = "images/menu/folderopen_n2.gif";

  icoPastaFch[2] = new Image();
  icoPastaFch[2].src = "images/menu/folder_n3.gif";
  icoPastaAbr[2] = new Image();
  icoPastaAbr[2].src = "images/menu/folderopen_n3.gif";

  icoPastaFch[3] = new Image();
  icoPastaFch[3].src = "images/menu/folder_n4.gif";
  icoPastaAbr[3] = new Image();
  icoPastaAbr[3].src = "images/menu/folderopen_n4.gif";

  icoPastaFch[4] = new Image();
  icoPastaFch[4].src = "images/menu/folder_n4.gif";
  icoPastaAbr[4] = new Image();
  icoPastaAbr[4].src = "images/menu/folderopen_n4.gif";

  icoPastaFch[5] = new Image();
  icoPastaFch[5].src = "images/menu/folder_n4.gif";
  icoPastaAbr[5] = new Image();
  icoPastaAbr[5].src = "images/menu/folderopen_n4.gif";

  icoPastaFch[6] = new Image();
  icoPastaFch[6].src = "images/menu/folder_n4.gif";
  icoPastaAbr[6] = new Image();
  icoPastaAbr[6].src = "images/menu/folderopen_n4.gif";
}

// Create the tree
function createTree(arrName, startNode, openNode) {
  nodes = arrName;

  for (i=0; i<nodes.length; i++) {
    var nodeValues = nodes[i].split("|");
    Arv_Id.push(nodeValues[0]);
    Arv1_Id.push(nodeValues[1]);
    Arv_Nome.push(nodeValues[2]);
    Arv_Link.push(nodeValues[3]);
				Arv_Nivel.push(0);
  }

  if (nodes.length > 0) {
    preloadIcons();
    if (startNode == null) startNode = 0;
    if (openNode != 0 || openNode != null) setOpenNodes(openNode);

    if (startNode !=0) {
      var nodeValues = nodes[getArrayId(startNode)].split("|");
      document.write("<B><a href=\"" + nodeValues[3] + "\" onmouseover=\"window.status='");
      document.write(nodeValues[2] + "';return true;\" onmouseout=\"window.status=' ';return true;\">");
      document.write("<img src=\"" + icoPastaAbr[0].src + "\"");
      document.write(" align=\"absbottom\" alt=\"\" />" + nodeValues[2] + "</a><br /></B>");
    } else document.write("<img src=\"images/menu/base.gif\" align=\"absbottom\" alt=\"\" />Website<br />");

    var recursedNodes = new Array();
    addNode(startNode, recursedNodes, 1);
  }
}

// Returns the position of a node in the array
function getArrayId(node) {
  for (i=0; i<nodes.length; i++) {
    if (Arv_Id[i]==node) return i;
  }
}

// Puts in array nodes that will be open
function setOpenNodes(openNode) {
  for (i=0; i<nodes.length; i++) {
    if (Arv_Id[i]==openNode) {
      openNodes.push(Arv_Id[i]);
      setOpenNodes(Arv1_Id[i]);
    }
  }
}

// Checks if a node is open
function isNodeOpen(node) {
  for (i=0; i<openNodes.length; i++)
    if (openNodes[i]==node) return true;
  return false;
}

// Encontrar algum índice do vetor com o valor de Pasta1_Id
function AnyPasta1Index (Pasta1_Id) {
  // Nelson: Busca Binária: Vetores devem estar ordenados por Arv1_Id
  var Min = 0;
  var Max = nodes.length - 1;
  while (Min <= Max) {
    var Rec = Math.floor((Min + Max) / 2);

    if (Pasta1_Id == Arv1_Id[Rec])
      return Rec;
    if (Number(Pasta1_Id) < Number(Arv1_Id[Rec]))
      var Max = Rec - 1;
    else
      var Min = Rec + 1;
  }

  return -1;
}

// Checks if a node has any children
function hasChildNode(parentNode) {
  var idx = AnyPasta1Index(parentNode);
  if (idx == -1) return false
    else return true;
}

// Checks if a node is the last sibling
function lastSibling (node, parentNode) {
  // Nelson: Encontrar algum item com o mesmo Pasta1_Id (parentNode)
  var lastChild = 0;
  var idx = AnyPasta1Index(parentNode);
  if (idx == -1) { // se não encontrar nenhum...
    if (lastChild==node) return true;
    return false;
  }
  for (i=idx; i< nodes.length; i++) {
    if (Arv1_Id[i] == parentNode)
      lastChild = Arv_Id[i]
    else break;
  }
  if (lastChild==node) return true;
  return false;
}

// Adds a new node in the tree
function addNode(parentNode, recursedNodes, nivel) {
  for (var i = 0; i < nodes.length; i++) {

    if (Arv1_Id[i] == parentNode) {

    		Arv_Nivel[i] = nivel; // preencher nível do nó
      var ls  = lastSibling(Arv_Id[i], Arv1_Id[i]);
      var hcn = hasChildNode(Arv_Id[i]);
      var ino = isNodeOpen(Arv_Id[i]);

      // Write out line & empty icons
      for (g=0; g<recursedNodes.length; g++) {
        if (recursedNodes[g] == 1) document.write("<img src=\"images/menu/line.gif\" align=\"absbottom\" alt=\"\" />");
        else  document.write("<img src=\"images/menu/empty.gif\" align=\"absbottom\" alt=\"\" />");
      }

      // put in array line & empty icons
      if (ls) recursedNodes.push(0);
        else recursedNodes.push(1);

      // Write out join icons
      if (hcn) {
        if (ls) {
          document.write("<a href=\"javascript: oc(" + Arv_Id[i] + ", 1, "+nivel+");\"><img id=\"join" + Arv_Id[i] + "\" src=\"images/menu/");
          if (ino) document.write("minus");
          else document.write("plus");
          document.write("bottom.gif\" align=\"absbottom\" alt=\"Open/Close node\" /></a>");
        } else {
          document.write("<a href=\"javascript: oc(" + Arv_Id[i] + ", 0, "+nivel+");\"><img id=\"join" + Arv_Id[i] + "\" src=\"images/menu/");
          if (ino) document.write("minus");
          else document.write("plus");
          document.write(".gif\" align=\"absbottom\" alt=\"Open/Close node\" /></a>");
        }
      } else {
        if (ls) document.write("<img src=\"images/menu/join.gif\" align=\"absbottom\" alt=\"\" />");
        else document.write("<img src=\"images/menu/joinbottom.gif\" align=\"absbottom\" alt=\"\" />");
      }

      // Start link
      document.write("<a href=\"" + Arv_Link[i] + "\" onmouseover=\"window.status='" + Arv_Nome[i] + "';return true;\" onmouseout=\"window.status=' ';return true;\">");

      // Write out folder & page icons
      if (hcn) {
        document.write("<img id=\"icon" + Arv_Id[i] + "\" src=\"");
        if (ino)
          document.write(icoPastaAbr[nivel].src)
        else
          document.write(icoPastaFch[nivel].src);
        document.write("\" align=\"absbottom\" alt=\"Folder\" />");
      } else {
        document.write("<img id=\"icon" + Arv_Id[i] + "\" src=\"");
        if ((ino) && (Arv_Id[i] = openNodes[0]))
          document.write(icoPastaAbr[nivel].src)
        else
          document.write(icoPastaFch[nivel].src);
        document.write("\" align=\"absbottom\" alt=\"Folder\" />");
      }

      // Write out node name
      if (ino) {
        document.write("<B>" + Arv_Nome[i] +"</B>");}
      else {
        document.write(Arv_Nome[i]);}

      // End link
      document.write("</a><br />");

      // If node has children write out divs and go deeper
      if (hcn) {
        document.write("<div id=\"div" + Arv_Id[i] + "\"");
        if (!ino) document.write(" style=\"display: none;\"");
        document.write(">");
        addNode(Arv_Id[i], recursedNodes, nivel+1);
        document.write("</div>");
      }

      // remove last line or empty icon
      recursedNodes.pop();
    }
  }
}


/* Nelson 20/07/2005: Comentário sobre a function oc
   Este método poderia ser muito melhorado se houvesse um controle (a partir de um array) dos nós que
   estão abertos, pois IsNodeOpen retorna os nós que iniciam abertos por fazer parte da seleção.]
	 Então este método deveria ter um parâmetro para determinar se está abrindo ou fechando o nó. */
// Opens or closes a node	 
function oc(node, bottom, nivel) {
  var theDiv = document.getElementById("div" + node);
  var theJoin	= document.getElementById("join" + node);
  var theIcon = document.getElementById("icon" + node);

  if (theDiv.style.display == 'none') {
    if (bottom==1) theJoin.src = icons[3].src;
    else theJoin.src = icons[2].src;
    theIcon.src = icoPastaAbr[nivel].src;
    theDiv.style.display = '';
  } else {
    if (bottom==1) theJoin.src = icons[1].src;
    else theJoin.src = icons[0].src;
    theIcon.src = icoPastaFch[nivel].src;
    theDiv.style.display = 'none';
  }
}

// Nelson: Abrir todos os nós abaixo 
function ExpandAll() {
  var i;
  for (i=0; i<nodes.length; i++) {
    if ( (Arv_Nivel[i] > 0)
				     && (hasChildNode(Arv_Id[i]) == true)	
									&& (isNodeOpen(Arv_Id[i]) == false) ) {	 
  		  oc(Arv_Id[i], 1, Arv_Nivel[i]);
				}
  }
}

// Nelson 19/06/2009: Iniciar a Árvore com os nós abertos, conforme o nível (só funciona para abrir!)
function AjustarPorNivel(status, nivelMin, nivelMax) {
  /* Este método deve ser executado apenas após criar a árvore. Quando a árvore é criada, os nós que
	   fazem parte do caminho do nó selecionado aparecem abertos. Esses nós são os que isNodeOpen retorna true.
		 O nó nivel 2 já inicia aberto. 
     Este método pode abrir níveis abaixo de um item, sem que ele seja aberto, de forma que quando for aberto,
     os níveis abaixo já apareçam espandidos. */ 		 
  var i;
	// loop de nós
  for (i=0; i<nodes.length; i++) {
    if (hasChildNode(Arv_Id[i]) == true)
		{
		  if ( (Arv_Nivel[i] >= nivelMin) && (Arv_Nivel[i] <= nivelMax) && (isNodeOpen(Arv_Id[i]) != status) ) 
  	    {	oc(Arv_Id[i], 1, Arv_Nivel[i]); } /* inverter nó ??? (aberto / fechado) */ 
		}
	}
}


// Nelson 15/07/2005: Iniciar a Árvore com todos os nós com nível acima de 2 abertos, além dos nós selecionados
function Expandir2N() {
  /* Este método deve ser executado apenas após criar a árvore. Quando a árvore é criada, os nós que
	   fazem parte do caminho do nó selecionado aparecem abertos. Esses nós são os que isNodeOpen retorna true.
		 O nó nivel 2 já inicia aberto. 
		 Esse nó apenas abrirá todos os nós a partir do nível 3, de tal forma que ao abrir um nó do nível 2,
		 toda a descendência seja aberta também. */ 		 
  var i;
	// Abrir todos os nós acima do nível 2, que não façam parte da seleção, e portanto, ainda não estejam abertos
  for (i=0; i<nodes.length; i++) {
    if (hasChildNode(Arv_Id[i]) == true)
		{
		  if ( (Arv_Nivel[i] > 1) && (isNodeOpen(Arv_Id[i]) == false) ) 
  	    {	oc(Arv_Id[i], 1, Arv_Nivel[i]); }
		}
	}
}

// Push and pop not implemented in IE(crap!    don´t know about NS though)
if(!Array.prototype.push) {
  function array_push() {
    for(var i=0;i<arguments.length;i++)
    this[this.length]=arguments[i];
    return this.length;
  }
  Array.prototype.push = array_push;
}
if(!Array.prototype.pop) {
  function array_pop(){
    lastElement = this[this.length-1];
    this.length = Math.max(this.length-1,0);
    return lastElement;
  }
  Array.prototype.pop = array_pop;
}
