import java.util.LinkedList;
import java.util.Iterator;

/** Trees with unlimited number of child Trees, holding data in its root
  * (and indirectly in the rest of its nodes via its children).
  * @param <D>  the type of data in the nodes */
public class Tree<D> {
  
  private D rootData;
  
  private LinkedList<Tree<D>> children = new LinkedList<Tree<D>>();
  
  /** Set the root data to d.
    * @param d  the new root data */
  public void setRootData(D d) {
    rootData = d;
  }
  
  /** Return the root data.
    * @return  the data in the root of this Tree, null if never set */
  public D getRootData() {
    return rootData;
  }
  
  /** Add c as the last child Tree of this Tree.
    * Precondition: c != null, c is not this Tree and c is not part of a Tree.
    * @param c  the child Tree to be added
    * @throws  IllegalArgumentException  if c is null or c is this Tree */
  public void addChildTree(Tree<D> c) {
    if (c == null || c == this) {
      throw new IllegalArgumentException();
    }
    children.addLast(c);
  }
  
  /** Return an Iterator over the child Trees.
    * The Iterator supports removal.
    * @return  an Iterator over the child subtrees. */
  public Iterator<Tree<D>> childTreeIterator() {
    return children.iterator();
  }
  
  /** Return the data in this tree and all its subtrees.
    * There is one piece of data per line, in preorder, indented 2 x depth,
    * with "null" for null data, and every line of data (including the last one)
    * is delimited by System.getProperty("line.separator").
    * @return the data on separate lines in preorder, indented 2 x depth. */
  public String toString() {
    return toString("");
  }
  
  /* Helper for toString(), where indent is an extra string of spaces to add
   * to the beginning of every line. */
  private String toString(String indent) {
    String result = indent + rootData + System.getProperty("line.separator");
    Iterator<Tree<D>> children = childTreeIterator();
    while (children.hasNext()) {
      result += children.next().toString(indent + "  ");
    }
    return result;
  }
  
}

