code: /*
   * Copyright (c) 2019 the Eclipse Milo Authors
   *
   * This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License 2.0
   * which is available at https://www.eclipse.org/legal/epl-2.0/
   *
   * SPDX-License-Identifier: EPL-2.0
   */
  
  package org.eclipse.milo.opcua.stack.core.util;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.function.BiConsumer;
  import java.util.function.Consumer;
  import java.util.function.Function;
  
  import org.jetbrains.annotations.Nullable;
  
  public class Tree<A> {
  
      private final List<Tree<A>> children = new ArrayList<>();
  
      private final Tree<A> parent;
      private final A value;
  
      public Tree(@Nullable Tree<A> parent, A value) {
          this.parent = parent;
          this.value = value;
      }
  
      public Tree<A> addChild(A value) {
          return addChild(new Tree<>(this, value));
      }
  
      public Tree<A> addChild(Tree<A> child) {
          children.add(child);
          return child;
      }
  
      @Nullable
      public Tree<A> getParent() {
          return parent;
      }
  
      public List<Tree<A>> getChildren() {
          return children;
      }
  
      public A getValue() {
          return value;
      }
  
      /**
       * Traverse this tree consuming the {@code value} at each node.
       *
       * @param c the value {@link Consumer}.
       */
      public void traverse(Consumer<A> c) {
          traverse(this, (a, integer) -> c.accept(a), 0);
      }
  
      /**
       * Traverse this tree consuming each {@link Tree} node.
       *
       * @param c the node {@link Consumer}.
       */
      public void traverseNodes(Consumer<Tree<A>> c) {
          traverseNodes(this, (t, integer) -> c.accept(t), 0);
      }
  
      /**
       * Traverse this tree consuming the {@code value} and current depth at each node.
       *
       * @param c the value and depth {@link BiConsumer}.
       */
      public void traverseWithDepth(BiConsumer<A, Integer> c) {
          traverse(this, c, 0);
      }
  
      /**
       * Traverse this tree consuming pairs of ({@code value}, {@code parent.value}).
       * <p>
       * {@code parent.value} may be null if this node is the root.
       *
       * @param c the {@link BiConsumer}.
       */
      public void traverseWithParent(BiConsumer<A, A> c) {
          traverse(this, c);
      }
  
      /**
       * Map this tree into a new tree using the transformation {@code f}.
       *
       * @param f   a function that transforms from {@code A} to {@code B}.
       * @param <B> the new type.
       * @return a new tree in which the values have been mapped from {@code A} to {@code B} using {@code f}.
       */
      public <B> Tree<B> map(Function<A, B> f) {
          return map(this, f);
      }
  
      private static <A, B> Tree<B> map(Tree<A> tA, Function<A, B> f) {
          Tree<B> tB = new Tree<>(null, f.apply(tA.value));
  
          map(tA, tB, f);
  
          return tB;
      }
  
      private static <A, B> void map(Tree<A> tA, Tree<B> tB, Function<A, B> f) {
          tA.children.forEach(cA -> {
              Tree<B> cB = tB.addChild(f.apply(cA.value));
              map(cA, cB, f);
          });
      }
  
      private static <T> void traverse(Tree<T> tree, BiConsumer<T, Integer> c, int depth) {
          T value = tree.value;
          c.accept(value, depth);
          tree.children.forEach(t -> traverse(t, c, depth + 1));
      }
  
      private static <T> void traverseNodes(Tree<T> tree, BiConsumer<Tree<T>, Integer> c, int depth) {
          c.accept(tree, depth);
          tree.children.forEach(t -> traverseNodes(t, c, depth + 1));
      }
  
      private static <T> void traverse(Tree<T> tree, BiConsumer<T, T> c) {
          T parentValue = tree.parent != null ? tree.parent.value : null;
          T value = tree.value;
          c.accept(value, parentValue);
          tree.children.forEach(t -> traverse(t, c));
      }
  
  }
  