/** {@inheritDoc} */
  @Override
  public CGraph transform(final LGraph inputGraph) {
    layeredGraph = inputGraph;

    // checking if the graph has edges and possibly prohibiting vertical compaction
    hasEdges =
        layeredGraph
            .getLayers()
            .stream()
            .flatMap(l -> l.getNodes().stream())
            .anyMatch(n -> !Iterables.isEmpty(n.getConnectedEdges()));
    EnumSet<Direction> supportedDirections =
        EnumSet.of(Direction.UNDEFINED, Direction.LEFT, Direction.RIGHT);
    if (!hasEdges) {
      supportedDirections.add(Direction.UP);
      supportedDirections.add(Direction.DOWN);
    }

    // initializing fields
    cGraph = new CGraph(supportedDirections);

    // importing LGraphElements into CNodes
    readNodes();

    return cGraph;
  }
  /** {@inheritDoc} */
  public void process(final LGraph layeredGraph, final IKielerProgressMonitor monitor) {
    monitor.begin("Comment pre-processing", 1);

    Iterator<LNode> nodeIter = layeredGraph.getLayerlessNodes().iterator();
    while (nodeIter.hasNext()) {
      LNode node = nodeIter.next();
      if (node.getProperty(LayoutOptions.COMMENT_BOX)) {
        int edgeCount = 0;
        LEdge edge = null;
        LPort oppositePort = null;
        for (LPort port : node.getPorts()) {
          edgeCount += port.getDegree();
          if (port.getIncomingEdges().size() == 1) {
            edge = port.getIncomingEdges().get(0);
            oppositePort = edge.getSource();
          }
          if (port.getOutgoingEdges().size() == 1) {
            edge = port.getOutgoingEdges().get(0);
            oppositePort = edge.getTarget();
          }
        }

        if (edgeCount == 1
            && oppositePort.getDegree() == 1
            && !oppositePort.getNode().getProperty(LayoutOptions.COMMENT_BOX)) {
          // found a comment that has exactly one connection
          processBox(node, edge, oppositePort, oppositePort.getNode());
          nodeIter.remove();
        } else {
          // reverse edges that are oddly connected
          List<LEdge> revEdges = Lists.newArrayList();
          for (LPort port : node.getPorts()) {
            for (LEdge outedge : port.getOutgoingEdges()) {
              if (!outedge.getTarget().getOutgoingEdges().isEmpty()) {
                revEdges.add(outedge);
              }
            }

            for (LEdge inedge : port.getIncomingEdges()) {
              if (!inedge.getSource().getIncomingEdges().isEmpty()) {
                revEdges.add(inedge);
              }
            }
          }

          for (LEdge re : revEdges) {
            re.reverse(layeredGraph, true);
          }
        }
      }
    }

    monitor.done();
  }
  /** {@inheritDoc} */
  @Override
  public void applyLayout() {
    // applying the compacted positions
    applyNodePositions();

    // calculating new graph size and offset
    KVector topLeft = new KVector(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
    KVector bottomRight = new KVector(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
    for (CNode cNode : cGraph.cNodes) {
      topLeft.x = Math.min(topLeft.x, cNode.hitbox.x);
      topLeft.y = Math.min(topLeft.y, cNode.hitbox.y);
      bottomRight.x = Math.max(bottomRight.x, cNode.hitbox.x + cNode.hitbox.width);
      bottomRight.y = Math.max(bottomRight.y, cNode.hitbox.y + cNode.hitbox.height);
    }
    layeredGraph.getOffset().reset().add(topLeft.clone().negate());
    layeredGraph.getSize().reset().add(bottomRight.clone().sub(topLeft));

    // resetting lists
    cGraph.cGroups.clear();
    cGraph.cNodes.clear();
  }