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();
    }
  }
  /**
   * 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();
      }
    }
  }
 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()]);
     }
   }
 }
  /** {@inheritDoc} */
  public void process(final LGraph graph, final IElkProgressMonitor progressMonitor) {
    progressMonitor.begin("Greedy switch crossing reduction", 1);

    greedySwitchType = graph.getProperty(Properties.GREEDY_SWITCH_TYPE);

    int layerCount = graph.getLayers().size();
    if (layerCount < 2 || greedySwitchType == GreedySwitchType.OFF) {
      progressMonitor.done();
      return;
    }

    initialize(graph);

    if (greedySwitchType.useBestOfUpOrDown()) {
      compareSweepingUpwardOrDownward();
    } else {
      sweepOneSidedOrTwoSided();
    }

    setAsGraph(bestNodeOrder);

    progressMonitor.done();
  }