package org.terracotta.context;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
abstract class AbstractTreeNode implements TreeNode {
private final CopyOnWriteArraySet<AbstractTreeNode> children = new CopyOnWriteArraySet<>();
public boolean addChild(AbstractTreeNode child) {
synchronized (this) {
Collection<AbstractTreeNode> ancestors = new HashSet<>(getAncestors());
ancestors.removeAll(child.getAncestors());
if (children.add(child)) {
child.addedParent(this);
for (AbstractTreeNode ancestor : ancestors) {
for (ContextListener listener : ancestor.getListeners()) {
listener.graphAdded(this, child);
}
}
return true;
} else {
return false;
}
}
}
public boolean removeChild(AbstractTreeNode child) {
synchronized (this) {
if (children.remove(child)) {
child.removedParent(this);
Collection<AbstractTreeNode> ancestors = new HashSet<>(getAncestors());
ancestors.removeAll(child.getAncestors());
for (AbstractTreeNode ancestor : ancestors) {
for (ContextListener listener : ancestor.getListeners()) {
listener.graphRemoved(this, child);
}
}
return true;
} else {
return false;
}
}
}
@Override
public Set<? extends AbstractTreeNode> getChildren() {
return Collections.unmodifiableSet(children);
}
@Override
public List<? extends TreeNode> getPath() {
Collection<List<? extends TreeNode>> paths = getPaths();
if (paths.size() == 1) {
return paths.iterator().next();
} else {
throw new IllegalStateException("No unique path to root");
}
}
@Override
public String toTreeString() {
return dumpSubtree(0, this);
}
public static String dumpSubtree(int indent, TreeNode node) {
char[] indentChars = new char[indent];
Arrays.fill(indentChars, ' ');
StringBuilder sb = new StringBuilder();
String nodeString = node.toString();
sb.append(indentChars).append(nodeString).append("\n");
for (TreeNode child : node.getChildren()) {
sb.append(dumpSubtree(indent + 2, child));
}
return sb.toString();
}
abstract void addedParent(AbstractTreeNode child);
abstract void removedParent(AbstractTreeNode child);
abstract Set<AbstractTreeNode> getAncestors();
abstract Collection<ContextListener> getListeners();
@Override
public void clean() {
for (AbstractTreeNode child : getChildren()) {
removeChild(child);
}
for (AbstractTreeNode parent : getAncestors()) {
parent.removeChild(this);
}
}
}