All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pivot4j.util.TreeNode Maven / Gradle / Ivy

The newest version!
/*
 * ====================================================================
 * 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 org.pivot4j.util;

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

import org.apache.commons.lang.ObjectUtils;
import org.olap4j.metadata.MetadataElement;

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

	private TreeNode parent;

	private List> children = new ArrayList>();

	private T reference;

	public TreeNode() {
	}

	/**
	 * @param obj
	 *            referenced object
	 */
	public TreeNode(T obj) {
		this.reference = obj;
	}

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

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

	public void clear() {
		children.clear();
	}

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

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

	/**
	 * deep copy (clone)
	 * 
	 * @return copy of TreeNode
	 */
	public TreeNode deepCopy() {
		TreeNode newNode = new TreeNode(reference);
		for (TreeNode 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 deepCopyPrune(int depth) {
		if (depth < 0) {
			throw new IllegalArgumentException("Depth is negative");
		}

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

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

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

	public int getMaxDescendantLevel() {
		int level;

		if (getChildCount() == 0) {
			level = getLevel();
		} else {
			level = 0;
			for (TreeNode child : getChildren()) {
				level = Math.max(level, child.getMaxDescendantLevel());
			}
		}

		return level;
	}

	public int getWidth() {
		int width = 0;

		if (getChildCount() > 0) {
			for (TreeNode child : getChildren()) {
				width += child.getWidth();
			}
		}

		return Math.max(1, width);
	}

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

		for (TreeNode 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 callbackHandler) {
		int code = 0;
		for (TreeNode 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> getChildren() {
		return Collections.unmodifiableList(children);
	}

	public int getChildCount() {
		if (children == null) {
			return 0;
		}
		return children.size();
	}

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

	public TreeNode getRoot() {
		if (parent == null) {
			return this;
		} else {
			return parent.getRoot();
		}
	}

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

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

	/**
	 * @param reference
	 * @return
	 */
	public TreeNode findNode(T reference) {
		TreeNode node = null;

		if (isEquals(getReference(), reference)) {
			node = this;
		} else {
			for (TreeNode child : getChildren()) {
				node = child.findNode(reference);

				if (node != null) {
					break;
				}
			}
		}

		return node;
	}

	/**
	 * @param reference
	 * @param otherReference
	 * @return
	 */
	private boolean isEquals(T reference, T otherReference) {
		if (reference instanceof MetadataElement
				&& otherReference instanceof MetadataElement) {
			return OlapUtils.equals((MetadataElement) reference,
					(MetadataElement) otherReference);
		} else {
			return ObjectUtils.equals(reference, otherReference);
		}
	}

	/**
	 * @param reference
	 * @return
	 */
	public TreeNode findChild(T reference) {
		TreeNode node = null;

		for (TreeNode child : getChildren()) {
			node = child.findNode(reference);

			if (node != null) {
				break;
			}
		}

		return node;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy