/** @param grids */
  private void writeGeometry(SuperGrid<BPMNElement> grids) {
    // write cells
    double x = 0;
    double y = 0;
    int row = 0;
    int column = 0;
    for (Row<BPMNElement> r : grids) {
      column = 0;
      double cellHeight = heightOfRow[row];
      for (Cell<BPMNElement> c : r) {
        double cellWidth = widthOfColumn[column];
        if (c.isFilled()) {
          BPMNElement elem = c.getValue();
          LayoutingBounds geom = elem.getGeometry();
          double newX =
              x + (cellWidth / 2.0) - (geom.getWidth() / 2.0) + maxLaneDepth * LANE_HEAD_WIDTH;
          double newY = y + (cellHeight / 2.0) - (geom.getHeight() / 2.0);

          elem.setGeometry(new LayoutingBoundsImpl(newX, newY, geom.getWidth(), geom.getHeight()));
          elem.updateDataModel();
        }
        x += cellWidth;
        column++;
      }
      x = 0;
      y += cellHeight;
      row++;
    }
  }
  /**
   * @param lane
   * @param absY
   * @param level
   */
  private void correctLaneElements(BPMNElement lane, double absY, int level) {
    List<BPMNElement> childs = lane2LaneChilds.get(lane);
    double height = 0;
    for (BPMNElement child : childs) {
      correctLaneElements(child, absY + height, level + 1);
      height += child.getGeometry().getHeight();
    }

    int xTrans = level * -LANE_HEAD_WIDTH;
    for (LayoutingElement content : diagram.getChildElementsOf(lane)) {
      if (!BPMNType.isASwimlane(content.getType())) {
        LayoutingBounds geom = content.getGeometry();
        content.setGeometry(
            new LayoutingBoundsImpl(
                geom.getX() + xTrans, geom.getY() - absY, geom.getWidth(), geom.getHeight()));
        ((BPMNElement) content).updateDataModel();
      }
    }
  }
  /**
   * @param lane
   * @param relY
   * @param level
   * @return height of lane
   */
  private double placeLane(BPMNElement lane, double relY, int level) {

    List<BPMNElement> childs = lane2LaneChilds.get(lane);
    double height = 0;
    for (BPMNElement child : childs) {
      height += placeLane(child, height, level + 1);
    }

    int width = poolWidth - level * LANE_HEAD_WIDTH;
    Grid<BPMNElement> myGrid = parent2Context.get(lane).grid;
    int firstRow = superGrid.findRow(myGrid.getFirstRow());
    int lastRow = superGrid.findRow(myGrid.getLastRow());
    for (int i = firstRow; i <= lastRow; i++) {
      height += heightOfRow[i];
    }

    double minHeight = lane.getGeometry().getHeight();
    if (level == 0) {
      minHeight += CELL_MARGIN / 2;
    }
    double diff = minHeight - height;
    if (diff > 1.0) {
      firstRow = superGrid.findRow(findFirstGridOfPool(lane).getFirstRow());
      double toAdd = diff / (lastRow - firstRow + 1.0);
      for (int i = firstRow; i <= lastRow; i++) {
        heightOfRow[i] += toAdd;
      }
      // Redo placement
      return placeLane(lane, relY, level);
    }
    if (level == 0) {
      // pool with magin
      lane.setGeometry(
          new LayoutingBoundsImpl(
              CELL_MARGIN, relY + (CELL_MARGIN / 4), width, height - (CELL_MARGIN / 2)));
    } else {
      // lane without margin
      lane.setGeometry(new LayoutingBoundsImpl(CELL_MARGIN, relY, width, height));
    }
    lane.updateDataModel();
    return height;
  }
  public void doLayout() {
    superGrid = new SuperGrid<BPMNElement>();
    parent2Context.clear();
    lane2LaneChilds.clear();
    maxLaneDepth = 0;

    if (parent == null) {
      for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) {
        prepareLanes((BPMNElement) pool, 1);
      }
    }

    layoutElements();

    if (parent == null) {
      // set collapsed pools
      List<LayoutingElement> collapsedPools =
          this.diagram.getElementsOfType(BPMNType.CollapsedPool);
      Grid<BPMNElement> cpGrid = new Grid<BPMNElement>();
      superGrid.add(0, cpGrid);
      for (LayoutingElement collapsedPool : collapsedPools) {
        // make them small to not disturb finding the biggest ones in
        // each row / column

        collapsedPool.setGeometry(new LayoutingBoundsImpl(0, 0, 0, COLLAPSED_POOL_HEIGHT));
        for (Cell<BPMNElement> insertCell : cpGrid.addLastRow()) {
          insertCell.setValue((BPMNElement) collapsedPool);
        }
      }

      calcGeometry(superGrid);

      poolWidth = Math.max(poolWidth, COLLAPSED_POOL_MIN_WIDTH);

      // place Lanes
      for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) {
        Grid<BPMNElement> firstGrid = findFirstGridOfPool((BPMNElement) pool);
        int firstGridFirstRowIndex = superGrid.findRow(firstGrid.getFirstRow());

        double poolY = 0;
        for (int i = 0; i < firstGridFirstRowIndex; i++) {
          poolY += heightOfRow[i];
        }
        placeLane((BPMNElement) pool, poolY, 0);
      }

      writeGeometry(superGrid);

      // set pools to start at x = CELL_MARGIN & correct size

      for (LayoutingElement collapsedPool : collapsedPools) {
        collapsedPool.setGeometry(
            new LayoutingBoundsImpl(
                CELL_MARGIN, collapsedPool.getGeometry().getY(), poolWidth, COLLAPSED_POOL_HEIGHT));
        ((BPMNElement) collapsedPool).updateDataModel();
      }

      // convert Coordinates of Elements in Lanes from absolut to
      // realitive
      for (LayoutingElement pool : diagram.getElementsOfType(BPMNType.Pool)) {
        correctLaneElements((BPMNElement) pool, pool.getGeometry().getY(), 0);
      }

    } else {
      calcGeometry(superGrid);
      writeGeometry(superGrid);
    }
  }