import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import static java.util.Map.entry; public class ChannelNode implements IChannelNode { private Map incoming; private Map outgoing; public ChannelNode() { incoming = new TreeMap<>(); outgoing = new TreeMap<>(); } @Override public void setConnections(Map conmap, Direction dir) throws IllegalArgumentException { if(conmap == null) throw new IllegalArgumentException("connection map is null"); if(dir == null) throw new IllegalArgumentException("direction is null"); if(conmap.containsKey(this)) throw new IllegalArgumentException("connection map contains this node"); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming = conmap), entry(Direction.OUTGOING, () -> outgoing = conmap) ), dir); } @Override public void setNumConnections(IChannelNode node, Direction dir, int num) throws IllegalArgumentException { if(node == null) throw new IllegalArgumentException("node is null"); if(node == this) throw new IllegalArgumentException("node is self"); if(dir == null) throw new IllegalArgumentException("dir is null"); if(num < 0) throw new IllegalArgumentException("num < 0"); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming.put(node, num)), entry(Direction.OUTGOING, () -> outgoing.put(node, num)) ), dir); } @Override public void addConnection(IChannelNode node, Direction dir) throws IllegalArgumentException { if(node == null) throw new IllegalArgumentException("node is null"); if(node == this) throw new IllegalArgumentException("node is self"); if(dir == null) throw new IllegalArgumentException("dir is null"); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming.put(node, ((incoming.get(node) != null) ? incoming.get(node) : 0) + 1)), entry(Direction.OUTGOING, () -> outgoing.put(node, ((outgoing.get(node) != null) ? outgoing.get(node) : 0) + 1)) ), dir); } @Override public void addConnections(Iterable nodes, Direction dir) throws IllegalArgumentException { if(nodes == null) throw new IllegalArgumentException("node is null"); if(dir == null) throw new IllegalArgumentException("dir is null"); nodes.forEach((node) -> {if(node == this) throw new IllegalArgumentException("one of the included nodes is this node");}); for(IChannelNode node: nodes) { Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming.put(node,((incoming.get(node) != null) ? incoming.get(node) : 0) + 1)), entry(Direction.OUTGOING, () -> outgoing.put(node,((outgoing.get(node) != null) ? outgoing.get(node) : 0) + 1)) ), dir); } } @Override public void removeConnection(IChannelNode node, Direction dir) throws IllegalArgumentException { if(node == null) throw new IllegalArgumentException("node is null"); if(node == this) throw new IllegalArgumentException("node is self"); if(dir == null) throw new IllegalArgumentException("dir is null"); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming.put(node, Math.max(incoming.get(node) - 1, 0))), entry(Direction.OUTGOING, () -> outgoing.put(node, Math.max(outgoing.get(node) - 1, 0))) ), dir); } @Override public void removeConnections(Iterable nodes, Direction dir) throws IllegalArgumentException { if(nodes == null) throw new IllegalArgumentException("node is null"); if(dir == null) throw new IllegalArgumentException("dir is null"); nodes.forEach((node) -> {if(node == this) throw new IllegalArgumentException("one of the included nodes is this node");}); for(IChannelNode node: nodes) { Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> incoming.put(node, Math.max(incoming.get(node) - 1, 0))), entry(Direction.OUTGOING, () -> outgoing.put(node, Math.max(outgoing.get(node) - 1, 0))) ), dir); } } @Override public void clearConnections() throws IllegalArgumentException { // I have no idea why this is throwing an unsupported operation exception incoming.clear(); outgoing.clear(); } @Override public boolean connectionExists(IChannelNode node, Direction dir) throws IllegalArgumentException { if(node == null) throw new IllegalArgumentException("node is null"); if(dir == null) throw new IllegalArgumentException("dir is null"); switch (dir) { case INCOMING -> {return incoming.containsKey(node);} case OUTGOING -> {return outgoing.containsKey(node);} case BOTH -> {return (incoming.containsKey(node) && outgoing.containsKey(node));} default -> throw new IllegalStateException("got unknown direction"); } } @Override public int getNumConnections(Direction dir) throws IllegalArgumentException { if(dir == null) throw new IllegalArgumentException("dir is null"); AtomicInteger total = new AtomicInteger(); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> {for(int i: incoming.values()) total.addAndGet(i);}), entry(Direction.OUTGOING, () -> {for(int i: outgoing.values()) total.addAndGet(i);}) ), dir); return total.get(); } @Override public Map getIncomingConnections() { return incoming; } @Override public Map getOutgoingConnections() { return outgoing; } @Override public List> getConnections(Direction dir) throws IllegalArgumentException { if(dir == null) throw new IllegalArgumentException("dir is null"); ArrayList> res = new ArrayList<>(); Direction.overVals(Map.ofEntries( entry(Direction.INCOMING, () -> res.add(incoming)), entry(Direction.OUTGOING, () -> res.add(outgoing)) ), dir); return res; } @Override public int compareTo(IChannelNode iChannelNode) throws IllegalArgumentException { if(iChannelNode == null) throw new IllegalArgumentException("comparison node is null"); int selfTotal = getNumConnections(Direction.BOTH), theirTotal = iChannelNode.getNumConnections(Direction.BOTH); return selfTotal - theirTotal; } }