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();
    }
  }
    /**
     * Splits this linear segment before the given node. The returned segment contains all nodes
     * from the given node onward, with their ID set to the new segment's ID. Those nodes are
     * removed from this segment.
     *
     * @param node the node to split the segment at.
     * @param newId the new segment's id.
     * @return new linear segment with ID {@code -1} and all nodes from {@code node} onward.
     */
    LinearSegment split(final LNode node, final int newId) {
      int nodeIndex = nodes.indexOf(node);

      // Prepare the new segment
      LinearSegment newSegment = new LinearSegment();
      newSegment.id = newId;

      // Move nodes to the new segment
      ListIterator<LNode> iterator = nodes.listIterator(nodeIndex);
      while (iterator.hasNext()) {
        LNode movedNode = iterator.next();
        movedNode.id = newId;
        newSegment.nodes.add(movedNode);
        iterator.remove();
      }

      return newSegment;
    }
  /**
   * Put a node into the given linear segment and check for following parts of a long edge.
   *
   * @param node the node to put into the linear segment
   * @param segment a linear segment
   * @return {@code true} if the given node was not already part of another segment and was thus
   *     added to the given segment.
   */
  private boolean fillSegment(final LNode node, final LinearSegment segment) {
    NodeType nodeType = node.getType();

    // handle initial big nodes as big node type
    if (node.getProperty(InternalProperties.BIG_NODE_INITIAL)) {
      nodeType = NodeType.BIG_NODE;
    }

    if (node.id >= 0) {
      // The node is already part of another linear segment
      return false;
    } else if (segment.nodeType != null
        && (nodeType == NodeType.BIG_NODE && nodeType != segment.nodeType)) {
      // Big nodes are not allowed to share a linear segment with other dummy nodes
      return false;
    } else {
      // Add the node to the given linear segment
      node.id = segment.id;
      segment.nodes.add(node);
    }
    segment.nodeType = nodeType;

    if (nodeType == NodeType.LONG_EDGE
        || nodeType == NodeType.NORTH_SOUTH_PORT
        || nodeType == NodeType.BIG_NODE) {

      // This is a LONG_EDGE, NORTH_SOUTH_PORT or BIG_NODE dummy; check if any of its
      // successors are of one of these types too. If so, we can form a linear segment
      // with one of them. (not with more than one, though)
      // Note 1: LONG_EDGES and NORTH_SOUTH_PORTs can share a common linear segment
      // Note 2: we must take care not to make a segment out of nodes that are in the same layer
      // Note 3: for BIG_NODEs also the first BIG_NODE_INITIAL which is no actual dummy node has
      // to be considered here
      for (LPort sourcePort : node.getPorts()) {
        for (LPort targetPort : sourcePort.getSuccessorPorts()) {
          LNode targetNode = targetPort.getNode();
          NodeType targetNodeType = targetNode.getType();

          if (node.getLayer() != targetNode.getLayer()) {
            if (nodeType == NodeType.BIG_NODE) {
              // current AND the next node are BIG_NODE dummies
              if (targetNodeType == NodeType.BIG_NODE) {
                if (fillSegment(targetNode, segment)) {
                  // We just added another node to this node's linear segment.
                  // That's quite enough.
                  return true;
                }
              }
            } else {
              // current no bignode and next node is LONG_EDGE and NORTH_SOUTH_PORT
              if (targetNodeType == NodeType.LONG_EDGE
                  || targetNodeType == NodeType.NORTH_SOUTH_PORT) {
                if (fillSegment(targetNode, segment)) {
                  // We just added another node to this node's linear segment.
                  // That's quite enough.
                  return true;
                }
              }
            }
          }
        }
      }
    }

    return true;
  }
  /**
   * Sorts the linear segments of the given layered graph by finding a topological ordering in the
   * corresponding segment ordering graph.
   *
   * @param layeredGraph layered graph to process
   * @return a sorted array of linear segments
   */
  private LinearSegment[] sortLinearSegments(final LGraph layeredGraph) {
    // set the identifier and input / output priority for all nodes
    List<LinearSegment> segmentList = Lists.newArrayList();
    for (Layer layer : layeredGraph) {
      for (LNode node : layer) {
        node.id = -1;
        int inprio = Integer.MIN_VALUE, outprio = Integer.MIN_VALUE;
        for (LPort port : node.getPorts()) {
          for (LEdge edge : port.getIncomingEdges()) {
            int prio = edge.getProperty(InternalProperties.PRIORITY);
            inprio = Math.max(inprio, prio);
          }
          for (LEdge edge : port.getOutgoingEdges()) {
            int prio = edge.getProperty(InternalProperties.PRIORITY);
            outprio = Math.max(outprio, prio);
          }
        }
        node.setProperty(INPUT_PRIO, inprio);
        node.setProperty(OUTPUT_PRIO, outprio);
      }
    }

    // create linear segments for the layered graph, ignoring odd port side dummies
    int nextLinearSegmentID = 0;
    for (Layer layer : layeredGraph) {
      for (LNode node : layer) {
        // Test for the node ID; calls to fillSegment(...) may have caused the node ID
        // to be != -1.
        if (node.id < 0) {
          LinearSegment segment = new LinearSegment();
          segment.id = nextLinearSegmentID++;
          fillSegment(node, segment);
          segmentList.add(segment);
        }
      }
    }

    // create and initialize segment ordering graph
    List<List<LinearSegment>> outgoingList = Lists.newArrayListWithCapacity(segmentList.size());
    List<Integer> incomingCountList = Lists.newArrayListWithCapacity(segmentList.size());
    for (int i = 0; i < segmentList.size(); i++) {
      outgoingList.add(new ArrayList<LinearSegment>());
      incomingCountList.add(0);
    }

    // create edges for the segment ordering graph
    createDependencyGraphEdges(layeredGraph, segmentList, outgoingList, incomingCountList);

    // turn lists into arrays
    LinearSegment[] segments = segmentList.toArray(new LinearSegment[segmentList.size()]);

    @SuppressWarnings("unchecked")
    List<LinearSegment>[] outgoing = outgoingList.toArray(new List[outgoingList.size()]);

    int[] incomingCount = new int[incomingCountList.size()];
    for (int i = 0; i < incomingCount.length; i++) {
      incomingCount[i] = incomingCountList.get(i);
    }

    // gather the sources of the segment ordering graph
    int nextRank = 0;
    List<LinearSegment> noIncoming = Lists.newArrayList();
    for (int i = 0; i < segments.length; i++) {
      if (incomingCount[i] == 0) {
        noIncoming.add(segments[i]);
      }
    }

    // find a topological ordering of the segment ordering graph
    int[] newRanks = new int[segments.length];
    while (!noIncoming.isEmpty()) {
      LinearSegment segment = noIncoming.remove(0);
      newRanks[segment.id] = nextRank++;

      while (!outgoing[segment.id].isEmpty()) {
        LinearSegment target = outgoing[segment.id].remove(0);
        incomingCount[target.id]--;

        if (incomingCount[target.id] == 0) {
          noIncoming.add(target);
        }
      }
    }

    // apply the new ordering to the array of linear segments
    linearSegments = new LinearSegment[segments.length];
    for (int i = 0; i < segments.length; i++) {
      assert outgoing[i].isEmpty();
      LinearSegment ls = segments[i];
      int rank = newRanks[i];
      linearSegments[rank] = ls;
      ls.id = rank;
      for (LNode node : ls.nodes) {
        node.id = rank;
      }
    }

    return linearSegments;
  }