(function(jQuery) {
  var FtTree = function(element) {
    element = $jq(element);
    var obj = this;

    this.level = 0;
    this.selectedIndex = -1;

    this.expandAll = function() {
      var time1 = new Date().getTime();
      element.find('li').css('display', 'block');
      element.find('span').each(function() {
        $jq(this).ftNode().data('ftNode').expand();
      });
      $jq('body').removeClass('wait');
      logTime(time1, new Date().getTime());
      return element;
    };
    
    this.collapseAll = function() {
      element.find('li').css('display', 'block');
      element.find('span').each(function() {
        $jq(this).ftNode().data('ftNode').collapse();
      });
      $jq('body').removeClass('wait');
      return this;
    };

    this.removeAll = function() {
      element.find('span.aof_listing').css('display', 'none');
      return element;
    };

    this.remove = function(aof_id) {
      $jq('#aof'+aof_id).css('display', 'none');
    }

    this.restoreAll = function() {
      element.find('span').each(function() {
        $jq('#dummyaofs').data('ftTree').restore($jq(this).ftNode().data('ftNode').aof_id);
      });
      this.collapseAll();
      return this;
    };

    this.restore = function(aof_id) {
      var parent = $jq('#aof'+aof_id).ftNode().data('ftNode').getParent();
      if (parent != null && parent.css('display') == 'none') this.restore(parent.ftNode().data('ftNode').aof_id);
      $jq('#aof'+aof_id).css('display', 'block');
      this.selectBranch(aof_id);
    };

    this.selectBranch = function(aof_id) {
      if (this.selectedIndex != -1) {
        $jq('#aof'+this.selectedIndex).css('fontWeight', 'normal');
      }
      this.selectedIndex = aof_id;
      $jq('#aof'+this.selectedIndex).css('fontWeight', 'bold');
      ftLog(this.selectedIndex);
    };

    this.search = function(search_term) {
      search_term = search_term.toLowerCase();
      this.expandAll();
      element.find('span').each(function() {
        var txt = $jq(this).text();
        if (txt != undefined && txt.strip().toLowerCase() == search_term) {
          $jq(this).ftNode().data('ftNode').show();
          ftLog("Showing "+txt);
        } else {
          $jq(this).css('display', 'none');
        }
      });
    };
  };
  
  var FtNode = function(element) {
    element = $jq(element);
    var obj = this;

    this.status = 'closed';
    this.name = element.textContent;
    this.aof_id = element.attr('id').split('aof')[1];

    this.toggle = function() {
      if (this.status == 'closed') {
        this.expand();
      } else {
        this.collapse();
      }
    };

    this.expand = function() {
      var parent = this.getParent();
      if (parent != null && parent.ftNode().data('ftNode').status == 'closed') parent.ftNode().data('ftNode').expand();
      if (element.siblings().size() == 0) return
      var image = this.getImage();
      element.siblings('ul').css('display', 'block');
      image.src = $jq.path+"images/arrow-down.gif";
      this.status = 'open';
    };

    this.collapse = function() {
      if (element.siblings().size() == 0) return
      var image = this.getImage();
      element.siblings('ul').css('display', 'none');
      image.src = $jq.path+"images/arrow-right.gif";
      this.status = 'closed';
    };

    this.getImage = function()
    {
      return $jq('#img'+element.attr('id'));
    };

    this.getParent = function() {
      var parent = element.parent().parent().siblings();
      if (parent.size() == 0 || $jq(parent[0]).attr('id') == "") {
        return null;
      } else {
        return $jq('#'+$jq(parent[0]).attr('id'));
      }
    };

    this.show = function() {
      $jq('#aof'+this.aof_id).css('display', 'block');
      $jq('#aof'+this.aof_id).parent().parent('ul').css('display', 'block');
      var parent = this.getParent();
      if (parent != null) {
        var parentlist = parent.parent().parent('ul')
        if (parentlist != null) $jq(parentlist).css('display', 'block');
        parent.ftNode().data('ftNode').show();
      }
    };

  
    this.getParentLevel = function() {
      var parent = this.getParent();
      if (parent == null) {
        return 0;
      } else {
        return parent.level;
      }
    };
    this.level = this.getParentLevel() + 1;

  };

  $jq.fn.extend({
    ftTree: function() {
      return this.each(function() {
        if ($jq(this).data('ftTree')) return;
        var ftTree = new FtTree(this);
        $jq(this).data('ftTree', ftTree);
      });
    },
    ftNode: function() {
      return this.each(function() {
        if ($jq(this).data('ftNode')) return;
        // not sure why we need to do this, but it seems to be trying to call ftNode on 'document'
        if ($jq(this).attr('id') == undefined) return;
        var ftNode = new FtNode(this);
        $jq(this).data('ftNode', ftNode);
      });
    }
  });

})(jQuery);

function ftLog(msg) {
  if (typeof(window["console"]) != "undefined") {
    console.log(msg);
  }
}

function logTime(time1, time2) {
  var diff = time2 - time1;
  ftLog('Execution: '+(diff/1000)+' sec');
}
