/**
* © 2016 Telenav, Inc. All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License").
*
* You may not use this file except in compliance with the License. You may obtain a copy of the
* License at http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable law or
* agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for
* the specific language governing permissions and limitations under the License.
*/
package com.telenav.nodeflow;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Data structure for storing user data.
* @param <T> data type
*/
public class Node<T> {
private T data;
private int depth;
private int index;
private Node<T> parent;
private List<Node<T>> children = new ArrayList<Node<T>>();
public Node(T data) {
this.data = data;
depth = 0;
}
private Node(T data, int depth, Node<T> parent, int index) {
this.data = data;
this.depth = depth;
this.parent = parent;
this.index = index;
}
/**
* Returns a new node object with the associated data.
* @param data associated data
*/
public static <E> Node<E> get(E data) {
return new Node<>(data);
}
/**
* Retrieve data associated with current node.
*/
public T getData() {
return data;
}
/**
* Retrieve the index of this node in parent's child list.
*/
public int getIndex() {
return index;
}
/**
* Retrieve the parent of the current node.
*/
public Node<T> getParent() {
return parent;
}
/**
* Returns true if this node has children.
*/
public boolean hasChildren() {
return !children.isEmpty();
}
/**
* Returns the number of children for this node.
*/
public int getChildCount() {
return children.size();
}
/**
* Retrieves child node at specified index. If index is out of range - will return null.
*/
public Node<T> getChildAt(int index) {
return index >= 0 && index < children.size() ? children.get(index) : null;
}
/**
* Adds a child node for the specified data.
* @param data node data
* @return instance of current node
*/
public Node<T> addChild(T data) {
children.add(new Node<T>(data, depth + 1, this, children.size()));
return this;
}
/**
* Adds a list of child nodes for the specified data collection.
* @param data collection of node data
* @return instance of current node
*/
public Node<T> addChildren(Collection<? extends T> data) {
for (T aux : data)
children.add(new Node<T>(aux, depth + 1, this, children.size()));
return this;
}
/**
* Adds a collection of nodes to the child list.
* @param nodes collection of nodes
* @return instance of current node
*/
public Node<T> addChildNodes(Collection<? extends Node<T>> nodes) {
for (Node<T> aux : nodes) {
aux.increaseDepth();
aux.parent = this;
aux.index = children.size();
children.add(aux);
}
return this;
}
/**
* Searches for a node with the specified data. If no such node exists - returns null.
* @param item data to search for
* @return node that contains the data or null
*/
public Node<T> search(T item) {
if (data.equals(item)) {
return this;
} else {
for (Node<T> n : children) {
Node<T> res = n.search(item);
if (res != null)
return res;
}
return null;
}
}
/**
* Returns the size of the longest path for the current node.
*/
public int getLongestPathSize() {
if (children.isEmpty()) {
return 0;
} else {
int count = children.size();
int max = 0, aux;
for (Node<T> n : children) {
aux = n.getLongestPathSize();
if (aux > max)
max = aux;
}
return count + max;
}
}
/**
* Returns the position relative to the root.
*/
public int getDepth() {
return depth;
}
private void setDepth(int depth) {
this.depth = depth;
}
private void increaseDepth() {
setDepth(depth + 1);
for (Node node : children)
node.increaseDepth();
}
}