package org.codefx.libfx.collection.tree.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.OptionalInt;
import org.codefx.libfx.collection.tree.navigate.TreeNavigator;
import org.codefx.libfx.collection.tree.stream.TreeIterationStrategy;
/**
* Supports testing by providing sample trees and a {@link Navigator} for them.
*/
class TreeTestHelper {
/**
* The singleton instance of a stateless navigator which can be used to iterate over the test trees.
*/
public static final Navigator NAVIGATOR = new Navigator();
// #begin TREES
/**
* @return a tree with the single node [singleton].
*/
public static Node createSingletonTree() {
Node tree = Node.singleton("singleton");
return tree;
}
/**
* @return a small binary tree [root] -> { [leftLeaf], [rightLeaf] }.
*/
public static Node createSimpleBinaryTree() {
Node tree = Node.root("root",
Node.leaf("leftLeaf"),
Node.leaf("rightLeaf")
);
return tree;
}
/**
* @return a perfect binary tree with depth 4 (see <a
* href="https://en.wikipedia.org/wiki/Binary_tree#Types_of_binary_trees">types of trees</a>); a septh-first
* search yields [1], [2], ..., [15]
*/
public static Node createDeepBinaryTree() {
Node tree = Node.root("1",
Node.node("2",
Node.node("3",
Node.leaf("4"),
Node.leaf("5")
),
Node.node("6",
Node.leaf("7"),
Node.leaf("8")
)
),
Node.node("9",
Node.node("10",
Node.leaf("11"),
Node.leaf("12")
),
Node.node("13",
Node.leaf("14"),
Node.leaf("15")
)
)
);
return tree;
}
// #end TREES
// #begin UTIL
/**
* @param strategy
* the strategy to iterate the nodes
* @return an array which contains each node the strategy returns
*/
public static String[] iterateTreeContent(TreeIterationStrategy<Node> strategy) {
List<String> treeContent = new ArrayList<>();
Optional<Node> nextNode = strategy.goToNextNode();
while (nextNode.isPresent()) {
treeContent.add(nextNode.get().content);
nextNode = strategy.goToNextNode();
}
return treeContent.toArray(new String[0]);
}
// #end UTIL
// #begin INNER CLASSES
/**
* A {@link TreeNavigator} for the {@link Node}-based trees available in this class.
*/
public static class Navigator implements TreeNavigator<Node> {
@Override
public Optional<Node> getParent(Node child) {
return child.parent;
}
@Override
public OptionalInt getChildIndex(Node node) {
Optional<Node> parent = node.parent;
if (parent.isPresent())
return OptionalInt.of(parent.get().children.indexOf(node));
else
return OptionalInt.empty();
}
@Override
public int getChildrenCount(Node parent) {
return parent.children.size();
}
@Override
public Optional<Node> getChild(Node parent, int childIndex) {
return (0 <= childIndex && childIndex < parent.children.size())
? Optional.of(parent.children.get(childIndex))
: Optional.empty();
}
}
/**
* A node in the trees returned by this class.
*/
public static class Node {
/**
* The nodes actual content.
*/
public final String content;
/**
* The node's children.
*/
public final List<Node> children;
/**
* The node's parent.
*/
public Optional<Node> parent;
private Node(String content, Node[] children) {
this.content = content;
this.parent = Optional.empty();
this.children = new ArrayList<>(Arrays.asList(children));
Arrays.stream(children).forEach(node -> node.parent = Optional.of(this));
}
/**
* @param content
* the node's content
* @return a singleton tree
*/
public static Node singleton(String content) {
return new Node(content, new Node[0]);
}
/**
* @param content
* the root node's content
* @param children
* the child nodes
* @return a tree with the specified child nodes
*/
public static Node root(String content, Node... children) {
return new Node(content, children);
}
/**
* @param content
* the node's content
* @param children
* the child nodes
* @return a node with the specified child nodes
*/
public static Node node(String content, Node... children) {
return new Node(content, children);
}
/**
* @param content
* the leaf's content
* @return a leaf node
*/
public static Node leaf(String content) {
return new Node(content, new Node[0]);
}
@Override
public String toString() {
return "Node [" + content + "]";
}
}
// #end INNER CLASSES
}