/**
   * Formats a two-dimensional page.
   *
   * @param cellSet Cell set
   * @param pageCoords Coordinates of page [page, chapter, section, ...]
   * @param columnsAxis Columns axis
   * @param columnsAxisInfo Description of columns axis
   * @param rowsAxis Rows axis
   * @param rowsAxisInfo Description of rows axis
   */
  private Matrix formatPage(
      final CellSet cellSet,
      final int[] pageCoords,
      final CellSetAxis columnsAxis,
      final AxisInfo columnsAxisInfo,
      final CellSetAxis rowsAxis,
      final AxisInfo rowsAxisInfo) {

    // Figure out the dimensions of the blank rectangle in the top left
    // corner.
    final int yOffset = columnsAxisInfo.getWidth();
    final int xOffsset = rowsAxisInfo.getWidth();

    // Populate a string matrix
    final Matrix matrix =
        new Matrix(
            xOffsset + (columnsAxis == null ? 1 : columnsAxis.getPositions().size()),
            yOffset + (rowsAxis == null ? 1 : rowsAxis.getPositions().size()));

    // Populate corner
    List<Level> levels = new ArrayList<>();
    if (rowsAxis != null && rowsAxis.getPositions().size() > 0) {
      Position p = rowsAxis.getPositions().get(0);
      for (int m = 0; m < p.getMembers().size(); m++) {
        AxisOrdinalInfo a = rowsAxisInfo.ordinalInfos.get(m);
        for (Integer depth : a.getDepths()) {
          levels.add(a.getLevel(depth));
        }
      }
      for (int x = 0; x < xOffsset; x++) {
        Level xLevel = levels.get(x);
        String s = xLevel.getCaption();
        for (int y = 0; y < yOffset; y++) {
          final MemberCell memberInfo = new MemberCell(false, x > 0);
          if (y == yOffset - 1) {
            memberInfo.setRawValue(s);
            memberInfo.setFormattedValue(s);
            memberInfo.setProperty("__headertype", "row_header_header");
            memberInfo.setProperty("levelindex", "" + levels.indexOf(xLevel));
            memberInfo.setHierarchy(xLevel.getHierarchy().getUniqueName());
            memberInfo.setParentDimension(xLevel.getDimension().getName());
            memberInfo.setLevel(xLevel.getUniqueName());
          }
          matrix.set(x, y, memberInfo);
        }
      }
    }
    // Populate matrix with cells representing axes
    // noinspection SuspiciousNameCombination
    populateAxis(matrix, columnsAxis, columnsAxisInfo, true, xOffsset);
    populateAxis(matrix, rowsAxis, rowsAxisInfo, false, yOffset);

    // Populate cell values
    for (final Cell cell : cellIter(pageCoords, cellSet)) {
      final List<Integer> coordList = cell.getCoordinateList();
      int x = xOffsset;
      if (coordList.size() > 0) x += coordList.get(0);
      int y = yOffset;
      if (coordList.size() > 1) y += coordList.get(1);
      final DataCell cellInfo = new DataCell(true, false, coordList);
      cellInfo.setCoordinates(cell.getCoordinateList());

      if (cell.getValue() != null) {
        try {
          cellInfo.setRawNumber(cell.getDoubleValue());
        } catch (Exception e1) {
        }
      }
      String cellValue = cell.getFormattedValue(); // First try to get a
      // formatted value

      if (cellValue == null || cellValue.equals("null")) { // $NON-NLS-1$
        cellValue = ""; // $NON-NLS-1$
      }
      if (cellValue.length() < 1) {
        final Object value = cell.getValue();
        if (value == null || value.equals("null")) // $NON-NLS-1$
        cellValue = ""; // $NON-NLS-1$
        else {
          try {
            // TODO this needs to become query / execution specific
            DecimalFormat myFormatter =
                new DecimalFormat(SaikuProperties.formatDefautNumberFormat); // $NON-NLS-1$
            DecimalFormatSymbols dfs = new DecimalFormatSymbols(SaikuProperties.locale);
            myFormatter.setDecimalFormatSymbols(dfs);
            cellValue = myFormatter.format(cell.getValue());
          } catch (Exception e) {
            // TODO: handle exception
          }
        }
        // the raw value
      }

      // Format string is relevant for Excel export
      // xmla cells can throw an error on this
      try {

        String formatString =
            (String) cell.getPropertyValue(Property.StandardCellProperty.FORMAT_STRING);
        if (formatString != null && !formatString.startsWith("|")) {
          cellInfo.setFormatString(formatString);
        } else {
          formatString = formatString.substring(1, formatString.length());
          cellInfo.setFormatString(formatString.substring(0, formatString.indexOf("|")));
        }
      } catch (Exception e) {
        // we tried
      }

      Map<String, String> cellProperties = new HashMap<>();
      String val = Olap4jUtil.parseFormattedCellValue(cellValue, cellProperties);
      if (!cellProperties.isEmpty()) {
        cellInfo.setProperties(cellProperties);
      }
      cellInfo.setFormattedValue(val);
      matrix.set(x, y, cellInfo);
    }
    return matrix;
  }