/*
 * ====================================================================
 * This software is subject to the terms of the Common Public License
 * Agreement, available at the following URL:
 *   http://www.opensource.org/licenses/cpl.html .
 * You must accept the terms of that agreement to use this software.
 * ====================================================================
 */
package com.eyeq.pivot4j.util;

import java.util.ArrayList;
import java.util.List;

/**
 * Tree Node for the for a general tree of Objects
 */
public class TreeNode<T> {

	private TreeNode<T> parent = null;

	private List<TreeNode<T>> children = null;

	private T reference;

	/**
	 * cTtor
	 * 
	 * @param obj
	 *            referenced object
	 */
	public TreeNode(T obj) {
		this.parent = null;
		this.reference = obj;
		this.children = new ArrayList<TreeNode<T>>();
	}

	/**
	 * remove node from tree
	 */
	public void remove() {
		if (parent != null) {
			parent.removeChild(this);
		}
	}

	/**
	 * remove child node
	 * 
	 * @param child
	 */
	public void removeChild(TreeNode<T> child) {
		if (children.contains(child)) {
			children.remove(child);
		}
	}

	/**
	 * add child node
	 * 
	 * @param child
	 *            node to be added
	 */
	public void addChild(TreeNode<T> child) {
		child.parent = this;
		if (!children.contains(child)) {
			children.add(child);
		}
	}

	/**
	 * deep copy (clone)
	 * 
	 * @return copy of TreeNode
	 */
	public TreeNode<T> deepCopy() {
		TreeNode<T> newNode = new TreeNode<T>(reference);
		for (TreeNode<T> child : children) {
			newNode.addChild(child.deepCopy());
		}
		return newNode;
	}

	/**
	 * deep copy (clone) and prune
	 * 
	 * @param depth
	 *            - number of child levels to be copied
	 * @return copy of TreeNode
	 */
	public TreeNode<T> deepCopyPrune(int depth) {
		if (depth < 0) {
			throw new IllegalArgumentException("Depth is negative");
		}

		TreeNode<T> newNode = new TreeNode<T>(reference);
		if (depth == 0) {
			return newNode;
		}

		for (TreeNode<T> child : children) {
			newNode.addChild(child.deepCopyPrune(depth - 1));
		}
		return newNode;
	}

	/**
	 * @return level = distance from root
	 */
	public int getLevel() {
		int level = 0;
		TreeNode<T> p = parent;
		while (p != null) {
			++level;
			p = p.parent;
		}
		return level;
	}

	/**
	 * walk through subtree of this node
	 * 
	 * @param callbackHandler
	 *            function called on iteration
	 */
	public int walkTree(TreeNodeCallback<T> callbackHandler) {
		int code = 0;
		code = callbackHandler.handleTreeNode(this);
		if (code != TreeNodeCallback.CONTINUE) {
			return code;
		}

		for (TreeNode<T> child : children) {
			code = child.walkTree(callbackHandler);
			if (code >= TreeNodeCallback.CONTINUE_PARENT) {
				return code;
			}
		}
		return code;
	}

	/**
	 * walk through children subtrees of this node
	 * 
	 * @param callbackHandler
	 *            function called on iteration
	 */
	public int walkChildren(TreeNodeCallback <T>callbackHandler) {
		int code = 0;
		for (TreeNode<T> child : children) {
			code = callbackHandler.handleTreeNode(child);
			if (code >= TreeNodeCallback.CONTINUE_PARENT) {
				return code;
			}
			if (code == TreeNodeCallback.CONTINUE) {
				code = child.walkChildren(callbackHandler);
				if (code > TreeNodeCallback.CONTINUE_PARENT) {
					return code;
				}
			}
		}
		return code;
	}

	/**
	 * @return List of children
	 */
	public List<TreeNode<T>> getChildren() {
		return children;
	}

	/**
	 * @return parent node
	 */
	public TreeNode<T> getParent() {
		return parent;
	}

	/**
	 * @return reference object
	 */
	public T getReference() {
		return reference;
	}

	/**
	 * set reference object
	 * 
	 * @param object
	 *            reference
	 */
	public void setReference(T object) {
		reference = object;
	}
}

@@ -2965,12 +2965,12 @@
 back
- 
 %3CT%3E
+ 
 call
@@ -3545,24 +3545,145 @@
 parent;%0A%09%7D%0A%0A
+%09public TreeNode%3CT%3E getRoot() %7B%0A%09%09if (parent == null) %7B%0A%09%09%09return this;%0A%09%09%7D else %7B%0A%09%09%09return parent.getParent();%0A%09%09%7D%0A%09%7D%0A%0A
 %09/**%0A%09 * @re

Add getRoot() method for convinience