package com.insightfullogic.honest_profiler.core.aggregation.result.diff;
import static java.util.stream.Collectors.toList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import com.insightfullogic.honest_profiler.core.aggregation.result.Aggregation;
import com.insightfullogic.honest_profiler.core.aggregation.result.straight.Node;
/**
* Subclass of {@link DiffEntry} which allows to arrange the items into a tree.
*/
public class DiffNode extends DiffEntry
{
// Instance Properties
private final Map<String, DiffNode> children;
// Instance Constructors
/**
* Constructor whach takes the two {@link Node}s to be compared as arguments.
* <p>
* @param baseNode the {@link Node} from the Base {@link Aggregation}
* @param newNode the {@link Node} from the New {@link Aggregation}
*/
public DiffNode(Node baseNode, Node newNode)
{
super(baseNode, newNode);
this.children = new HashMap<>();
addBaseChildren(baseNode);
addNewChildren(newNode);
}
/**
* Specialized internal constructor for {@link #copyWithFilter(Predicate)}.
* <p>
* @param node the {@link DiffNode} being copied
* @param children the new, filtered children
*/
private DiffNode(DiffNode node, List<DiffNode> children)
{
super(node.getBaseEntry(), node.getNewEntry());
this.children = new HashMap<>();
children.forEach(child -> this.children.put(child.getKey(), child));
}
// Instance Accessors
/**
* Sets the Base {@link Node}.
* <p>
* The return value is provided as a convenience for
* {@link TreeDiff#set(com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree, com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree)}.
* <p>
* @param node the Base {@link Node}
* @return this {@link DiffNode}
*/
public DiffNode setBase(Node node)
{
super.setBase(node);
addBaseChildren(node);
return this;
}
/**
* Sets the New {@link Node}.
* <p>
* The return value is provided as a convenience for
* {@link TreeDiff#set(com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree, com.insightfullogic.honest_profiler.core.aggregation.result.straight.Tree)}.
* <p>
* @param node the New {@link Node}
* @return this {@link DiffNode}
*/
public DiffNode setNew(Node node)
{
super.setNew(node);
addNewChildren(node);
return this;
}
/**
* Returns the children of this node.
* <p>
* @return a {@link Collection} containing the children of this node.
*/
public Collection<DiffNode> getChildren()
{
return children.values();
}
/**
* Filter the descendants of this DiffNode recursively, creating copies of the "survivors". If this node has
* survivor descendants or is accepted by the filter, the copy is returned, otherwise the method returns null.
* <p>
* @param filter the filter to be applied to this node and its descendants.
* @return a new {@link DiffNode} containing the filtered information, or null
*/
public DiffNode copyWithFilter(Predicate<DiffNode> filter)
{
List<DiffNode> newChildren = children.values().stream()
.map(child -> child.copyWithFilter(filter)).filter(child -> child != null)
.collect(toList());
return newChildren.size() > 0 || filter.test(this) ? new DiffNode(this, newChildren) : null;
}
// Helper Methods
/**
* Create child DiffNodes or set the Base {@link Node} for existing ones, based on the children from the provided
* {@link Node}.
* <p>
* @param node the Base {@link Node} whose children need to be incorporated into the children of this node
*/
private void addBaseChildren(Node node)
{
if (node == null)
{
return;
}
node.getChildren().forEach(this::addBaseChild);
}
/**
* Create child DiffNodes or set the New {@link Node} for existing ones, based on the children from the provided
* {@link Node}.
* <p>
* @param node the Base {@link Node} whose children need to be incorporated into the children of this node
*/
private void addNewChildren(Node node)
{
if (node == null)
{
return;
}
node.getChildren().forEach(this::addNewChild);
}
/**
* Sets the Base {@link Node} of the correct child DiffNode to the provided {@link Node}, or create a new child
* DiffNode if it doesn't exist yet, and set the Base {@link Node} in it to the provided {@link Node}.
* <p>
* @param child the {@link Node} to be added as Base {@link Node} of a child DiffNode
*/
private void addBaseChild(Node child)
{
children.compute(
child.getKey(),
(k, v) -> v == null ? new DiffNode(child, null) : v.setBase(child));
}
/**
* Sets the New {@link Node} of the correct child DiffNode to the provided {@link Node}, or create a new child
* DiffNode if it doesn't exist yet, and set the New {@link Node} in it to the provided {@link Node}.
* <p>
* @param child the {@link Node} to be added as New {@link Node} of a child DiffNode
*/
private void addNewChild(Node child)
{
children.compute(
child.getKey(),
(k, v) -> v == null ? new DiffNode(null, child) : v.setNew(child));
}
}