// Path: src/main/java/org/laborra/beantrace/BeanTraceException.java
// public class BeanTraceException extends RuntimeException {
//     public BeanTraceException(Throwable cause) {
//         super(cause);
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/internal/Graphs.java
// public class Graphs {
// 
//     /**
//      * Collect all vertices in the given graph.
//      *
//      * @param root A vertex contained in the graph
//      * @return A collection with all vertices
//      */
//     public static Collection<Vertex> collectAllVertices(Vertex root) {
//         final CollectorVisitor collectorVisitor = new CollectorVisitor();
//         traverse(root, collectorVisitor);
//         return collectorVisitor.getResult();
//     }
// 
//     /**
//      * Traverse the graph where the root is contained with the given visitor.
//      *
//      * @param root The starting vertex
//      * @param visitor The visitor to apply to all vertices
//      */
//     public static void traverse(Vertex root, VertexVisitor visitor) {
//         traverse(root, visitor, new HashSet<Vertex>());
//     }
// 
//     private static void traverse(Vertex vertex, VertexVisitor visitor, Set<Vertex> visited) {
//         if (visited.contains(vertex)) {
//             return;
//         }
//         visited.add(vertex);
// 
//         visitor.visit(vertex);
// 
//         final Set<Edge> references = vertex.getReferences();
//         for (Edge reference : references) {
//             traverse(reference.getTo(), visitor, visited);
//         }
//     }
// 
//     /**
//      * Return a map view of the graph edges, where each key is an edge and the value is the
//      * vertex the edge start from.
//      *
//      * @param subject The root vertex of the graph
//      * @return The map representing the graph
//      */
//     public static Map<Edge, Vertex> mapEdgeToStartingVertex(Vertex subject) {
//         final Map<Edge, Vertex> edgeMap = new HashMap<>();
//         traverse(subject, new VertexVisitor() {
//             @Override
//             public void visit(Vertex vertex) {
//                 for (Edge edge : vertex.getReferences()) {
//                     edgeMap.put(edge, vertex);
//                 }
//             }
//         });
//         return edgeMap;
//     }
// 
//     public static Map<Vertex, Integer> mapVerticesToIndex(Collection<Vertex> vertices) {
//         final Map<Vertex, Integer> vertexToIndexMap = new HashMap<>();
//         int i=0;
//         for (Vertex vertex : vertices) {
//             vertexToIndexMap.put(vertex, i);
//             i++;
//         }
//         return vertexToIndexMap;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Attribute.java
// public class Attribute<T> {
//     private String name;
//     private T value;
// 
//     public Attribute(String name, T value) {
//         this.name = name;
//         this.value = value;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public T getValue() {
//         return value;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Edge.java
// public class Edge {
//     private String name;
//     private Vertex to;
// 
//     public Edge(String name, Vertex to) {
//         this.name = name;
//         this.to = to;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public Vertex getTo() {
//         return to;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Vertex.java
// public class Vertex {
//     private Class<?> clazz;
//     private String id;
//     private Set<Edge> references = new HashSet<>();
//     private Set<Attribute> attributes = new HashSet<>();
// 
//     public Vertex(Class<?> clazz, String id) {
//         this(clazz, id, new HashSet<Edge>(), new HashSet<Attribute>());
//     }
// 
//     public Vertex(Class<?> clazz, String id, Set<Edge> references, Set<Attribute> attributes) {
//         this.id = id;
//         this.clazz = clazz;
//         this.references = references;
//         this.attributes = attributes;
//     }
// 
//     public Set<Edge> getReferences() {
//         return references;
//     }
// 
//     public Set<Attribute> getAttributes() {
//         return attributes;
//     }
// 
//     public Class<?> getClazz() {
//         return clazz;
//     }
// 
//     public String getId() {
//         return id;
//     }
// }


import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import org.laborra.beantrace.BeanTraceException;
import org.laborra.beantrace.internal.Graphs;
import org.laborra.beantrace.model.Attribute;
import org.laborra.beantrace.model.Edge;
import org.laborra.beantrace.model.Vertex;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
package org.laborra.beantrace.renderers;



public class GraphvizDotRenderer implements GraphRenderer {

    private final Writer writer;

    public GraphvizDotRenderer(Writer writer) {
        this.writer = writer;
    }

    @Override
    public void render(Vertex subject) {
        final Collection<Vertex> vertices = Graphs.collectAllVertices(subject);
        final Map<Edge, Vertex> edgeMap = Graphs.mapEdgeToStartingVertex(subject);

        try (Writer output = writer) {
            output.append(getHeader())
                    .append(formatEdges(edgeMap))
                    .append(formatVertices(vertices))
                    .append(getFooter());
        } catch (IOException e) {
            throw new BeanTraceException(e);
        }

    }

    private static String getHeader() {
        return "digraph bean_trace {\n";
    }

    private String formatEdges(final Map<Edge, Vertex> edgeMap) {
// Path: src/main/java/org/laborra/beantrace/BeanTraceException.java
// public class BeanTraceException extends RuntimeException {
//     public BeanTraceException(Throwable cause) {
//         super(cause);
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/internal/Graphs.java
// public class Graphs {
// 
//     /**
//      * Collect all vertices in the given graph.
//      *
//      * @param root A vertex contained in the graph
//      * @return A collection with all vertices
//      */
//     public static Collection<Vertex> collectAllVertices(Vertex root) {
//         final CollectorVisitor collectorVisitor = new CollectorVisitor();
//         traverse(root, collectorVisitor);
//         return collectorVisitor.getResult();
//     }
// 
//     /**
//      * Traverse the graph where the root is contained with the given visitor.
//      *
//      * @param root The starting vertex
//      * @param visitor The visitor to apply to all vertices
//      */
//     public static void traverse(Vertex root, VertexVisitor visitor) {
//         traverse(root, visitor, new HashSet<Vertex>());
//     }
// 
//     private static void traverse(Vertex vertex, VertexVisitor visitor, Set<Vertex> visited) {
//         if (visited.contains(vertex)) {
//             return;
//         }
//         visited.add(vertex);
// 
//         visitor.visit(vertex);
// 
//         final Set<Edge> references = vertex.getReferences();
//         for (Edge reference : references) {
//             traverse(reference.getTo(), visitor, visited);
//         }
//     }
// 
//     /**
//      * Return a map view of the graph edges, where each key is an edge and the value is the
//      * vertex the edge start from.
//      *
//      * @param subject The root vertex of the graph
//      * @return The map representing the graph
//      */
//     public static Map<Edge, Vertex> mapEdgeToStartingVertex(Vertex subject) {
//         final Map<Edge, Vertex> edgeMap = new HashMap<>();
//         traverse(subject, new VertexVisitor() {
//             @Override
//             public void visit(Vertex vertex) {
//                 for (Edge edge : vertex.getReferences()) {
//                     edgeMap.put(edge, vertex);
//                 }
//             }
//         });
//         return edgeMap;
//     }
// 
//     public static Map<Vertex, Integer> mapVerticesToIndex(Collection<Vertex> vertices) {
//         final Map<Vertex, Integer> vertexToIndexMap = new HashMap<>();
//         int i=0;
//         for (Vertex vertex : vertices) {
//             vertexToIndexMap.put(vertex, i);
//             i++;
//         }
//         return vertexToIndexMap;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Attribute.java
// public class Attribute<T> {
//     private String name;
//     private T value;
// 
//     public Attribute(String name, T value) {
//         this.name = name;
//         this.value = value;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public T getValue() {
//         return value;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Edge.java
// public class Edge {
//     private String name;
//     private Vertex to;
// 
//     public Edge(String name, Vertex to) {
//         this.name = name;
//         this.to = to;
//     }
// 
//     public String getName() {
//         return name;
//     }
// 
//     public Vertex getTo() {
//         return to;
//     }
// }
// 
// Path: src/main/java/org/laborra/beantrace/model/Vertex.java
// public class Vertex {
//     private Class<?> clazz;
//     private String id;
//     private Set<Edge> references = new HashSet<>();
//     private Set<Attribute> attributes = new HashSet<>();
// 
//     public Vertex(Class<?> clazz, String id) {
//         this(clazz, id, new HashSet<Edge>(), new HashSet<Attribute>());
//     }
// 
//     public Vertex(Class<?> clazz, String id, Set<Edge> references, Set<Attribute> attributes) {
//         this.id = id;
//         this.clazz = clazz;
//         this.references = references;
//         this.attributes = attributes;
//     }
// 
//     public Set<Edge> getReferences() {
//         return references;
//     }
// 
//     public Set<Attribute> getAttributes() {
//         return attributes;
//     }
// 
//     public Class<?> getClazz() {
//         return clazz;
//     }
// 
//     public String getId() {
//         return id;
//     }
// }


// Path: src/main/java/org/laborra/beantrace/renderers/GraphvizDotRenderer.java
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import org.laborra.beantrace.BeanTraceException;
import org.laborra.beantrace.internal.Graphs;
import org.laborra.beantrace.model.Attribute;
import org.laborra.beantrace.model.Edge;
import org.laborra.beantrace.model.Vertex;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

package org.laborra.beantrace.renderers;



public class GraphvizDotRenderer implements GraphRenderer {

    private final Writer writer;

    public GraphvizDotRenderer(Writer writer) {
        this.writer = writer;
    }

    @Override
    public void render(Vertex subject) {
        final Collection<Vertex> vertices = Graphs.collectAllVertices(subject);
        final Map<Edge, Vertex> edgeMap = Graphs.mapEdgeToStartingVertex(subject);

        try (Writer output = writer) {
            output.append(getHeader())
                    .append(formatEdges(edgeMap))
                    .append(formatVertices(vertices))
                    .append(getFooter());
        } catch (IOException e) {
            throw new BeanTraceException(e);
        }

    }

    private static String getHeader() {
        return "digraph bean_trace {\n";
    }

    private String formatEdges(final Map<Edge, Vertex> edgeMap) {
        final Iterable<String> chunks = Iterables.transform(edgeMap.entrySet(), new Function<Map.Entry<Edge, Vertex>, String>() {