package org.archstudio.utils.bna.dot;
import java.awt.geom.Point2D;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.archstudio.bna.IBNAWorld;
import org.archstudio.bna.IThing;
import org.archstudio.bna.constants.ArrowheadShape;
import org.archstudio.bna.facets.IHasAnchorPoint;
import org.archstudio.bna.facets.IHasArrowheads;
import org.archstudio.bna.facets.IHasBoundingBox;
import org.archstudio.bna.facets.IHasEndpoints;
import org.archstudio.bna.keys.IThingKey;
import org.archstudio.bna.logics.coordinating.StickPointLogic;
import org.archstudio.bna.utils.BNAUtils;
import org.archstudio.swtutils.constants.Orientation;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
public class Edge {
public static final Map<String, Edge> scanForEdges(IBNAWorld world,
Iterable<? extends IThing> things, Map<String, ? extends Node> nodes) {
Map<String, Edge> edges = new HashMap<>();
for (IHasEndpoints t : Iterables.filter(things, IHasEndpoints.class)) {
Endpoint endpoint1 = getEndpoint(world, t, IHasEndpoints.ENDPOINT_1_KEY, nodes);
Endpoint endpoint2 = getEndpoint(world, t, IHasEndpoints.ENDPOINT_2_KEY, nodes);
if (endpoint1 != null && endpoint2 != null) {
if (t instanceof IHasArrowheads) {
IHasArrowheads arrowheads = (IHasArrowheads) t;
if (isPointed(arrowheads, 2)) {
if (!isPointed(arrowheads, 1)) {
edges.put(Node.getUniqueId(t), new Edge(t, endpoint1, endpoint2));
continue;
}
} else if (isPointed(arrowheads, 1)) {
edges.put(Node.getUniqueId(t), new Edge(t, endpoint2, endpoint1));
continue;
}
}
if (t.getEndpoint1().getY() < t.getEndpoint2().getY()) {
edges.put(Node.getUniqueId(t), new Edge(t, endpoint1, endpoint2));
continue;
}
edges.put(Node.getUniqueId(t), new Edge(t, endpoint2, endpoint1));
}
}
return edges;
}
public static Iterable<Node> filterNodesByEdges(Iterable<Node> nodes, Iterable<Edge> edges) {
final Set<String> referencedNodes = new HashSet<>();
for (Edge edge : edges) {
referencedNodes.add(Node.getUniqueId(edge.getFromEndpoint().getNode().getThing()));
referencedNodes.add(Node.getUniqueId(edge.getToEndpoint().getNode().getThing()));
}
return Iterables.filter(nodes, new Predicate<Node>() {
@Override
public boolean apply(Node node) {
return referencedNodes.contains(Node.getUniqueId(node.getThing()));
}
});
}
private static final boolean isPointed(IHasArrowheads arrowheads, int endpoint) {
if (endpoint == 1) {
return arrowheads.getArrowhead1Color() != null
&& arrowheads.getArrowhead1Shape() != ArrowheadShape.NONE;
} else if (endpoint == 2) {
return arrowheads.getArrowhead2Color() != null
&& arrowheads.getArrowhead2Shape() != ArrowheadShape.NONE;
} else {
throw new IllegalArgumentException("Invalid endpoint: " + endpoint);
}
}
private static final Endpoint getEndpoint(IBNAWorld world, IThing thing,
IThingKey<Point2D> pointKey, Map<String, ? extends Node> nodes) {
StickPointLogic stickLogic = world.getThingLogicManager().getThingLogic(StickPointLogic.class);
IThing stickyThing = stickLogic.getStickyThing(thing, pointKey);
if (stickyThing != null) {
IThing stickyAnchoredThing =
stickLogic.getStickyThing(stickyThing, IHasAnchorPoint.ANCHOR_POINT_KEY);
if (stickyAnchoredThing == null) {
Node node = nodes.get(Node.getUniqueId(stickyThing));
if (node == null) {
return null;
}
return new Endpoint(node, null, null);
}
Node anchoredNode = nodes.get(Node.getUniqueId(stickyAnchoredThing));
if (anchoredNode == null) {
Node node = nodes.get(Node.getUniqueId(stickyThing));
if (node == null) {
return null;
}
return new Endpoint(node, null, null);
}
Orientation o = null;
if (stickyAnchoredThing instanceof IHasBoundingBox) {
Point a = BNAUtils.toPoint(((IHasAnchorPoint) stickyThing).getAnchorPoint());
Rectangle r = ((IHasBoundingBox) stickyAnchoredThing).getBoundingBox();
int A = 3;
int B = 7;
Point tl = new Point(r.x + A * r.width / B, r.y + A * r.height / B);
Point br = new Point(r.x + (B - A) * r.width / B, r.y + (B - A) * r.height / B);
if (a.x < tl.x) {
if (a.y < tl.y) {
o = Orientation.NORTHWEST;
} else if (a.y > br.y) {
o = Orientation.SOUTHWEST;
} else {
o = Orientation.WEST;
}
} else if (a.x > br.x) {
if (a.y < tl.y) {
o = Orientation.NORTHEAST;
} else if (a.y > br.y) {
o = Orientation.SOUTHEAST;
} else {
o = Orientation.EAST;
}
} else {
if (a.y < tl.y) {
o = Orientation.NORTH;
} else if (a.y > br.y) {
o = Orientation.SOUTH;
} else {
o = Orientation.NONE;
}
}
}
return new Endpoint(anchoredNode, stickyThing, o);
}
return null;
}
private final IHasEndpoints thing;
private final Endpoint fromEndpoint;
private final Endpoint toEndpoint;
public Edge(IHasEndpoints thing, Endpoint fromEndpoint, Endpoint toEndpoint) {
this.thing = Preconditions.checkNotNull(thing);
this.fromEndpoint = Preconditions.checkNotNull(fromEndpoint);
this.toEndpoint = Preconditions.checkNotNull(toEndpoint);
}
public IHasEndpoints getThing() {
return thing;
}
public Endpoint getFromEndpoint() {
return fromEndpoint;
}
public Endpoint getToEndpoint() {
return toEndpoint;
}
public String toDotEdge() {
return fromEndpoint.toDotID() + " -> " + toEndpoint.toDotID() + ";\n";
}
}