function TreeControlFactory()
{
  throw new Error("TreeControlFactory is a static class and, as such, can neither be instantiated nor called directly.");
}

TreeControlFactory.expandImagePath = "/images/TreeExpand.gif";
TreeControlFactory.collapseImagePath = "/images/TreeCollapse.gif";

TreeControlFactory.createTreeControls = function ()
{
  // get all the ULs
  var trees = document.getElementsByTagName("ul");
  // narrow down the ULs to only those with the TreeControl class
  for (var i = 0; i < trees.length; i++)
  {
    if (containsClassName(trees[i], "TreeControl"))
    {
      // now that we've got the main TreeControl container, the root node, we
      // need to crawl the tree and assign custom properties and events to its
      // child nodes to make the TreeControl work
      var subtrees = trees[i].getElementsByTagName("ul");
      for (var j = 0; j < subtrees.length; j++)
      {
        addClassName(subtrees[j].parentNode, "Branch");
        
        if (containsClassName(subtrees[j], "Expand"))
        {
          expandSubtree(trees[i], subtrees[j]);
        }
        else
        {
          subtrees[j].treeState = "collapsed";
        }
        
        subtrees[j].parentNode.onclick = function (e)
        {
          var subtree = this.getElementsByTagName("ul")[0];
          if (subtree.treeState == "collapsed")
          {
            subtree.style.display = "block";
            subtree.parentNode.style.backgroundImage = "url(\"" + TreeControlFactory.collapseImagePath + "\")";
            subtree.treeState = "expanded";
          }
          else if (subtree.treeState == "expanded")
          {
            subtree.style.display = "none";
            subtree.parentNode.style.backgroundImage = "url(\"" + TreeControlFactory.expandImagePath + "\")";
            subtree.treeState = "collapsed";
          }
          EventUtils.cancelBubbling(e);
        }
        
        subtrees[j].onclick = function (e)
        {
          EventUtils.cancelBubbling(e);
        }
      }
    }
  }
}

function expandSubtree(tree, subtree)
{
  // crawl to the root of the tree, expanding each ancestor along the way
  var ancestorTree = subtree;
  while (ancestorTree != tree)
  {
    if (ancestorTree.tagName.toLowerCase() == "ul")
    {
      ancestorTree.style.display = "block";
      ancestorTree.parentNode.style.backgroundImage = "url(\"" + TreeControlFactory.collapseImagePath + "\")";
      ancestorTree.treeState = "expanded";
    }
    ancestorTree = ancestorTree.parentNode;
  }
}

function EventUtils()
{
  throw new Error("EventUtils is a static class and, as such, can neither be instantiated nor called directly.");
}

EventUtils.cancelBubbling = function (e)
{
  if (typeof(e) !="undefined")
  {
    e.stopPropagation();
  }
  else
  {
    event.cancelBubble = true;
  }
}

function containsClassName(el, className)
{
  var classNames = el.className.split(" ");
  for (var i = 0; i < classNames.length; i++)
  {
    if (classNames[i] == className) return true;
  }
  return false;
}

function addClassName(el, className)
{
  if (("" + el.className).length == 0)
  {
    el.className = className;
  }
  else
  {
    el.className += " " + className;
  }
}
