package org.gbif.checklistbank.neo.printer;
import org.gbif.api.vocabulary.Rank;
import org.gbif.checklistbank.neo.Labels;
import org.gbif.checklistbank.neo.RelType;
import org.gbif.checklistbank.neo.traverse.RankEvaluator;
import java.io.IOException;
import java.io.Writer;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
/**
* Expects no pro parte relations in the walker!
* http://www.graphviz.org/doc/info/lang.html
*
* Example:
*
* digraph G {
* t1 [label="Animalia"]
* t1 -> t16 [type=parent_of];
* t16 [label="Abies"]
* t17 [label="Pinus"]
* t17 -> t16 [type=synonym_of];
* }
*/
public class DotPrinter implements TreePrinter {
private final Writer writer;
private final Function<Node, String> getTitle;
private final RankEvaluator rankEvaluator;
public DotPrinter(Writer writer, @Nullable Rank rankThreshold, Function<Node, String> getTitle) {
this.writer = writer;
this.getTitle = getTitle;
this.rankEvaluator = new RankEvaluator(rankThreshold);
printHeader();
}
private void printHeader() {
try {
writer.write("digraph G {\n");
writer.write(" node [shape=plaintext]\n\n");
} catch (IOException e) {
Throwables.propagate(e);
}
}
@Override
public void close() {
try {
writer.write("}\n");
} catch (IOException e) {
Throwables.propagate(e);
}
}
@Override
public void start(Node n) {
try {
// n1 [label="Animalia"]
writer.append(" n");
writer.append(String.valueOf(n.getId()));
writer.append(" [label=\"");
writer.append(getTitle.apply(n));
if (n.hasLabel(Labels.SYNONYM)) {
writer.append("\", fontcolor=darkgreen]\n");
} else {
writer.append("\"]\n");
}
// edges
for (Relationship rel : n.getRelationships(Direction.OUTGOING)) {
if (rankEvaluator.evaluateNode(rel.getOtherNode(n))) {
//n1 -> n16 [type=parent_of]
long start;
long end;
String type = null;
if (rel.isType(RelType.PARENT_OF)) {
start = rel.getStartNode().getId();
end = rel.getEndNode().getId();
} else {
start = rel.getEndNode().getId();
end = rel.getStartNode().getId();
if (rel.isType(RelType.SYNONYM_OF)) {
type = "syn";
} else if (rel.isType(RelType.PROPARTE_SYNONYM_OF)) {
type = "pp";
} else if (rel.isType(RelType.BASIONYM_OF)) {
type = "bas";
} else {
type = rel.getType().name().toLowerCase().replace("_of", "");
}
}
writer.append(" n");
writer.append(String.valueOf(start));
writer.append(" -> n");
writer.append(String.valueOf(end));
if (type != null) {
writer.append(" [color=darkgreen, fontcolor=darkgreen, label=");
writer.append(type);
writer.append("]");
}
writer.append("\n");
}
}
} catch (IOException e) {
Throwables.propagate(e);
}
}
@Override
public void end(Node n) {
}
}