/**
  * 出力対象のシートか判定する
  *
  * @param sheet テンプレートシート
  * @param reportBook 帳票ワークブック情報
  * @return
  */
 private boolean isOutputSheet(Sheet sheet, ReportBook reportBook) {
   for (ReportSheet reportSheet : reportBook.getReportSheets()) {
     if (reportSheet != null && sheet.getSheetName().equals(reportSheet.getSheetName())) {
       return true;
     }
   }
   return false;
 }
  /**
   * テンプレートワークブックのシートを、帳票出力単位に変換する。
   *
   * @param workbook テンプレートワークブック
   * @param reportBook 帳票ワークブック情報
   * @return 削除が必要なテンプレートシートインデックス
   */
  private Set<Integer> expandTemplate(Workbook workbook, ReportBook reportBook) {

    Set<Integer> delTemplateIndexs = new TreeSet<Integer>(Collections.reverseOrder());
    Set<Integer> useTemplateIndexs = new HashSet<Integer>();

    // 出力シート単位にコピーする
    for (ReportSheet reportSheet : reportBook.getReportSheets()) {

      if (reportSheet != null) {
        if (reportSheet.getSheetName().equals(reportSheet.getTemplateName())) {
          // テンプレート名=出力シート名
          int lastSheetIndex = workbook.getNumberOfSheets() - 1;
          workbook.setSheetOrder(reportSheet.getSheetName(), lastSheetIndex);
          useTemplateIndexs.add(lastSheetIndex);
        } else {
          int tempIdx = workbook.getSheetIndex(reportSheet.getTemplateName());

          Sheet sheet = workbook.cloneSheet(tempIdx);
          workbook.setSheetName(workbook.getSheetIndex(sheet), reportSheet.getSheetName());
          delTemplateIndexs.add(tempIdx);
        }
      }
    }

    // 出力対象外シートを削除インデックスに追加
    for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
      Sheet sheet = workbook.getSheetAt(i);
      if (!isOutputSheet(sheet, reportBook)) {
        delTemplateIndexs.add(workbook.getSheetIndex(sheet));
      }
    }

    delTemplateIndexs.removeAll(useTemplateIndexs);

    return delTemplateIndexs;
  }
  /**
   * ワークブックの変換処理を実行する。
   *
   * @param reportBook ワークブックの置換情報
   */
  private void processBook(ReportBook reportBook) {

    if (reportBook == null) {
      return;
    }

    Workbook workbook = getTemplateWorkbook(reportBook.getInputStream());

    for (ReportProcessListener listener : listeners) {
      listener.preBookParse(workbook, reportBook);
    }

    checkReportBook(reportBook);

    // テンプレート展開
    Set<Integer> delTemplateIndexs = expandTemplate(workbook, reportBook);

    // 出力ファイル取得
    BookController controller = new BookController(workbook);

    // Parserの設定
    for (ReportsTagParser<?> tagParser : parsers.values()) {
      controller.addTagParser(tagParser);
    }
    // リスナーの設定
    controller.addSheetParseListener(new RemoveAdapter());
    for (ReportProcessListener listener : listeners) {
      controller.addSheetParseListener(listener);
    }

    // Exporterの設定
    for (ConvertConfiguration configuration : reportBook.getConfigurations()) {
      if (configuration == null) {
        continue;
      }
      for (ReportBookExporter reportExporter : exporters.values()) {
        if (configuration.getFormatType().equals(reportExporter.getFormatType())) {
          reportExporter.setConfiguration(configuration);
          reportExporter.setOutputStream(reportBook.getOutputStream());
          controller.addBookExporter(reportExporter);
        }
      }
    }

    ReportsParserInfo reportsParserInfo = new ReportsParserInfo();
    reportsParserInfo.setReportParsers(new ArrayList<ReportsTagParser<?>>(parsers.values()));
    reportsParserInfo.setReportBook(reportBook);

    BookData bookData = controller.getBookData();
    bookData.clear();
    for (String sheetName : controller.getSheetNames()) {
      if (sheetName.startsWith(BookController.COMMENT_PREFIX)) {
        continue;
      }
      ReportSheet reportSheet = ReportsUtil.getReportSheet(sheetName, reportBook);
      if (reportSheet != null) {

        reportsParserInfo.setParamInfo(reportSheet.getParamInfo());
        // 解析の実行
        SheetData sheetData = controller.parseSheet(sheetName, reportsParserInfo);
        // 結果の追加
        controller.getBookData().putSheetData(sheetName, sheetData);
      }
    }

    // 不要テンプレート削除
    for (Integer deleteSheetIndex : delTemplateIndexs) {
      workbook.removeSheetAt(deleteSheetIndex);
    }

    // 出力処理前にリスナー呼び出し
    for (ReportProcessListener listener : listeners) {
      listener.postBookParse(workbook, reportBook);
    }

    // 出力処理の実行
    for (BookExporter exporter : controller.getExporter()) {
      if (exporter != null) {
        exporter.setup();
        try {
          exporter.export(workbook, bookData);
        } finally {
          exporter.tearDown();
        }
      }
    }
  }