@Override
    public boolean hasNext() {
        // set up stage for iterating on root node's children
        if (currentStage.equals(IterationStage.ON_PARENT)) {
            this.next = this.treeNode;
            currentStage = IterationStage.ON_CHILD;
            return true;
        }
        if (currentStage.equals(IterationStage.ON_CHILD)) {
            if (currentChildNodeIterator.hasNext()) {
                // set up the next child for iteration on the sub-nodes
                INode<T> nextChild = currentChildNodeIterator.next();
                childSubNodeIterator = nextChild.iterator();
                currentStage = IterationStage.ON_CHILD_SUB;
                return hasNext();
            } else {
                currentStage = null;
                return false;
            }
        }
        if (currentStage.equals(IterationStage.ON_CHILD_SUB)) {
            if (childSubNodeIterator.hasNext()) {
                // set up next sub node for iteration
                next = childSubNodeIterator.next();
                return true;
            } else {
                // we don't have anything else to iterate in the sub-nodes, so move on to the next child of the parent
                this.next = null;
                this.currentStage = IterationStage.ON_CHILD;
                return hasNext();
            }
        }
        return false;
    }