/* To set via TAG: Node template */
var TEMPLATE_NODE = "<a href=\"javascript: toggleNode('$id$', '$tree$');\"><img src=\"$icon$\" toggle=\"icon\" align=\"absmiddle\" border=\"0\" /></a><a href=\"$href$\" target=\"$target$\" ondblclick=\"toggleNode('$id$', '$tree$');\">$name$</a>";

/* To set via TAG: Node default attributes */
var NODE_ATTRIBUTES = "";

/* To set via TAG: Indent width */
var CHILD_INDENT = "16px";

/* The base url to fetch new nodes, need to append some params only */
var TREE_SERVLET = "";

/* The current frame */
var CURRENT_FRAME= "navigate";

/* UI functions: Toggle the node */
function toggleNode(ID, Tree)
{
  var _tree = document.getElementById(Tree);

  var _cursorstate = _tree.style.cursor;
  _tree.style.cursor = "wait";

  var _node = document.getElementById(Tree + "+" + ID);
  var _childs = document.getElementById(Tree + "+" + "childs_" + ID);

  if (_node && _childs)
  {
    /* Everything available, hide or show ... */
    if (_childs.style.display=="none")
    {
      toggleContent(ID, _node, true);
      _childs.style.display = "block";
            setNodeOpened(ID);
    }
    else
    {
      toggleContent(ID, _node, false);
      _childs.style.display = "none";
            setNodeClosed(ID);
    }
  }
  else if (_node)
  {
    /* Node available, but no content ... toggle node and load content */
    toggleContent(ID, _node, true);
    setNodeOpened(ID);

    /* Callback, when loading finished ... '*/
    appendChilds = function(xmlDoc, Container)
    {
      rootElement = xmlDoc.documentElement;
      if (!rootElement.firstChild) return;
      child = rootElement.firstChild;

      do
      {
        Container.appendChild(getNode(new Element(child), Tree));

        if (child.getAttribute("open")=="true")
        {
          toggleNode(child.getAttribute("guid"), Tree);
        }
        child = child.nextSibling;
      }
      while (child!=null);
    }

    childsContainer = getContainer(ID, Tree);
    loadXmlDocument(ID, appendChilds, childsContainer);

    _node.appendChild(childsContainer);
  }
  else
  {
    appendChilds = function(xmlDoc, Tree)
    {
      rootElement = xmlDoc.documentElement;
      Tree.appendChild(getNode(new Element(rootElement), Tree.id));

      if (rootElement.getAttribute("open")=="true")
        toggleNode(rootElement.getAttribute("guid"), Tree.id);
    }

    loadXmlDocument(ID, appendChilds, _tree);
  }

  if (_cursorstate=="") _cursorstate = "auto";
  _tree.style.cursor = _cursorstate;
}

function setNodeActive(ID, Tree)
{
  var _tree = document.getElementById(Tree);
  var _node = document.getElementById(Tree + "+" + ID);
}

/* Create a new (child)node */
function getNode(Element, Tree)
{
  var _node = document.createElement("div");

  _node.id = Tree + "+" + Element.guid;
  _node.innerHTML = renderContent(TEMPLATE_NODE, Element, Tree);

  return _node;
}

/* Create a new container for child nodes */
function getContainer(ID, Tree)
{
  var _container = document.createElement("div");

  _container.id = Tree + "+" + "childs_" + ID;
  _container.style.paddingLeft = CHILD_INDENT;

  return _container;
}

/* Merge template and element to output ... */
function renderContent(Template, Element, Tree)
{
  var _keyregex = /\$([\w\_]+)\$/;
  var terminator = 256;

  while (_keyregex.test(Template) && terminator>0)
  {
    _result = _keyregex.exec(Template);

    _replace = "\\$" + _result[1] + "\\$";
    _replacereg = new RegExp(_replace, "g");

    if (_result[1]=="tree")
      _value = Tree;
    else
      if (Element[_result[1]])
        _value = Element[_result[1]];
      else
        _value = "";

    Template = Template.replace(_replacereg, _value);

    terminator--;
  }

  return Template;
}

/* Toogle element content, like icon ... */
function toggleContent(ID, Node, Active)
{
  for (i=0; i<Node.childNodes.length; i++)
  {
    if (document.all || Node.childNodes[i].getAttribute)
    {
      if (Node.childNodes[i] && Node.childNodes[i].getAttribute && (_attr = Node.childNodes[i].getAttribute("toggle")))
      {
        if (Node.childNodes[i].nodeType==1)
        {
          if (Node.childNodes[i].nodeName.toLowerCase()=="img")
          {
            if (Active)
              Node.childNodes[i].src = renderContent("$_" + _attr + "$", ElementStack[ID]);
            else
              Node.childNodes[i].src = renderContent("$" + _attr + "$", ElementStack[ID]);
          }
          else
          {
            if (Active)
              Node.childNodes[i].innerHTML = renderContent("$_" + _attr + "$", ElementStack[ID]);
            else
              Node.childNodes[i].innerHTML = renderContent("$" + _attr + "$", ElementStack[ID]);
          }
        }
      }
    }

    if (Node.childNodes[i].hasChildNodes() && !Node.childNodes[i].id.match(/^childs/)) toggleContent(ID, Node.childNodes[i], Active);
  }
}

function getHttpRequestObject()
{
  if(window.ActiveXObject && navigator.userAgent.match(/Win/))
  {
    return new ActiveXObject("Microsoft.XMLHTTP");
  }
  else if (document.implementation && document.implementation.createDocument)
  {
    return new XMLHttpRequest();
  }
  else
  {
    return null;
  }
}

function loadXmlDocument(ID, callbackFunction, Container)
{
  var request = getHttpRequestObject();

  if (!request) return null;

  request.open("POST", TREE_SERVLET, true);
  request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

  request.onreadystatechange=function()
  {
    if (request.readyState==4)
    {
      callbackFunction(request.responseXML, Container);
      request = null;
    }
  }

  request.send("root=" + ID + "&params=guid,descr,href,target&action=open&target=" + CURRENT_FRAME);
}

function setNodeOpened(ID)
{
  var URL = TREE_SERVLET + "?root=" + ID + "&action=open";
  var request_opened = getHttpRequestObject();

  request_opened.open("GET", URL, false);
}

function setNodeClosed(ID)
{
  var URL = TREE_SERVLET + "?root=" + ID + "&action=close";
  var request_close = getHttpRequestObject();

  request_close.open("GET", URL, false);
  request_close.send(null);
}

/* Elementstack for later usage of elements */
var ElementStack = new Array();

/* An element */
function Element(Attributes)
{
  this.id = Attributes.guid;

  /* Fill object with default attributes */
  _tmp = NODE_ATTRIBUTES.split(" ");
  for (i=0; i<_tmp.length; i++)
  {
    _tmppair = _tmp[i].split("=");
    this[_tmppair[0]] = _tmppair[1];
  }

  /* Make attributes an array, if it is a string */
  if (typeof Attributes == "string")
  {
    _tmp = Attributes.split(" ");
    Attributes = new Array();

    for (i=0; i<_tmp.length; i++)
    {
      _tmppair = _tmp[i].split("=");
      Attributes[_tmppair[0]] = _tmppair[1];
    }
  }

  /* Make attributes an array, if it is an xml element */
  if (typeof Attributes == "object" && Attributes.attributes)
  {
    var _tmp = new Array();

    for (i=0; i<Attributes.attributes.length; i++)
    {
      _tmp[Attributes.attributes[i].nodeName] = Attributes.attributes[i].nodeValue;
    }

    Attributes = _tmp;
  }

  /* Merge attributes to element */
  for (key in Attributes) 
  {
    this[key] = Attributes[key].replace(/\n/, "");
  }

  /* Put element to stack */
  ElementStack[this.guid] = this;
}
