private void initialize(final LGraph graph) {
    layeredGraph = graph;
    int layerCount = graph.getLayers().size();
    bestNodeOrder = new LNode[layerCount][];
    currentNodeOrder = new LNode[layerCount][];
    originalNodeOrder = new LNode[layerCount][];

    ListIterator<Layer> layerIter = graph.getLayers().listIterator();
    while (layerIter.hasNext()) {
      Layer layer = layerIter.next();

      int layerNodeCount = layer.getNodes().size();
      assert layerNodeCount > 0;

      int layerIndex = layerIter.previousIndex();
      bestNodeOrder[layerIndex] = new LNode[layerNodeCount];
      currentNodeOrder[layerIndex] = new LNode[layerNodeCount];
      originalNodeOrder[layerIndex] = new LNode[layerNodeCount];

      ListIterator<LNode> nodeIter = layer.getNodes().listIterator();
      int id = 0;
      while (nodeIter.hasNext()) {
        LNode node = nodeIter.next();
        node.id = id++;

        currentNodeOrder[layerIndex][nodeIter.previousIndex()] = node;
        bestNodeOrder[layerIndex][nodeIter.previousIndex()] = node;
        originalNodeOrder[layerIndex][nodeIter.previousIndex()] = node;
      }
    }
    crossingCounter = new AllCrossingsCounter(currentNodeOrder);
    if (greedySwitchType.useHyperedgeCounter()) {
      crossingCounter.useHyperedgeCounter();
    }
  }
 private void setAsGraph(final LNode[][] nodeOrder) {
   ListIterator<Layer> layerIter = layeredGraph.getLayers().listIterator();
   while (layerIter.hasNext()) {
     Layer layer = layerIter.next();
     LNode[] nodes = nodeOrder[layerIter.previousIndex()];
     ListIterator<LNode> nodeIter = layer.getNodes().listIterator();
     while (nodeIter.hasNext()) {
       nodeIter.next();
       nodeIter.set(nodes[nodeIter.previousIndex()]);
     }
   }
 }
  /**
   * Merge regions by testing whether they would overlap after applying the deflection.
   *
   * @param layeredGraph the layered graph
   * @return true if any two regions have been merged
   */
  private boolean mergeRegions(final LGraph layeredGraph) {

    boolean changed = false;
    double threshold = OVERLAP_DETECT * spacings.nodeSpacing * spacings.inLayerSpacingFactor;
    for (Layer layer : layeredGraph) {
      Iterator<LNode> nodeIter = layer.getNodes().iterator();

      // Get the first node
      LNode node1 = nodeIter.next();
      LinearSegment region1 = linearSegments[node1.id].region();

      // While there are still nodes following the current node
      while (nodeIter.hasNext()) {
        // Test whether nodes have different regions
        LNode node2 = nodeIter.next();
        LinearSegment region2 = linearSegments[node2.id].region();

        if (region1 != region2) {
          // Calculate how much space is allowed between the nodes
          double spacing = spacings.getVerticalSpacing(node1, node2);

          double node1Extent =
              node1.getPosition().y
                  + node1.getSize().y
                  + node1.getMargin().bottom
                  + region1.deflection
                  + spacing;
          double node2Extent = node2.getPosition().y - node2.getMargin().top + region2.deflection;

          // Test if the nodes are overlapping
          if (node1Extent > node2Extent + threshold) {
            // Merge the first region under the second top level segment
            int weightSum = region1.weight + region2.weight;
            assert weightSum > 0;
            region2.deflection =
                (region2.weight * region2.deflection + region1.weight * region1.deflection)
                    / weightSum;
            region2.weight = weightSum;
            region1.refSegment = region2;
            changed = true;
          }
        }

        node1 = node2;
        region1 = region2;
      }
    }
    return changed;
  }
  /**
   * Creates an unbalanced placement for the sorted linear segments.
   *
   * @param layeredGraph the layered graph to create an unbalanced placement for.
   */
  private void createUnbalancedPlacement(final LGraph layeredGraph) {
    // How many nodes are currently placed in each layer
    int[] nodeCount = new int[layeredGraph.getLayers().size()];

    // The type of the node most recently placed in a given layer
    NodeType[] recentNodeType = new NodeType[layeredGraph.getLayers().size()];

    // Iterate through the linear segments (in proper order!) and place them
    for (LinearSegment segment : linearSegments) {
      // Determine the uppermost placement for the linear segment
      double uppermostPlace = 0.0f;
      for (LNode node : segment.nodes) {
        NodeType nodeType = node.getType();
        int layerIndex = node.getLayer().getIndex();
        nodeCount[layerIndex]++;

        // Calculate how much space to leave between the linear segment and the last
        // node of the given layer
        float spacing = spacings.edgeEdgeSpacing * spacings.inLayerSpacingFactor;
        if (nodeCount[layerIndex] > 0) {
          if (recentNodeType[layerIndex] != null) {
            spacing = spacings.getVerticalSpacing(recentNodeType[layerIndex], nodeType);
          }
        }

        uppermostPlace = Math.max(uppermostPlace, node.getLayer().getSize().y + spacing);
      }

      // Apply the uppermost placement to all elements
      for (LNode node : segment.nodes) {
        // Set the node position
        node.getPosition().y = uppermostPlace + node.getMargin().top;

        // Adjust layer size
        Layer layer = node.getLayer();
        layer.getSize().y =
            uppermostPlace + node.getMargin().top + node.getSize().y + node.getMargin().bottom;

        recentNodeType[layer.getIndex()] = node.getType();
      }
    }
  }
  /**
   * Fills the dependency graph with dependencies. If a dependency would introduce a cycle, the
   * offending linear segment is split into two linear segments.
   *
   * @param layeredGraph the layered graph.
   * @param segmentList the list of segments. Updated to include the newly created linear segments.
   * @param outgoingList the lists of outgoing dependencies for each segment. This essentially
   *     encodes the edges of the dependency graph.
   * @param incomingCountList the number of incoming dependencies for each segment.
   */
  private void createDependencyGraphEdges(
      final LGraph layeredGraph,
      final List<LinearSegment> segmentList,
      final List<List<LinearSegment>> outgoingList,
      final List<Integer> incomingCountList) {

    /*
     * There's some <scaryVoice> faaaancy </scaryVoice> stuff going on here. Basically, we go
     * through all the layers, from left to right. In each layer, we go through all the nodes.
     * For each node, we retrieve the linear segment it's part of and add a dependency to the
     * next node's linear segment. So far so good.
     *
     * This works perfectly fine as long as we assume that the relative order of linear segments
     * doesn't change from one layer to the next. However, since the introduction of north /
     * south port dummies, it can. We now have to avoid creating cycles in the dependency graph.
     * This is done by remembering the indices of each linear segment in the previous layer.
     * When we encounter a segment x, we check if there is a segment y that came before x in the
     * previous layer. (that would introduce a cycle) If that's the case, we split x at the
     * current layer, resulting in two segments, x1 and x2, x2 starting at the current layer.
     * Now, we proceed as usual, adding a dependency from x2 to y. But we have avoided a cycle
     * because y does not depend on x2, but on x1.
     */

    int nextLinearSegmentID = segmentList.size();
    int layerIndex = 0;
    for (Layer layer : layeredGraph) {
      List<LNode> nodes = layer.getNodes();
      if (nodes.isEmpty()) {
        // Ignore empty layers
        continue;
      }

      Iterator<LNode> nodeIter = nodes.iterator();
      int indexInLayer = 0;

      // We carry the previous node with us for dependency management
      LNode previousNode = null;

      // Get the layer's first node
      LNode currentNode = nodeIter.next();
      LinearSegment currentSegment = null;

      while (currentNode != null) {
        // Get the current node's segment
        currentSegment = segmentList.get(currentNode.id);

        /*
         * Check if we have a cycle. That's the case if the following holds: - The current
         * segment appeared in the previous layer as well. - In the previous layer, we find
         * a segment after the current segment that appears before the current segment in
         * the current layer.
         */
        if (currentSegment.indexInLastLayer >= 0) {
          LinearSegment cycleSegment = null;
          Iterator<LNode> cycleNodesIter = layer.getNodes().listIterator(indexInLayer + 1);
          while (cycleNodesIter.hasNext()) {
            LNode cycleNode = cycleNodesIter.next();
            cycleSegment = segmentList.get(cycleNode.id);

            if (cycleSegment.lastLayer == currentSegment.lastLayer
                && cycleSegment.indexInLastLayer < currentSegment.indexInLastLayer) {

              break;
            } else {
              cycleSegment = null;
            }
          }

          // If we have found a cycle segment, we need to split the current linear segment
          if (cycleSegment != null) {
            // Update the current segment before it's split
            if (previousNode != null) {
              incomingCountList.set(currentNode.id, incomingCountList.get(currentNode.id) - 1);
              outgoingList.get(previousNode.id).remove(currentSegment);
            }

            currentSegment = currentSegment.split(currentNode, nextLinearSegmentID++);
            segmentList.add(currentSegment);
            outgoingList.add(new ArrayList<LinearSegment>());

            if (previousNode != null) {
              outgoingList.get(previousNode.id).add(currentSegment);
              incomingCountList.add(1);
            } else {
              incomingCountList.add(0);
            }
          }
        }

        // Now add a dependency to the next node, if any
        LNode nextNode = null;
        if (nodeIter.hasNext()) {
          nextNode = nodeIter.next();
          LinearSegment nextSegment = segmentList.get(nextNode.id);

          outgoingList.get(currentNode.id).add(nextSegment);
          incomingCountList.set(nextNode.id, incomingCountList.get(nextNode.id) + 1);
        }

        // Update segment's layer information
        currentSegment.lastLayer = layerIndex;
        currentSegment.indexInLastLayer = indexInLayer++;

        // Cycle nodes
        previousNode = currentNode;
        currentNode = nextNode;
      }

      layerIndex++;
    }

    // Write debug output graph
    if (layeredGraph.getProperty(LayoutOptions.DEBUG_MODE)) {
      DebugUtil.writeDebugGraph(layeredGraph, segmentList, outgoingList);
    }
  }