public List<GenericTreeNode<T>> traceParents() {
    // logger.debug("traceParents");
    List<GenericTreeNode<T>> parents = new ArrayList<>();
    boolean reachedRoot = false;

    int maxIterations = 100;
    int i = 0;
    GenericTreeNode<T> currentNode = this;

    while (!reachedRoot) {
      i++;
      // logger.debug("Iteration: " + i);
      if (i > maxIterations) {
        logger.warn("Too deep recursion, breaking");
        break;
      }
      GenericTreeNode<T> p = currentNode.getParent();
      if (p != null) {
        // logger.debug("Adding parent: " + p.getData().toString());
        parents.add(p);
        currentNode = p;
      } else {
        // logger.debug("this node is a root node: " + currentNode.getData().toString());
        reachedRoot = true;
      }
    }

    return parents;
  }
  private int auxiliaryGetNumberOfNodes(GenericTreeNode<T> node) {
    int numberOfNodes = node.getNumberOfChildren();

    for (GenericTreeNode<T> child : node.getChildren()) {
      numberOfNodes += auxiliaryGetNumberOfNodes(child);
    }

    return numberOfNodes;
  }
  private GenericTreeNode<T> auxiliaryFind(GenericTreeNode<T> currentNode, T dataToFind) {
    GenericTreeNode<T> returnNode = null;
    int i = 0;

    if (currentNode.getData().equals(dataToFind)) {
      returnNode = currentNode;
    } else if (currentNode.hasChildren()) {
      i = 0;
      while (returnNode == null && i < currentNode.getNumberOfChildren()) {
        returnNode = auxiliaryFind(currentNode.getChildAt(i), dataToFind);
        i++;
      }
    }

    return returnNode;
  }
  private void buildPostOrder(GenericTreeNode<T> node, List<GenericTreeNode<T>> traversalResult) {
    for (GenericTreeNode<T> child : node.getChildren()) {
      buildPostOrder(child, traversalResult);
    }

    traversalResult.add(node);
  }
  private void buildPostOrderWithDepth(
      GenericTreeNode<T> node, Map<GenericTreeNode<T>, Integer> traversalResult, int depth) {
    for (GenericTreeNode<T> child : node.getChildren()) {
      buildPostOrderWithDepth(child, traversalResult, depth + 1);
    }

    traversalResult.put(node, depth);
  }
 public void addChildAt(int index, GenericTreeNode<T> child) throws IndexOutOfBoundsException {
   child.parent = this;
   children.add(index, child);
 }
 public void addChild(GenericTreeNode<T> child) {
   child.parent = this;
   children.add(child);
 }
 public void setChildren(List<GenericTreeNode<T>> children) {
   for (GenericTreeNode<T> child : children) {
     child.parent = this;
   }
   this.children = children;
 }