/**
   * The table area is a reference area that contains areas for columns, bodies, rows and the
   * contents are in cells.
   *
   * @param parentIter the position iterator
   * @param layoutContext the layout context for adding areas
   */
  @Override
  public void addAreas(final PositionIterator parentIter, final LayoutContext layoutContext) {
    getParentArea(null);
    addId();

    // add space before, in order to implement display-align = "center" or
    // "after"
    if (layoutContext.getSpaceBefore() != 0) {
      addBlockSpacing(0.0, MinOptMax.getInstance(layoutContext.getSpaceBefore()));
    }

    final int startXOffset = getTable().getCommonMarginBlock().startIndent.getValue(this);

    // add column, body then row areas

    // BPD of the table, i.e., height of its content; table's borders and
    // paddings not counted
    int tableHeight = 0;
    // Body childLM;
    final LayoutContext lc = new LayoutContext(0);

    lc.setRefIPD(getContentAreaIPD());
    this.contentLM.setStartXOffset(startXOffset);
    this.contentLM.addAreas(parentIter, lc);
    tableHeight += this.contentLM.getUsedBPD();

    this.curBlockArea.setBPD(tableHeight);

    if (this.columnBackgroundAreas != null) {
      for (final Iterator iter = this.columnBackgroundAreas.iterator(); iter.hasNext(); ) {
        final ColumnBackgroundInfo b = (ColumnBackgroundInfo) iter.next();
        TraitSetter.addBackground(
            b.backgroundArea,
            b.column.getCommonBorderPaddingBackground(),
            this,
            b.xShift,
            -b.backgroundArea.getYOffset(),
            b.column.getColumnWidth().getValue(this),
            tableHeight);
      }
      this.columnBackgroundAreas.clear();
    }

    if (getTable().isSeparateBorderModel()) {
      TraitSetter.addBorders(
          this.curBlockArea,
          getTable().getCommonBorderPaddingBackground(),
          this.discardBorderBefore,
          this.discardBorderAfter,
          false,
          false,
          this);
      TraitSetter.addPadding(
          this.curBlockArea,
          getTable().getCommonBorderPaddingBackground(),
          this.discardPaddingBefore,
          this.discardPaddingAfter,
          false,
          false,
          this);
    }
    TraitSetter.addBackground(
        this.curBlockArea, getTable().getCommonBorderPaddingBackground(), this);
    TraitSetter.addMargins(
        this.curBlockArea,
        getTable().getCommonBorderPaddingBackground(),
        this.startIndent,
        this.endIndent,
        this);
    TraitSetter.addBreaks(
        this.curBlockArea, getTable().getBreakBefore(), getTable().getBreakAfter());
    TraitSetter.addSpaceBeforeAfter(
        this.curBlockArea, layoutContext.getSpaceAdjust(), this.effSpaceBefore, this.effSpaceAfter);

    flush();

    resetSpaces();
    this.curBlockArea = null;

    notifyEndOfLayout();
  }
  /** {@inheritDoc} */
  @Override
  public List getNextKnuthElements(final LayoutContext context, final int alignment) {

    final List returnList = new LinkedList();

    /*
     * Compute the IPD and adjust it if necessary (overconstrained)
     */
    this.referenceIPD = context.getRefIPD();
    if (getTable().getInlineProgressionDimension().getOptimum(this).getEnum() != EN_AUTO) {
      final int contentIPD =
          getTable().getInlineProgressionDimension().getOptimum(this).getLength().getValue(this);
      updateContentAreaIPDwithOverconstrainedAdjust(contentIPD);
    } else {
      if (!getTable().isAutoLayout()) {
        final BlockLevelEventProducer eventProducer =
            BlockLevelEventProducer.Provider.get(getTable().getUserAgent().getEventBroadcaster());
        eventProducer.tableFixedAutoWidthNotSupported(this, getTable().getLocator());
      }
      updateContentAreaIPDwithOverconstrainedAdjust();
    }
    final int sumOfColumns = this.columns.getSumOfColumnWidths(this);
    if (!this.autoLayout && sumOfColumns > getContentAreaIPD()) {
      log.debug(
          FONode.decorateWithContextInfo(
              "The sum of all column widths is larger than the specified table width.",
              getTable()));
      updateContentAreaIPDwithOverconstrainedAdjust(sumOfColumns);
    }
    final int availableIPD = this.referenceIPD - getIPIndents();
    if (getContentAreaIPD() > availableIPD) {
      final BlockLevelEventProducer eventProducer =
          BlockLevelEventProducer.Provider.get(getTable().getUserAgent().getEventBroadcaster());
      eventProducer.objectTooWide(
          this,
          getTable().getName(),
          getContentAreaIPD(),
          context.getRefIPD(),
          getTable().getLocator());
    }

    /*
     * initialize unit to determine computed values for
     * proportional-column-width()
     */
    if (this.tableUnit == 0.0) {
      this.tableUnit = this.columns.computeTableUnit(this);
    }

    if (!this.firstVisibleMarkServed) {
      addKnuthElementsForSpaceBefore(returnList, alignment);
    }

    if (getTable().isSeparateBorderModel()) {
      addKnuthElementsForBorderPaddingBefore(returnList, !this.firstVisibleMarkServed);
      this.firstVisibleMarkServed = true;
      // Border and padding to be repeated at each break
      // This must be done only in the separate-border model, as in
      // collapsing
      // tables have no padding and borders are determined at the cell
      // level
      addPendingMarks(context);
    }

    // Elements for the table-header/footer/body
    List contentKnuthElements;
    this.contentLM = new TableContentLayoutManager(this);
    final LayoutContext childLC = new LayoutContext(0);
    /*
     * childLC.setStackLimit( MinOptMax.subtract(context.getStackLimit(),
     * stackSize));
     */
    childLC.setRefIPD(context.getRefIPD());
    childLC.copyPendingMarksFrom(context);

    contentKnuthElements = this.contentLM.getNextKnuthElements(childLC, alignment);
    // Set index values on elements coming from the content LM
    final Iterator iter = contentKnuthElements.iterator();
    while (iter.hasNext()) {
      final ListElement el = (ListElement) iter.next();
      notifyPos(el.getPosition());
    }
    // TODO fixme : don't toString() a list...
    log.debug(contentKnuthElements.toString());
    wrapPositionElements(contentKnuthElements, returnList);

    context.updateKeepWithPreviousPending(getKeepWithPrevious());
    context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());

    context.updateKeepWithNextPending(getKeepWithNext());
    context.updateKeepWithNextPending(childLC.getKeepWithNextPending());

    if (getTable().isSeparateBorderModel()) {
      addKnuthElementsForBorderPaddingAfter(returnList, true);
    }
    addKnuthElementsForSpaceAfter(returnList, alignment);

    if (!context.suppressBreakBefore()) {
      // addKnuthElementsForBreakBefore(returnList, context);
      final int breakBefore =
          BreakUtil.compareBreakClasses(getTable().getBreakBefore(), childLC.getBreakBefore());
      if (breakBefore != Constants.EN_AUTO) {
        returnList.add(
            0,
            new BreakElement(
                getAuxiliaryPosition(), 0, -KnuthElement.INFINITE, breakBefore, context));
      }
    }

    // addKnuthElementsForBreakAfter(returnList, context);
    final int breakAfter =
        BreakUtil.compareBreakClasses(getTable().getBreakAfter(), childLC.getBreakAfter());
    if (breakAfter != Constants.EN_AUTO) {
      returnList.add(
          new BreakElement(getAuxiliaryPosition(), 0, -KnuthElement.INFINITE, breakAfter, context));
    }

    setFinished(true);
    resetSpaces();
    return returnList;
  }