package ini.trakem2.analysis;
import ij.gui.GenericDialog;
import ij.text.TextWindow;
import ini.trakem2.display.AreaList;
import ini.trakem2.display.AreaTree;
import ini.trakem2.display.Ball;
import ini.trakem2.display.Connector;
import ini.trakem2.display.DLabel;
import ini.trakem2.display.Displayable;
import ini.trakem2.display.LayerSet;
import ini.trakem2.display.Patch;
import ini.trakem2.display.Pipe;
import ini.trakem2.display.Polyline;
import ini.trakem2.display.Profile;
import ini.trakem2.display.Treeline;
import ini.trakem2.display.ZDisplayable;
import ini.trakem2.utils.Utils;
import java.awt.Point;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.SwingUtilities;
public class Graph {
static public final <T extends Displayable> Map<String,StringBuilder> extractGraph(final LayerSet ls, final Set<Class<T>> only) {
final StringBuilder sif = new StringBuilder(4096),
xml = new StringBuilder(4096).append("<graph>\n"),
names = new StringBuilder(4096);
final Set<Displayable> seen = new HashSet<Displayable>();
for (final Connector con : ls.getAll(Connector.class)) {
Set<Displayable> origins = con.getOrigins();
if (origins.isEmpty()) {
Utils.log("Graph: ignoring connector without origins: #" + con.getId());
continue;
}
List<Set<Displayable>> target_lists = con.getTargets();
if (target_lists.isEmpty()) {
Utils.log("Graph: ignoring connector without targets: #" + con.getId());
continue;
}
for (final Displayable origin : origins) {
if (Thread.currentThread().isInterrupted()) return null;
if (null != only && !only.contains(origin.getClass())) continue;
seen.add(origin);
for (final Set<Displayable> targets : target_lists) {
for (final Displayable target : targets) {
if (null != only && !only.contains(target.getClass())) continue;
sif.append(origin.getId()).append(" pd ").append(target.getId()).append('\n');
xml.append('\t').append("<edge cid=\"").append(con.getId()).append("\" origin=\"").append(origin.getId()).append("\" target=\"").append(target.getId()).append("\" />\n");
seen.add(target);
}
}
}
}
xml.append("</graph>\n");
for (final Displayable d : seen) {
names.append(d.getId()).append('\t').append(d.getProject().getMeaningfulTitle(d)).append('\n');
}
final Map<String,StringBuilder> m = new HashMap<String,StringBuilder>();
m.put("sif", sif);
m.put("xml", xml);
m.put("names", names);
return m;
}
/** Extract the graph based on connectors; leave @param only null to include all types. */
static public final <T extends Displayable> void extractAndShowGraph(final LayerSet ls, final Set<Class<T>> only) {
final Map<String,StringBuilder> m = Graph.extractGraph(ls, only);
if (null == m) return;
SwingUtilities.invokeLater(new Runnable() { public void run() {
new TextWindow("Graph", m.get("xml").toString(), 500, 500);
TextWindow tw = new TextWindow("SIF", m.get("sif").toString(), 500, 500);
Point p = tw.getLocation();
tw.setLocation(p.x + 50, p.y + 50);
tw = new TextWindow("Names", m.get("names").toString(), 500, 500);
tw.setLocation(p.x + 100, p.y + 100);
}});
}
/** Shows a dialog to pick which classes is one interested in. */
static public final void extractAndShowGraph(final LayerSet ls) {
GenericDialog gd = new GenericDialog("Graph elements");
Class<Displayable>[] c = new Class[]{AreaList.class, AreaTree.class, Ball.class, Connector.class, Patch.class, Pipe.class, Polyline.class, Profile.class, DLabel.class, Treeline.class};
String[] types = new String[]{"AreaList", "AreaTree", "Ball", "Connector", "Image", "Pipe", "Polyline", "Profile", "Text", "Treeline"};
boolean[] states = new boolean[]{true, true, false, false, false, false, true, true, false, true};
assert(c.length == types.length && types.length == states.length);
for (int i=0; i<c.length; i++) {
if (ZDisplayable.class.isAssignableFrom(c[i])) {
if (!ls.contains(c[i])) states[i] = false;
} else if (!ls.containsDisplayable(c[i])) states[i] = false;
}
gd.addCheckboxGroup(types.length, 1, types, states, new String[]{"Include only:"});
gd.showDialog();
if (gd.wasCanceled()) return;
HashSet<Class<Displayable>> only = new HashSet<Class<Displayable>>();
for (int i=0; i<types.length; i++) {
if (gd.getNextBoolean()) only.add(c[i]);
}
Graph.extractAndShowGraph(ls, only);
}
}