package com.linkedin.thirdeye.client.diffsummary; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.fasterxml.jackson.annotation.JsonIgnore; public class HierarchyNode { int level; int index; double baselineValue; double currentValue; Row data; HierarchyNode parent; List<HierarchyNode> children = new ArrayList<>(); public HierarchyNode() { } public HierarchyNode(int level, int index, Row data, HierarchyNode parent) { this.level = level; this.index = index; this.baselineValue = data.baselineValue; this.currentValue = data.currentValue; this.data = data; this.parent = parent; } public int getLevel() { return level; } public void resetValues() { this.baselineValue = this.data.baselineValue; this.currentValue = this.data.currentValue; } public void removeNodeValues(HierarchyNode node) { this.baselineValue -= node.baselineValue; this.currentValue -= node.currentValue; } public void addNodeValues(HierarchyNode node) { this.baselineValue += node.baselineValue; this.currentValue += node.currentValue; } public double getBaselineValue() { return baselineValue; } public double getCurrentValue() { return currentValue; } @JsonIgnore public double getOriginalBaselineValue() { return data.baselineValue; } @JsonIgnore public double getOriginalCurrentValue() { return data.currentValue; } @JsonIgnore public Dimensions getDimensions() { return data.dimensions; } @JsonIgnore public DimensionValues getDimensionValues() { return data.dimensionValues; } public HierarchyNode getParent() { return parent; } public int childrenSize() { return children.size(); } public List<HierarchyNode> getChildren() { return Collections.unmodifiableList(children); } public double aggregatedRatio() { return data.ratio(); } public double currentRatio() { return currentValue / baselineValue; } /** * Return the ratio of the node. If the ratio is not a finite number, then it returns the aggragatedRatio. * If the aggregatedRaio is not a finite number, then it bootstraps to the parents until it finds a finite * ratio. If no finite ratio available, then it returns 1. */ public double targetRatio() { double ratio = currentRatio(); if (!Double.isInfinite(ratio) && Double.compare(ratio, 0d) != 0) { return ratio; } else { ratio = aggregatedRatio(); if (!Double.isInfinite(ratio) && Double.compare(ratio, 0d) != 0) { return ratio; } else { if (parent != null) { return parent.targetRatio(); } else { return 1.; } } } } /** * Returns the current ratio of this node is increased or decreased, i.e., returns true if ratio of the node >= 1.0. * If the current ratio is NAN, then the ratio of the aggregated values is used. * * Precondition: the aggregated baseline and current values cannot both be zero. */ public boolean side() { double ratio = currentRatio(); if (!Double.isNaN(ratio)) { return Double.compare(1., currentRatio()) <= 0; } else { return Double.compare(1., aggregatedRatio()) <= 0; } } public String toString() { ToStringBuilder tsb = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); tsb.append(data.dimensionValues)//.append(data.baselineValue).append(data.currentValue) .append(baselineValue).append(currentValue).append("ratio", currentRatio()); if (parent != null) { tsb.append("\t parent").append(parent.data.dimensionValues).append(parent.baselineValue).append(parent.currentValue) .append("ratio", parent.currentRatio()); } return tsb.toString(); } }