/**
   * Calculates the data-range that is to be used for plotting the chart.
   *
   * @param tableBlock the {@link TableBlock}.
   * @return an integer array consisting of start-row, start-column, end-row and end-column of the
   *     data range.
   * @throws MacroExecutionException if it's not possible to determine the data range correctly.
   */
  protected int[] getDataRange(TableBlock tableBlock) throws MacroExecutionException {

    Integer[] r = getDataRangeFromParameter();

    int rowCount = tableBlock.getChildren().size();
    if (rowCount > 0) {
      TableRowBlock firstRow = (TableRowBlock) tableBlock.getChildren().get(0);
      int columnCount = firstRow.getChildren().size();
      if (columnCount > 0) {
        return new int[] {
          r[0] != null ? r[0] : 0,
          r[1] != null ? r[1] : 0,
          r[2] != null ? r[2] : rowCount - 1,
          r[3] != null ? r[3] : columnCount - 1
        };
      }
    }

    throw new MacroExecutionException("Data table is incomplete.");
  }
  /**
   * Build a category dataset.
   *
   * @param tableBlock The table block to parse.
   * @param dataRange The data range.
   * @param datasetBuilder The dataset builder.
   * @throws MacroExecutionException if there are any errors.
   */
  private void buildDataset(
      TableBlock tableBlock, int[] dataRange, TableDatasetBuilder datasetBuilder)
      throws MacroExecutionException {
    int startRow = dataRange[0];
    int startColumn = dataRange[1];
    int endRow = dataRange[2];
    int endColumn = dataRange[3];

    if (startRow == 0 && datasetBuilder.forceRowHeadings()) {
      startRow = 1;
    }

    if (startColumn == 0 && datasetBuilder.forceColumnHeadings()) {
      startColumn = 1;
    }

    getRowKeys(tableBlock, startRow, endRow, startColumn, datasetBuilder);

    getColumnKeys(tableBlock, startColumn, endColumn, startRow, datasetBuilder);

    for (int i = startRow; i <= endRow; i++) {
      if (i < tableBlock.getChildren().size()) {
        TableRowBlock tableRow = (TableRowBlock) tableBlock.getChildren().get(i);
        for (int j = startColumn; j <= endColumn; j++) {
          if (j < tableRow.getChildren().size()) {
            Number value = cellContentAsNumber((TableCellBlock) tableRow.getChildren().get(j));
            datasetBuilder.setValue(i - startRow, j - startColumn, value);
          } else {
            throw new MacroExecutionException("Data range (columns) overflow.");
          }
        }
      } else {
        throw new MacroExecutionException("Data range (rows) overflow.");
      }
    }
  }
  /**
   * @param tableBlock The table block to parse.
   * @param startColumn The first column to include.
   * @param endColumn The last column to include.
   * @param startRow The first row to include.
   * @param datasetBuilder The dataset builder.
   * @throws MacroExecutionException if there are any errors in the table.
   */
  private void getColumnKeys(
      TableBlock tableBlock,
      int startColumn,
      int endColumn,
      int startRow,
      TableDatasetBuilder datasetBuilder)
      throws MacroExecutionException {
    datasetBuilder.setNumberOfColumns(endColumn - startColumn + 1);

    if (startRow > 0) {
      TableRowBlock tableRow = (TableRowBlock) tableBlock.getChildren().get(startRow - 1);
      for (int i = startColumn; i <= endColumn; i++) {
        String key = cellContentAsString((TableCellBlock) tableRow.getChildren().get(i));
        datasetBuilder.setColumnHeading(i - startColumn, key);
      }
    } else {
      for (int i = startColumn; i <= endColumn; i++) {
        datasetBuilder.setColumnHeading(i - startColumn, "C" + i);
      }
    }
  }
  /**
   * @param tableBlock The table block to parse.
   * @param startRow The first row to include.
   * @param endRow The last row to include.
   * @param startColumn The first column to include.
   * @param datasetBuilder The dataset builder.
   * @throws MacroExecutionException if there are any errors in the table.
   */
  private void getRowKeys(
      TableBlock tableBlock,
      int startRow,
      int endRow,
      int startColumn,
      TableDatasetBuilder datasetBuilder)
      throws MacroExecutionException {

    datasetBuilder.setNumberOfRows(endRow - startRow + 1);

    if (startColumn > 0) {
      Set<String> rowKeySet = new HashSet<String>();
      for (int i = startRow; i <= endRow; i++) {
        TableRowBlock tableRow = (TableRowBlock) tableBlock.getChildren().get(i);
        String key =
            cellContentAsString((TableCellBlock) tableRow.getChildren().get(startColumn - 1));
        datasetBuilder.setRowHeading(i - startRow, key);
      }
    } else {
      for (int i = startRow; i <= endRow; i++) {
        datasetBuilder.setRowHeading(i - startRow, "R" + i);
      }
    }
  }