/**
   * Builds the rows' headers recursively with this order: |-----|-----|-----| | | | 3 | | | |-----|
   * | | 2 | 4 | | | |-----| | 1 | | 5 | | |-----|-----| | | | 7 | | | 6 |-----| | | | 8 |
   * |-----|-----|-----| | | | 11 | | 9 | 10 |-----| | | | 12 | |-----|-----|-----|
   *
   * @param sheet The sheet of the XLS file
   * @param siblings The siblings nodes of the headers structure
   * @param rowNum The row number where the first sibling must be inserted
   * @param columnNum The column number where the siblings must be inserted
   * @param createHelper The file creation helper
   * @throws JSONException
   */
  protected void buildRowsHeaders(
      Sheet sheet,
      CrossTab cs,
      List<Node> siblings,
      int rowNum,
      int columnNum,
      CreationHelper createHelper,
      Locale locale,
      CellStyle cellStyle)
      throws JSONException {
    int rowsCounter = rowNum;

    for (int i = 0; i < siblings.size(); i++) {
      Node aNode = siblings.get(i);
      List<Node> childs = aNode.getChilds();
      Row row = sheet.getRow(rowsCounter);
      Cell cell = row.createCell(columnNum);
      String text = (String) aNode.getDescription();

      if (cs.isMeasureOnRow() && (childs == null || childs.size() <= 0)) {
        // apply the measure scale factor
        text = MeasureScaleFactorOption.getScaledName(text, cs.getMeasureScaleFactor(text), locale);
      }
      cell.setCellValue(createHelper.createRichTextString(text));
      cell.setCellType(this.getCellTypeString());

      cell.setCellStyle(cellStyle);

      int descendants = aNode.getLeafsNumber();
      if (descendants > 1) {
        sheet.addMergedRegion(
            new CellRangeAddress(
                rowsCounter, // first row (0-based)
                rowsCounter + descendants - 1, // last row  (0-based)
                columnNum, // first column (0-based)
                columnNum // last column  (0-based)
                ));
      }

      if (childs != null && childs.size() > 0) {
        buildRowsHeaders(
            sheet, cs, childs, rowsCounter, columnNum + 1, createHelper, locale, cellStyle);
      }
      int increment = descendants > 1 ? descendants : 1;
      rowsCounter = rowsCounter + increment;
    }
  }
  /**
   * Builds the columns' headers recursively with this order:
   * |------------------------------------------| | 1 | 9 |
   * |------------------------------------------| | 2 | 5 | 10 |
   * |-----------|-----------------|------------| | 3 | 4 | 6 | 7 | 8 | 11 | 12 |
   * |------------------------------------------|
   *
   * @param sheet The sheet of the XLS file
   * @param siblings The siblings nodes of the headers structure
   * @param rowNum The row number where the siblings must be inserted
   * @param columnNum The column number where the first sibling must be inserted
   * @param createHelper The file creation helper
   * @param dimensionCellStyle The cell style for cells containing dimensions (i.e. attributes'
   *     names)
   * @param memberCellStyle The cell style for cells containing members (i.e. attributes' values)
   * @throws JSONException
   */
  protected void buildColumnsHeader(
      Sheet sheet,
      CrossTab cs,
      List<Node> siblings,
      int rowNum,
      int columnNum,
      CreationHelper createHelper,
      Locale locale,
      CellStyle memberCellStyle,
      CellStyle dimensionCellStyle)
      throws JSONException {
    int columnCounter = columnNum;

    for (int i = 0; i < siblings.size(); i++) {
      Node aNode = (Node) siblings.get(i);
      List<Node> childs = aNode.getChilds();
      Row row = sheet.getRow(rowNum);
      Cell cell = row.createCell(columnCounter);
      String text = (String) aNode.getDescription();
      if (!cs.isMeasureOnRow() && (childs == null || childs.size() <= 0)) {
        // apply the measure scale factor
        text = MeasureScaleFactorOption.getScaledName(text, cs.getMeasureScaleFactor(text), locale);
      }

      cell.setCellValue(createHelper.createRichTextString(text));
      cell.setCellType(this.getCellTypeString());
      int descendants = aNode.getLeafsNumber();
      if (descendants > 1) {
        sheet.addMergedRegion(
            new CellRangeAddress(
                rowNum, // first row (0-based)
                rowNum, // last row  (0-based)
                columnCounter, // first column (0-based)
                columnCounter + descendants - 1 // last column  (0-based)
                ));
      }

      /*
       * Now we have to set the style properly according to the nature of
       * the node: if it contains the name of a dimension or a member.
       * Since the structure foresees that a list of members follows a
       * dimension, we calculate the position of the node with respect to
       * the leaves; in case it is odd, the cell contains a dimension; in
       * case it is even, the cell contains a dimension.
       */
      int distanceToLeaves = aNode.getDistanceFromLeaves();
      if (!cs.isMeasureOnRow()) {
        distanceToLeaves--;
      }
      boolean isDimensionNameCell = distanceToLeaves > 0 && (distanceToLeaves % 2) == 1;
      if (isDimensionNameCell) {
        cell.setCellStyle(dimensionCellStyle);
      } else {
        cell.setCellStyle(memberCellStyle);
      }

      if (childs != null && childs.size() > 0) {
        buildColumnsHeader(
            sheet,
            cs,
            childs,
            rowNum + 1,
            columnCounter,
            createHelper,
            locale,
            memberCellStyle,
            dimensionCellStyle);
      }
      int increment = descendants > 1 ? descendants : 1;
      columnCounter = columnCounter + increment;
    }
  }