package org.sigmah.server.servlet.exporter.template;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import java.io.OutputStream;
import java.util.List;
import java.util.Set;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.util.CellRangeAddress;
import org.sigmah.server.domain.Indicator;
import org.sigmah.server.domain.logframe.ExpectedResult;
import org.sigmah.server.domain.logframe.LogFrameActivity;
import org.sigmah.server.domain.logframe.LogFrameGroup;
import org.sigmah.server.domain.logframe.Prerequisite;
import org.sigmah.server.domain.logframe.SpecificObjective;
import org.sigmah.server.servlet.exporter.data.LogFrameExportData;
import org.sigmah.server.servlet.exporter.utils.ExcelUtils;
import org.sigmah.server.servlet.exporter.utils.ExportConstants;
/**
* Excel template for log frame
*
* @author sherzod (v1.3)
*/
public class LogFrameExcelTemplate implements ExportTemplate {
private final LogFrameExportData data;
private final HSSFWorkbook wb;
private HSSFRow row = null;
private HSSFCell cell = null;
private final HSSFSheet sheet;
private final ExcelUtils utils;
private CellRangeAddress region;
private final float defHeight = ExportConstants.TITLE_ROW_HEIGHT;
private final int colWidthDesc = 35;
private final int colWidthIndicator = 25;
private StringBuilder builder;
public LogFrameExcelTemplate(final LogFrameExportData data) throws Throwable {
this(data, new HSSFWorkbook());
}
public LogFrameExcelTemplate(final LogFrameExportData data, final HSSFWorkbook wb) throws Throwable {
this.wb = wb;
this.data = data;
sheet = wb.createSheet(data.getLocalizedVersion("logFrame"));
utils = new ExcelUtils(wb);
int rowIndex = -1;
int cellIndex = 0;
// empty row
utils.putEmptyRow(sheet, ++rowIndex, 8.65f);
// title
utils.putMainTitle(sheet, ++rowIndex, data.getLocalizedVersion("logFrame").toUpperCase(), data.getNumbOfCols());
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// info
utils.putInfoRow(sheet, ++rowIndex, data.getLocalizedVersion("logFrameActionTitle"), data.getTitleOfAction(), data.getNumbOfCols());
utils.putInfoRow(sheet, ++rowIndex, data.getLocalizedVersion("logFrameMainObjective"), data.getMainObjective(), data.getNumbOfCols());
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// column headers
row = sheet.createRow(++rowIndex);
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
cellIndex = 3;
utils.putHeader(row, ++cellIndex, data.getLocalizedVersion("logFrameInterventionLogic"));
utils.putHeader(row, ++cellIndex, data.getLocalizedVersion("indicators"));
utils.putHeader(row, ++cellIndex, data.getLocalizedVersion("logFrameMeansOfVerification"));
utils.putHeader(row, ++cellIndex, data.getLocalizedVersion("logFrameRisksAndAssumptions"));
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// freeze pane
sheet.createFreezePane(0, rowIndex);
boolean titleIsSet = false;
boolean hasElement = false;
int typeStartRow = rowIndex + 1;
// SO
if (data.getEnableSpecificObjectivesGroups()) {
hasElement = data.getSoMap().keySet().size() > 0;
for (final LogFrameGroup soGroup : data.getSoMap().keySet()) {
row = sheet.createRow(++rowIndex);
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
// type (only once) SO,ER,A
if (!titleIsSet) {
putTypeCell(data.getLocalizedVersion("logFrameSpecificObjectives"), data.getLocalizedVersion("logFrameSpecificObjectivesCode"));
titleIsSet = true;
}
// groups
putGroupCell(rowIndex, data.getLocalizedVersion("logFrameGroup"), data.getLocalizedVersion("logFrameSpecificObjectivesCode"), soGroup.getLabel());
// items per group
rowIndex = putSOItems(rowIndex, false, data.getSoMap().get(soGroup));
}
// merge type cell
if (hasElement) {
mergeCell(typeStartRow, rowIndex, 1, 1);
}
} else {
hasElement = data.getSoMainList().size() > 0;
if (hasElement) {
row = sheet.createRow(++rowIndex);
putTypeCell(data.getLocalizedVersion("logFrameSpecificObjectives"), data.getLocalizedVersion("logFrameSpecificObjectivesCode"));
rowIndex = putSOItems(rowIndex, true, data.getSoMainList());
mergeCell(typeStartRow, rowIndex, 1, 1);
}
}
// ER
if (data.getEnableExpectedResultsGroups()) {
hasElement = data.getErMap().keySet().size() > 0;
typeStartRow = rowIndex + 1;
titleIsSet = false;
for (final LogFrameGroup erGroup : data.getErMap().keySet()) {
row = sheet.createRow(++rowIndex);
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
// type (only once) SO,ER,A
if (!titleIsSet) {
putTypeCell(data.getLocalizedVersion("logFrameExceptedResults"), data.getLocalizedVersion("logFrameExceptedResultsCode"));
titleIsSet = true;
}
// groups
putGroupCell(rowIndex, data.getLocalizedVersion("logFrameGroup"), data.getLocalizedVersion("logFrameExceptedResultsCode"), erGroup.getLabel());
// items per group
rowIndex = putERItems(rowIndex, false, data.getErMap().get(erGroup));
}
// merge type cell
if (hasElement) {
mergeCell(typeStartRow, rowIndex, 1, 1);
}
} else {
hasElement = data.getErMainList().size() > 0;
if (hasElement) {
typeStartRow = rowIndex + 1;
row = sheet.createRow(++rowIndex);
putTypeCell(data.getLocalizedVersion("logFrameExceptedResults"), data.getLocalizedVersion("logFrameExceptedResultsCode"));
rowIndex = putERItems(rowIndex, true, data.getErMainList());
mergeCell(typeStartRow, rowIndex, 1, 1);
}
}
// Activities
if (data.getEnableActivitiesGroups()) {
hasElement = data.getAcMap().keySet().size() > 0;
titleIsSet = false;
typeStartRow = rowIndex + 1;
for (final LogFrameGroup aGroup : data.getAcMap().keySet()) {
row = sheet.createRow(++rowIndex);
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
// type (only once) SO,ER,A
if (!titleIsSet) {
putTypeCell(data.getLocalizedVersion("logFrameActivities"), data.getLocalizedVersion("logFrameActivitiesCode"));
titleIsSet = true;
}
// groups
putGroupCell(rowIndex, data.getLocalizedVersion("logFrameGroup"), data.getLocalizedVersion("logFrameActivitiesCode"), aGroup.getLabel());
// items per group
rowIndex = putAcItems(rowIndex, false, data.getAcMap().get(aGroup));
}
// merge type cell
if (hasElement) {
mergeCell(typeStartRow, rowIndex, 1, 1);
}
} else {
hasElement = data.getAcMainList().size() > 0;
if (hasElement) {
typeStartRow = rowIndex + 1;
row = sheet.createRow(++rowIndex);
putTypeCell(data.getLocalizedVersion("logFrameActivities"), data.getLocalizedVersion("logFrameActivitiesCode"));
rowIndex = putAcItems(rowIndex, true, data.getAcMainList());
mergeCell(typeStartRow, rowIndex, 1, 1);
}
}
// Prerequisites
if (data.getEnablePrerequisitesGroups()) {
hasElement = data.getPrMap().keySet().size() > 0;
titleIsSet = false;
typeStartRow = rowIndex + 1;
for (final LogFrameGroup pGroup : data.getPrMap().keySet()) {
row = sheet.createRow(++rowIndex);
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
// type (only once) SO,ER,A
if (!titleIsSet) {
putTypeCell(data.getLocalizedVersion("logFramePrerequisites"), data.getLocalizedVersion("logFramePrerequisitesCode"));
titleIsSet = true;
}
// groups
putGroupCell(rowIndex, data.getLocalizedVersion("logFrameGroup"), data.getLocalizedVersion("logFramePrerequisitesCode"), pGroup.getLabel());
// items per group
rowIndex = putPrItems(rowIndex, false, data.getPrMap().get(pGroup));
}
// merge type cell
if (hasElement) {
mergeCell(typeStartRow, rowIndex, 1, 1);
}
} else {
hasElement = data.getPrMainList().size() > 0;
if (hasElement) {
typeStartRow = rowIndex + 1;
row = sheet.createRow(++rowIndex);
putTypeCell(data.getLocalizedVersion("logFramePrerequisites"), data.getLocalizedVersion("logFramePrerequisitesCode"));
rowIndex = putPrItems(rowIndex, true, data.getPrMainList());
mergeCell(typeStartRow, rowIndex, 1, 1);
}
}
sheet.setColumnWidth(0, 256 * 2);
sheet.setColumnWidth(1, 256 * 20);
sheet.setColumnWidth(2, 256 * 12);
sheet.setColumnWidth(3, 256 * 12);
sheet.setColumnWidth(4, 256 * colWidthDesc);
sheet.setColumnWidth(5, 256 * colWidthIndicator);
sheet.setColumnWidth(6, 256 * colWidthIndicator);
sheet.setColumnWidth(7, 256 * colWidthDesc);
}
private void mergeCell(int startRow, int endRow, int startCol, int endCol) {
region = new CellRangeAddress(startRow, endRow, startCol, endCol);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
}
private int putPrItems(int rowIndex, boolean skipFirst, List<Prerequisite> prList) {
int lineCount = 0;
for (final Prerequisite p : prList) {
if (!skipFirst) {
row = sheet.createRow(++rowIndex);
}
skipFirst = false;
builder = new StringBuilder(data.getLocalizedVersion("logFramePrerequisitesCode"));
builder.append(" ");
builder.append(p.getCode());
builder.append(".");
putCenteredBasicCell(rowIndex, 2, builder.toString());
utils.putBorderedBasicCell(sheet, rowIndex, 3, p.getContent());
lineCount = utils.calculateLineCount(p.getContent(), 18 + 2 * (colWidthDesc + colWidthIndicator));
row.setHeightInPoints(lineCount * defHeight);
mergeCell(rowIndex, rowIndex, 3, data.getNumbOfCols());
}
return rowIndex;
}
private int putAcItems(int rowIndex, boolean skipFirst, List<LogFrameActivity> acList) {
int lineCount = 0;
for (final LogFrameActivity a : acList) {
if (!skipFirst) {
row = sheet.createRow(++rowIndex);
}
skipFirst = false;
builder = new StringBuilder(data.getLocalizedVersion("logFrameActivitiesCode"));
builder.append(" (");
builder.append(data.getLocalizedVersion("logFrameExceptedResultsCode"));
builder.append(" ");
builder.append(data.getFormattedCode(a.getParentExpectedResult().getParentSpecificObjective().getCode()));
builder.append(a.getParentExpectedResult().getCode());
builder.append(".");
builder.append(")");
putCenteredBasicCell(rowIndex, 2, builder.toString());
builder = new StringBuilder(data.getLocalizedVersion("logFrameActivitiesCode"));
builder.append(" ");
builder.append(data.getFormattedCode(a.getParentExpectedResult().getParentSpecificObjective().getCode()));
builder.append(a.getParentExpectedResult().getCode());
builder.append(".");
builder.append(a.getCode());
builder.append(".");
putCenteredBasicCell(rowIndex, 3, builder.toString());
utils.putBorderedBasicCell(sheet, rowIndex, 4, a.getTitle());
utils.putBorderedBasicCell(sheet, rowIndex, 7, null);
lineCount = utils.calculateLineCount(a.getTitle(), colWidthDesc);
row.setHeightInPoints(lineCount * defHeight);
// indicators and their means of verifications
rowIndex = putIndicators(a.getIndicators(), rowIndex, false, lineCount);
}
return rowIndex;
}
private int putERItems(int rowIndex, boolean skipFirst, List<ExpectedResult> erList) {
int lineCount = 0;
for (final ExpectedResult er : erList) {
if (!skipFirst) {
row = sheet.createRow(++rowIndex);
}
skipFirst = false;
builder = new StringBuilder(data.getLocalizedVersion("logFrameExceptedResultsCode"));
builder.append(" (");
builder.append(data.getLocalizedVersion("logFrameSpecificObjectivesCode"));
builder.append(" ");
builder.append(data.getFormattedCode(er.getParentSpecificObjective().getCode()));
builder.append(")");
putCenteredBasicCell(rowIndex, 2, builder.toString());
builder = new StringBuilder(data.getLocalizedVersion("logFrameExceptedResultsCode"));
builder.append(" ");
builder.append(data.getFormattedCode(er.getParentSpecificObjective().getCode()));
builder.append(er.getCode());
builder.append(".");
putCenteredBasicCell(rowIndex, 3, builder.toString());
lineCount = utils.calculateLineCount(er.getInterventionLogic(), colWidthDesc);
utils.putBorderedBasicCell(sheet, rowIndex, 4, er.getInterventionLogic());
lineCount = Math.max(lineCount, utils.calculateLineCount(er.getRisksAndAssumptions(), colWidthDesc));
utils.putBorderedBasicCell(sheet, rowIndex, 7, er.getRisksAndAssumptions());
row.setHeightInPoints(lineCount * defHeight);
// indicators and their means of verifications
rowIndex = putIndicators(er.getIndicators(), rowIndex, false, lineCount);
}
return rowIndex;
}
private int putSOItems(int rowIndex, boolean skipFirst, List<SpecificObjective> soList) {
int lineCount = 0;
for (final SpecificObjective so : soList) {
if (!skipFirst) {
row = sheet.createRow(++rowIndex);
}
skipFirst = false;
builder = new StringBuilder(data.getLocalizedVersion("logFrameSpecificObjectivesCode"));
builder.append(" ");
builder.append(data.getFormattedCode(so.getCode()));
putCenteredBasicCell(rowIndex, 2, builder.toString());
lineCount = utils.calculateLineCount(so.getInterventionLogic(), colWidthDesc);
utils.putBorderedBasicCell(sheet, rowIndex, 4, so.getInterventionLogic());
lineCount = Math.max(lineCount, utils.calculateLineCount(so.getRisksAndAssumptions(), colWidthDesc));
utils.putBorderedBasicCell(sheet, rowIndex, 7, so.getRisksAndAssumptions());
row.setHeightInPoints(lineCount * defHeight);
// indicators and their means of verifications
rowIndex = putIndicators(so.getIndicators(), rowIndex, true, lineCount);
}
return rowIndex;
}
private int putIndicators(final Set<Indicator> indicators, int rowIndex, boolean mergeCodeCells, int lineCount) {
if (indicators.size() > 0) {
int startIndex = rowIndex;
int indiTextLinesSum = 0;
int indiLineCount = 0;
for (final Indicator indicator : indicators) {
if (startIndex != rowIndex) {
row = sheet.createRow(rowIndex);
}
indiLineCount = 0;
if (data.isIndicatorsSheetExist()) {
utils.createLinkCell(row.createCell(5), indicator.getName(), ExportConstants.INDICATOR_SHEET_PREFIX + indicator.getName(), true);
indiLineCount = utils.calculateLineCount(indicator.getName(), colWidthIndicator);
} else {
String indiName = data.getDetailedIndicatorName(indicator.getId());
utils.putBorderedBasicCell(sheet, rowIndex, 5, indiName);
indiLineCount = utils.calculateLineCount(indiName, colWidthIndicator);
}
indiLineCount = Math.max(indiLineCount, utils.calculateLineCount(indicator.getSourceOfVerification(), colWidthIndicator));
utils.putBorderedBasicCell(sheet, rowIndex, 6, indicator.getSourceOfVerification());
indiTextLinesSum += indiLineCount;
row.setHeightInPoints(indiLineCount * defHeight);
rowIndex++;
}
rowIndex--;
if (indiTextLinesSum < lineCount) {
indiLineCount += (lineCount - indiTextLinesSum);
row.setHeightInPoints(indiLineCount * defHeight);
}
if (mergeCodeCells) {
region = new CellRangeAddress(startIndex, rowIndex, 2, 3);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
} else {
region = new CellRangeAddress(startIndex, rowIndex, 2, 2);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
region = new CellRangeAddress(startIndex, rowIndex, 3, 3);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
}
region = new CellRangeAddress(startIndex, rowIndex, 4, 4);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
region = new CellRangeAddress(startIndex, rowIndex, 7, 7);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
} else {
utils.putBorderedBasicCell(sheet, rowIndex, 5, "");
utils.putBorderedBasicCell(sheet, rowIndex, 6, "");
if (mergeCodeCells) {
region = new CellRangeAddress(rowIndex, rowIndex, 2, 3);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
} else {
region = new CellRangeAddress(rowIndex, rowIndex, 2, 2);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
region = new CellRangeAddress(rowIndex, rowIndex, 3, 3);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
}
}
return rowIndex;
}
private void putTypeCell(String typeLabel, String code) {
StringBuilder builder = new StringBuilder(typeLabel);
builder.append(" (");
builder.append(code);
builder.append(")");
utils.putHeader(row, 1, builder.toString());
}
private void putGroupCell(int rowIndex, String groupType, String code, String groupLabel) {
cell = sheet.getRow(rowIndex).createCell(2);
StringBuilder builder = new StringBuilder(groupType);
builder.append(" (");
builder.append(code);
builder.append(") - ");
builder.append(groupLabel);
cell.setCellValue(builder.toString());
CellRangeAddress region = new CellRangeAddress(rowIndex, rowIndex, 2, data.getNumbOfCols());
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
cell.setCellStyle(utils.getGroupStyle(wb));
}
private void putCenteredBasicCell(int rowIndex, int cellIndex, String text) {
cell = utils.putBorderedBasicCell(sheet, rowIndex, cellIndex, text);
cell.getCellStyle().setAlignment(CellStyle.ALIGN_CENTER);
}
@Override
public void write(OutputStream output) throws Throwable {
wb.write(output);
}
}