package com.google.common.graph;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.graph.GraphConstants.SELF_LOOPS_NOT_ALLOWED;
import static com.google.common.graph.Graphs.checkNonNegative;
import static com.google.common.graph.Graphs.checkPositive;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
final class ConfigurableMutableValueGraph<N, V> extends ConfigurableValueGraph<N, V>
implements MutableValueGraph<N, V> {
ConfigurableMutableValueGraph(AbstractGraphBuilder<? super N> builder) {
super(builder);
}
@Override
@CanIgnoreReturnValue
public boolean addNode(N node) {
checkNotNull(node, "node");
if (containsNode(node)) {
return false;
}
addNodeInternal(node);
return true;
}
@CanIgnoreReturnValue
private GraphConnections<N, V> addNodeInternal(N node) {
GraphConnections<N, V> connections = newConnections();
checkState(nodeConnections.put(node, connections) == null);
return connections;
}
@Override
@CanIgnoreReturnValue
public V putEdgeValue(N nodeU, N nodeV, V value) {
checkNotNull(nodeU, "nodeU");
checkNotNull(nodeV, "nodeV");
checkNotNull(value, "value");
if (!allowsSelfLoops()) {
checkArgument(!nodeU.equals(nodeV), SELF_LOOPS_NOT_ALLOWED, nodeU);
}
GraphConnections<N, V> connectionsU = nodeConnections.get(nodeU);
if (connectionsU == null) {
connectionsU = addNodeInternal(nodeU);
}
V previousValue = connectionsU.addSuccessor(nodeV, value);
GraphConnections<N, V> connectionsV = nodeConnections.get(nodeV);
if (connectionsV == null) {
connectionsV = addNodeInternal(nodeV);
}
connectionsV.addPredecessor(nodeU, value);
if (previousValue == null) {
checkPositive(++edgeCount);
}
return previousValue;
}
@Override
@CanIgnoreReturnValue
public boolean removeNode(N node) {
checkNotNull(node, "node");
GraphConnections<N, V> connections = nodeConnections.get(node);
if (connections == null) {
return false;
}
if (allowsSelfLoops()) {
if (connections.removeSuccessor(node) != null) {
connections.removePredecessor(node);
--edgeCount;
}
}
for (N successor : connections.successors()) {
nodeConnections.getWithoutCaching(successor).removePredecessor(node);
--edgeCount;
}
if (isDirected()) {
for (N predecessor : connections.predecessors()) {
checkState(nodeConnections.getWithoutCaching(predecessor).removeSuccessor(node) != null);
--edgeCount;
}
}
nodeConnections.remove(node);
checkNonNegative(edgeCount);
return true;
}
@Override
@CanIgnoreReturnValue
public V removeEdge(N nodeU, N nodeV) {
checkNotNull(nodeU, "nodeU");
checkNotNull(nodeV, "nodeV");
GraphConnections<N, V> connectionsU = nodeConnections.get(nodeU);
GraphConnections<N, V> connectionsV = nodeConnections.get(nodeV);
if (connectionsU == null || connectionsV == null) {
return null;
}
V previousValue = connectionsU.removeSuccessor(nodeV);
if (previousValue != null) {
connectionsV.removePredecessor(nodeU);
checkNonNegative(--edgeCount);
}
return previousValue;
}
private GraphConnections<N, V> newConnections() {
return isDirected()
? DirectedGraphConnections.<N, V>of()
: UndirectedGraphConnections.<N, V>of();
}
}