/**
   * This method converts the given tree completely into dot code.
   *
   * @param root The root of the tree.
   * @param ps The stream in which the dot code will be written.
   * @param includeWeights Determines whether to include weights or not.
   * @param includeEois Determines whether to include the execution order indices or not.
   * @param shortLabels Determines whether to use short labels or not.
   */
  private static void dotFromCallingTree(
      final AbstractCallTreeNode<?> root,
      final PrintStream ps,
      final boolean includeWeights,
      final boolean includeEois,
      final boolean shortLabels) {
    // preamble:
    ps.println("digraph G {");
    final StringBuilder edgestringBuilder = new StringBuilder();

    final Map<AbstractCallTreeNode<?>, Integer> nodeIds =
        new Hashtable<AbstractCallTreeNode<?>, Integer>(); // NOPMD (not synchronized)

    AbstractCallTreeFilter.dotEdgesFromSubTree(
        root, nodeIds, new AtomicInteger(0), ps, shortLabels);
    AbstractCallTreeFilter.dotVerticesFromSubTree(
        root,
        includeEois ? new AtomicInteger(1) : null,
        nodeIds,
        ps,
        includeWeights); // NOPMD NOCS (null)

    ps.println(edgestringBuilder.toString());
    ps.println("}");
  }
  public static <T> void writeDotForMessageTrace(
      final AbstractCallTreeNode<T> root,
      final IPairFactory<T> pairFactory,
      final MessageTrace msgTrace,
      final String outputFilename,
      final boolean includeWeights,
      final boolean shortLabels)
      throws FileNotFoundException, TraceProcessingException, UnsupportedEncodingException {

    AbstractCallTreeFilter.<T>addTraceToTree(
        root, msgTrace, pairFactory, false); // false: no aggregation
    AbstractCallTreeFilter.saveTreeToDotFile(
        root, outputFilename, includeWeights, true, shortLabels); // includeEois
  }
 @SuppressWarnings("unchecked")
 // javac reports unchecked casts
 protected static final String nodeLabel(
     final AbstractCallTreeNode<?> node, final boolean shortLabels) {
   if (node.getEntity() instanceof AllocationComponentOperationPair) {
     return AbstractCallTreeFilter.allocationComponentOperationPairNodeLabel(
         (AbstractCallTreeNode<AllocationComponentOperationPair>) node, shortLabels);
   } else if (node.getEntity() instanceof AssemblyComponentOperationPair) {
     return AbstractCallTreeFilter.assemblyComponentOperationPairNodeLabel(
         (AbstractCallTreeNode<AssemblyComponentOperationPair>) node, shortLabels);
   } else {
     throw new UnsupportedOperationException(
         "Node type not supported: " + node.getEntity().getClass().getName());
   }
 }
 /**
  * Traverse tree recursively and generate dot code for vertices.
  *
  * @param n The root node.
  * @param eoiCounter The counter for the execution order index.
  * @param nodeIds The map containing the node IDs.
  * @param ps The stream on which the generated code will be printed.
  * @param includeWeights Determines whether to include weights or not.
  */
 private static void dotVerticesFromSubTree(
     final AbstractCallTreeNode<?> n,
     final AtomicInteger eoiCounter,
     final Map<AbstractCallTreeNode<?>, Integer> nodeIds,
     final PrintStream ps,
     final boolean includeWeights) {
   final int thisId = nodeIds.get(n);
   for (final WeightedDirectedCallTreeEdge<?> child : n.getChildEdges()) {
     final StringBuilder strBuild = new StringBuilder(1024);
     final int childId = nodeIds.get(child.getTarget());
     strBuild
         .append('\n')
         .append(thisId)
         .append("->")
         .append(childId)
         .append("[style=solid,arrowhead=none");
     if (includeWeights) {
       strBuild.append(",label=\"").append(child.getTargetWeight().get()).append('"');
     } else if (eoiCounter != null) {
       strBuild.append(",label=\"").append(eoiCounter.getAndIncrement()).append(".\"");
     }
     strBuild.append(" ]");
     ps.println(strBuild.toString());
     AbstractCallTreeFilter.dotVerticesFromSubTree(
         child.getTarget(), eoiCounter, nodeIds, ps, includeWeights);
   }
 }
 /**
  * This method saves the given tree as valid dot code into the given file.
  *
  * @param root The root of the tree.
  * @param outputFn The file in which the code will be written.
  * @param includeWeights Determines whether to include weights or not.
  * @param includeEois Determines whether to include the execution order indices or not.
  * @param shortLabels Determines whether to use short labels or not.
  * @throws FileNotFoundException If the given file is somehow invalid.
  * @throws UnsupportedEncodingException If the default encoding is not supported.
  */
 protected static void saveTreeToDotFile(
     final AbstractCallTreeNode<?> root,
     final String outputFn,
     final boolean includeWeights,
     final boolean includeEois,
     final boolean shortLabels)
     throws FileNotFoundException, UnsupportedEncodingException {
   final PrintStream ps = new PrintStream(new FileOutputStream(outputFn), false, ENCODING);
   AbstractCallTreeFilter.dotFromCallingTree(root, ps, includeWeights, includeEois, shortLabels);
   ps.flush();
   ps.close();
 }
 /**
  * Traverse tree recursively and generate dot code for edges.
  *
  * @param n The root node to start with.
  * @param nodeIds The map containing the node IDs.
  * @param nextNodeId The counter for the IDs of the nodes.
  * @param ps The stream in which the dot code will be written.
  * @param shortLabels Determines whether to use short labels or not.
  */
 private static void dotEdgesFromSubTree(
     final AbstractCallTreeNode<?> n,
     final Map<AbstractCallTreeNode<?>, Integer> nodeIds,
     final AtomicInteger nextNodeId,
     final PrintStream ps,
     final boolean shortLabels) {
   final StringBuilder strBuild = new StringBuilder(64);
   nodeIds.put(n, nextNodeId.get());
   strBuild
       .append(nextNodeId.getAndIncrement())
       .append("[label =\"")
       .append(
           n.isRootNode()
               ? SystemModelRepository.ROOT_NODE_LABEL // NOCS
               : AbstractCallTreeFilter.nodeLabel(n, shortLabels)) // NOCS
       .append("\",shape=" + DotFactory.DOT_SHAPE_NONE + "];");
   ps.println(strBuild.toString());
   for (final WeightedDirectedCallTreeEdge<?> child : n.getChildEdges()) {
     AbstractCallTreeFilter.dotEdgesFromSubTree(
         child.getTarget(), nodeIds, nextNodeId, ps, shortLabels);
   }
 }