/*
* Copyright (c) 2010 Mathew Hall, University of Sheffield.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* Neither the name of the University of Sheffield nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package translator;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Arrays;
import primitives.cluster.ClusterHead;
import primitives.cluster.ClusterNode;
import primitives.cluster.IClusterLevel;
import primitives.graph.Graph;
import primitives.graph.Node;
import primitives.graph.Transition;
import search.fitnessfunctions.util.EdgeSubsumptionTransformer;
public class DOTWriter implements GraphWriter {
private static final String PREAMBLE = "digraph g{\ncompound = true\n";
public static final String NOTE_START = "###4358b5009c67d0e3<";
public static final String NOTE_END = "###1d7fbf1663fcd3bf>";
private boolean printRefCounts = false;
public void setPrintRefCounts(boolean p){
printRefCounts = p;
}
public String getDOT(ClusterHead ch, String notes){
//ch = (ClusterHead)EdgeSubsumptionTransformer.transform(ch);
StringBuilder ret = new StringBuilder(PREAMBLE);
if(!"".equals(notes)){
ret.append("#Notes are attached. \n");
ret.append(NOTE_START + "\n");
notes =notes.replaceAll("(\r\n|\r|\n)+","\n#");
ret.append(notes);
ret.append("\n");
ret.append(NOTE_END + "\n");
} //*/
// TODO: fix this to write clusters with states in and then the states,
for (int i = 0; i < 3; i++) {
ret .append("\n");
}
ret.append(getTransitions(ch.getNodes()));
int i = 0;
for (IClusterLevel l : ch.getChildren()) {
ret.append(writeCluster(l, String.format("%d", i++)));
}
ret.append("\n}\n");
return ret.toString();
}
public String getDOT(ClusterHead ch) {
return getDOT(ch, "");
}
public String getTransitions(Collection<Node> nodes) {
StringBuilder ret = new StringBuilder();
for (Node n : nodes) {
for (Transition t : n.getTransitionsAsT()) {
if(!t.getSuperstate()){
ret .append(n.getLabel() + " -> "
+ t.getDestinationNode().getLabel() + "[label=\""
+ t.getLabel() + "\"]\n");
}
}
ret.append("\n");
}
return ret.toString();
}
public String getSuperstateTransitions(Collection<Node> nodes, String name){
StringBuilder ret = new StringBuilder();
for (Node n : nodes) {
for (Transition t : n.getTransitionsAsT()) {
if(t.getSuperstate()){
ret .append(n.getLabel() + " -> "
+ t.getDestinationNode().getLabel() + "["
+ t.getLabel() + "ltail="+ name +"];\n");
}
}
ret.append("\n");
}
return ret.toString();
}
public String getDOT(Graph g) {
StringBuilder ret = new StringBuilder(PREAMBLE);
for (Node n : g.getNodes()) {
String x = "";
if(printRefCounts){
x = "[label=\"" + n.getLabel() + "~"+ n.refCount + "\"]";
}
ret.append(n.getLabel() + x+";\n");
}
ret.append("\n\n\n");
ret.append(getTransitions(g.getTransitions().keySet()));
ret.append("\n}\n");
return ret.toString();
}
public String writeCluster(IClusterLevel l, String name) {
if (!l.encapsulates()) {
return String.format("subgraph \"cluster%s\"{\n%s\n}", name, writeCluster(l));
}
if(l.getNodes().size() <= 1){
return String.format("subgraph \"cluster%s\"{\n%s\n}", name, writeCluster(l));
}
int c = 0;
int num = 0;
ClusterNode cl = (ClusterNode) l;
String subMods = "";
//if there is only one child of this cluster then don't print out a box around a box
if(cl.getChildren().size() == 1){
//Using Set there is no get so iterate over the 1 element set:
for(IClusterLevel el: cl.getChildren()){
return writeCluster(el,name);
}
}
for (IClusterLevel el : cl.getChildren()) {
if (!el.encapsulates()) {
c++;
}
}
for (IClusterLevel el : cl.getChildren()) {
String subMod = "";
//if (!el.encapsulates() && c == 1) {
// don't do anything, there's more than one clusterleaf
// so they'll be printed as normal.
//} else {
subMod = writeCluster(el, name + "_" + num++);
//}
subMods += subMod;
}
String trans = getSuperstateTransitions(l.getNodes(),name);
return String.format("subgraph \"cluster%s\""
+ "{"
+ "\n%s\n"
+ "%s"
+ "\n"
+ "%s"
+ "}\n", name, writeCluster(l), subMods,trans);
}
public String writeCluster(IClusterLevel l) {
return "\t" + join(getNodeNames(l), ";\n\t")+ "\n";
}
//XXX: refactor this to go somewhere else, for now let's just ruin OO principles:
public static String join(Collection<? extends Object> c, String d) {
StringBuilder ret = new StringBuilder();
Iterator<? extends Object> iter = c.iterator();
while (iter.hasNext()) {
ret.append((iter.next()).toString());
if (iter.hasNext()) {
ret.append(d);
}
}
return ret.toString();
}
public static Set<String> getNodeNames(IClusterLevel l) {
HashSet<String> nodes = new HashSet<String>();
for (Node n : l.getNodes()) {
nodes.add(n.getLabel());
}
return nodes;
}
@Override
public String getRepresentation(ClusterHead ch) {
return getDOT(ch);
}
@Override
public String getRepresentation(Graph g) {
// TODO Auto-generated method stub
return getDOT( g);
}
}