public void encodeTbody(FacesContext context, DataTable table, boolean dataOnly)
      throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String rowIndexVar = table.getRowIndexVar();
    String clientId = table.getClientId(context);
    String emptyMessage = table.getEmptyMessage();
    UIComponent emptyFacet = table.getFacet("emptyMessage");
    SubTable subTable = table.getSubTable();
    SummaryRow summaryRow = table.getSummaryRow();

    if (table.isSelectionEnabled()) {
      table.findSelectedRowKeys();
    }

    int rows = table.getRows();
    int first = table.getFirst();
    int rowCount = table.getRowCount();
    int rowCountToRender =
        rows == 0 ? (table.isLiveScroll() ? table.getScrollRows() : rowCount) : rows;
    boolean hasData = rowCount > 0;

    if (!dataOnly) {
      writer.startElement("tbody", null);
      writer.writeAttribute("id", clientId + "_data", null);
      writer.writeAttribute("class", DataTable.DATA_CLASS, null);
    }

    if (hasData) {
      for (int i = first; i < (first + rowCountToRender); i++) {
        if (subTable != null) {
          encodeSubTable(context, table, subTable, i, rowIndexVar);
        } else {

          table.setRowIndex(i);
          if (!table.isRowAvailable()) {
            break;
          }

          encodeRow(context, table, clientId, i, rowIndexVar);

          if (summaryRow != null && !isInSameGroup(context, table, i)) {
            table.setRowIndex(i); // restore
            encodeSummaryRow(context, table, summaryRow);
          }
        }
      }
    } else {
      // Empty message
      writer.startElement("tr", null);
      writer.writeAttribute("class", DataTable.EMPTY_MESSAGE_ROW_CLASS, null);

      writer.startElement("td", null);
      writer.writeAttribute("colspan", table.getColumnsCount(), null);

      if (emptyFacet != null) emptyFacet.encodeAll(context);
      else writer.write(emptyMessage);

      writer.endElement("td");

      writer.endElement("tr");
    }

    if (!dataOnly) {
      writer.endElement("tbody");
    }

    // Cleanup
    table.setRowIndex(-1);
    if (rowIndexVar != null) {
      context.getExternalContext().getRequestMap().remove(rowIndexVar);
    }
  }
  public boolean encodeRow(
      FacesContext context, DataTable table, String clientId, int rowIndex, String rowIndexVar)
      throws IOException {
    ResponseWriter writer = context.getResponseWriter();

    boolean selectionEnabled = table.isSelectionEnabled();

    Object rowKey = null;
    if (selectionEnabled) {
      // try rowKey attribute
      rowKey = table.getRowKey();

      // ask selectable datamodel
      if (rowKey == null) rowKey = table.getRowKeyFromModel(table.getRowData());
    }

    // Preselection
    boolean selected = table.getSelectedRowKeys().contains(rowKey);

    String userRowStyleClass = table.getRowStyleClass();
    String rowStyleClass =
        rowIndex % 2 == 0
            ? DataTable.ROW_CLASS + " " + DataTable.EVEN_ROW_CLASS
            : DataTable.ROW_CLASS + " " + DataTable.ODD_ROW_CLASS;

    if (selected) {
      rowStyleClass = rowStyleClass + " ui-state-highlight";
    }

    if (userRowStyleClass != null) {
      rowStyleClass = rowStyleClass + " " + userRowStyleClass;
    }

    if (table.isEditingRow()) {
      rowStyleClass = rowStyleClass + " " + DataTable.EDITING_ROW_CLASS;
    }

    writer.startElement("tr", null);
    writer.writeAttribute("data-ri", rowIndex, null);
    if (rowKey != null) {
      writer.writeAttribute("data-rk", rowKey, null);
    }
    writer.writeAttribute("class", rowStyleClass, null);
    writer.writeAttribute("role", "row", null);
    if (selectionEnabled) {
      writer.writeAttribute("aria-selected", String.valueOf(selected), null);
    }

    for (UIColumn column : table.getColumns()) {
      if (column instanceof Column) {
        encodeCell(context, table, column, clientId, selected);
      } else if (column instanceof DynamicColumn) {
        DynamicColumn dynamicColumn = (DynamicColumn) column;
        dynamicColumn.applyModel();

        encodeCell(context, table, dynamicColumn, null, false);
      }
    }

    writer.endElement("tr");

    return true;
  }
  protected void encodeMarkup(FacesContext context, DataTable table) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String clientId = table.getClientId(context);
    boolean scrollable = table.isScrollable();
    boolean hasPaginator = table.isPaginator();
    String style = table.getStyle();
    String paginatorPosition = table.getPaginatorPosition();

    // style class
    String containerClass =
        scrollable
            ? DataTable.CONTAINER_CLASS + " " + DataTable.SCROLLABLE_CONTAINER_CLASS
            : DataTable.CONTAINER_CLASS;
    containerClass =
        table.getStyleClass() != null
            ? containerClass + " " + table.getStyleClass()
            : containerClass;
    if (table.isResizableColumns())
      containerClass = containerClass + " " + DataTable.RESIZABLE_CONTAINER_CLASS;
    if (ComponentUtils.isRTL(context, table))
      containerClass = containerClass + " " + DataTable.RTL_CLASS;

    // default sort
    if (!table.isDefaultSorted() && table.getSortBy() != null && !table.isLazy()) {
      SortFeature sortFeature = (SortFeature) table.getFeature(DataTableFeatureKey.SORT);

      if (table.isMultiSort()) sortFeature.multiSort(context, table);
      else sortFeature.singleSort(context, table);

      table.setDefaultSorted();
    }

    if (hasPaginator) {
      table.calculateFirst();
    }

    writer.startElement("div", table);
    writer.writeAttribute("id", clientId, "id");
    writer.writeAttribute("class", containerClass, "styleClass");
    if (style != null) {
      writer.writeAttribute("style", style, "style");
    }

    encodeFacet(context, table, table.getHeader(), DataTable.HEADER_CLASS);

    if (hasPaginator && !paginatorPosition.equalsIgnoreCase("bottom")) {
      encodePaginatorMarkup(context, table, "top");
    }

    if (scrollable) {
      encodeScrollableTable(context, table);
    } else {
      encodeRegularTable(context, table);
    }

    if (hasPaginator && !paginatorPosition.equalsIgnoreCase("top")) {
      encodePaginatorMarkup(context, table, "bottom");
    }

    encodeFacet(context, table, table.getFooter(), DataTable.FOOTER_CLASS);

    if (table.isSelectionEnabled()) {
      encodeStateHolder(
          context,
          table,
          table.getClientId(context) + "_selection",
          table.getSelectedRowKeysAsString());
    }

    if (table.isDraggableColumns()) {
      encodeStateHolder(context, table, table.getClientId(context) + "_columnOrder", null);
    }

    if (scrollable) {
      encodeStateHolder(
          context, table, table.getClientId(context) + "_scrollState", table.getScrollState());
    }

    writer.endElement("div");
  }