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.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import com.google.inject.Injector;
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.util.CellRangeAddress;
import org.sigmah.server.dispatch.CommandHandler;
import org.sigmah.server.dispatch.impl.UserDispatch.UserExecutionContext;
import org.sigmah.server.domain.Contact;
import org.sigmah.server.domain.OrgUnit;
import org.sigmah.server.domain.PhaseModel;
import org.sigmah.server.domain.Project;
import org.sigmah.server.domain.base.EntityId;
import org.sigmah.server.domain.element.ContactListElement;
import org.sigmah.server.domain.element.FlexibleElement;
import org.sigmah.server.domain.layout.Layout;
import org.sigmah.server.domain.layout.LayoutConstraint;
import org.sigmah.server.domain.layout.LayoutGroup;
import org.sigmah.server.handler.GetLayoutGroupIterationsHandler;
import org.sigmah.server.handler.GetValueHandler;
import org.sigmah.server.i18n.I18nServer;
import org.sigmah.server.servlet.base.ServletExecutionContext;
import org.sigmah.server.servlet.exporter.data.BaseSynthesisData;
import org.sigmah.server.servlet.exporter.data.cells.ExportDataCell;
import org.sigmah.server.servlet.exporter.data.cells.ExportLinkCell;
import org.sigmah.server.servlet.exporter.data.cells.ExportStringCell;
import org.sigmah.server.servlet.exporter.utils.ExcelUtils;
import org.sigmah.server.servlet.exporter.utils.ExportConstants;
import org.sigmah.server.servlet.exporter.utils.ExporterUtil;
import org.sigmah.server.servlet.exporter.utils.ValueLabel;
import org.sigmah.shared.Language;
import org.sigmah.shared.command.GetLayoutGroupIterations;
import org.sigmah.shared.command.GetValue;
import org.sigmah.shared.command.result.ListResult;
import org.sigmah.shared.command.result.ValueResult;
import org.sigmah.shared.dto.layout.LayoutGroupIterationDTO;
/**
* Base excel template for project/orgunit/contact excel templates
*
* @author sherzod (v1.3)
*/
public abstract class BaseSynthesisExcelTemplate implements ExportTemplate {
private final BaseSynthesisData data;
private final HSSFWorkbook wb;
private HSSFRow row = null;
private HSSFCell cell = null;
private final ExcelUtils utils;
private CellRangeAddress region;
private final float defHeight = ExportConstants.TITLE_ROW_HEIGHT;
private final int labelColWidth = 60;
private final int valueColWidth = 60;
private final Class<?> clazz;
private final ServletExecutionContext context;
private Injector injector;
public BaseSynthesisExcelTemplate(final BaseSynthesisData data, final HSSFWorkbook wb, final Class<?> clazz, final ServletExecutionContext context, final I18nServer i18nTranslator, final Language language, final Injector injector) throws Throwable {
this.context = context;
this.wb = wb;
this.data = data;
this.clazz = clazz;
this.injector = injector;
String title = data.getLocalizedVersion("projectSynthesis");
if (clazz.equals(OrgUnit.class))
title = data.getLocalizedVersion("orgUnitSynthesis");
if (clazz.equals(Contact.class))
title = data.getLocalizedVersion("contactSynthesis");
final HSSFSheet sheet = wb.createSheet(title);
utils = new ExcelUtils(wb);
int rowIndex = -1;
// empty row
utils.putEmptyRow(sheet, ++rowIndex, 8.65f);
// title
utils.putMainTitle(sheet, ++rowIndex, title.toUpperCase(), data.getNumbOfCols());
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// column headers
row = sheet.createRow(++rowIndex);
utils.putHeader(row, 2, data.getLocalizedVersion("adminFlexibleName"));
utils.putHeader(row, 3, data.getLocalizedVersion("value"));
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// freeze pane
sheet.createFreezePane(0, rowIndex);
// detail
row = sheet.createRow(++rowIndex);
utils.putHeader(row, 1, data.getLocalizedVersion("projectDetails"));
// Project synthesis
if (clazz.equals(Project.class)) {
rowIndex = putLayout(sheet, data.getProject().getProjectModel().getProjectDetails().getLayout(), rowIndex, i18nTranslator, language);
// empty row
utils.putEmptyRow(sheet, ++rowIndex, ExportConstants.EMPTY_ROW_HEIGHT);
// run through project phases to get synthesis data
for (final PhaseModel phaseModel : data.getProject().getProjectModel().getPhaseModels()) {
// phase name
row = sheet.createRow(++rowIndex);
utils.putHeader(row, 1, phaseModel.getName());
rowIndex = putLayout(sheet, phaseModel.getLayout(), rowIndex, i18nTranslator, language);
}
} else if (clazz.equals(OrgUnit.class)) {
// Org Unit synthesis
rowIndex = putLayout(sheet, data.getOrgUnit().getOrgUnitModel().getDetails().getLayout(), rowIndex, i18nTranslator, language);
} else {
// Contact synthesis
rowIndex = putLayout(sheet, data.getContact().getContactModel().getDetails().getLayout(), rowIndex, i18nTranslator, language);
}
sheet.setColumnWidth(0, 256 * 2);
sheet.setColumnWidth(1, 256 * 25);
sheet.setColumnWidth(2, 256 * labelColWidth);
sheet.setColumnWidth(3, 256 * valueColWidth);
}
private int putLayout(final HSSFSheet sheet, final Layout layout, int rowIndex, final I18nServer i18nTranslator, final Language language) throws Throwable {
EntityManager entityManager = injector.getInstance(EntityManager.class);
int typeStartRow = rowIndex;
boolean firstGroup = true;
final EntityId<Integer> container = data.getContainerWithClass(clazz);
// layout groups for each phase
for (final LayoutGroup layoutGroup : layout.getGroups()) {
// layout group cell
if(layoutGroup.getHasIterations()) {
if(createIterativeGroupSheet(layoutGroup, container, i18nTranslator, language, entityManager)) {
if (!firstGroup) {
row = sheet.createRow(++rowIndex);
}
firstGroup = false;
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
cell = sheet.getRow(rowIndex).createCell(2);
cell.setCellStyle(utils.getGroupStyle(wb));
cell.setCellValue(layoutGroup.getTitle());
cell = sheet.getRow(rowIndex).createCell(3);
utils.createLinkCell(cell, data.getLocalizedVersion("seeIterationDetails"), ExportConstants.GROUP_ITERATIONS_SHEET_PREFIX + layoutGroup.getTitle(), true);
}
continue;
}
if (!firstGroup) {
row = sheet.createRow(++rowIndex);
}
firstGroup = false;
row.setHeightInPoints(ExportConstants.TITLE_ROW_HEIGHT);
CellRangeAddress region = new CellRangeAddress(rowIndex, rowIndex, 2, data.getNumbOfCols());
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
cell = sheet.getRow(rowIndex).createCell(2);
cell.setCellStyle(utils.getGroupStyle(wb));
cell.setCellValue(layoutGroup.getTitle());
// elements for each layout group
for (final LayoutConstraint constraint : layoutGroup.getConstraints()) {
final FlexibleElement element = constraint.getElement();
// skip if element is not exportable
if (!element.isExportable()) {
continue;
}
/* CONTACT LIST */
if (data.isWithContacts() && element instanceof ContactListElement) {
final ValueResult valueResult = ExporterUtil.getValueResult(element, container, data.getHandler());
utils.putBorderedBasicCell(sheet, rowIndex, 2, element.getLabel());
utils.createLinkCell(sheet.getRow(rowIndex).createCell(3), String.valueOf(ExporterUtil.getContactListCount(valueResult)), ExportConstants.CONTACT_SHEET_PREFIX + element.getLabel(), true);
}
/* OTHERS */
else {
final ValueLabel pair = ExporterUtil.getPair(element, container, data.getEntityManager(), data.getHandler(), i18nTranslator, language, data);
if (pair != null) {
putElement(sheet, ++rowIndex, pair, pair.isMessage());
}
}
}// elements
}
region = new CellRangeAddress(typeStartRow, rowIndex, 1, 1);
sheet.addMergedRegion(utils.getBorderedRegion(region, sheet, wb));
return rowIndex;
}
/**
* Returns true if sheet was really created (if iterative group contains exportable fields).
*/
private boolean createIterativeGroupSheet(final LayoutGroup group, final EntityId<Integer> container, final I18nServer i18nTranslator, final Language language, final EntityManager entityManager) {
List<LayoutConstraint> allConstraints = group.getConstraints();
List<LayoutConstraint> constraints = new ArrayList<>();
// keeping only exportable constraints
for (LayoutConstraint constraint : allConstraints) {
if (constraint.getElement().isExportable()) {
constraints.add(constraint);
}
}
if (constraints.isEmpty()) {
return false;
}
final HSSFSheet sheet = wb.createSheet(ExportConstants.GROUP_ITERATIONS_SHEET_PREFIX + group.getTitle());
final GetLayoutGroupIterations command = new GetLayoutGroupIterations(group.getId(), container.getId(), -1);
// headers
List<String> headers = new ArrayList<>();
headers.add(i18nTranslator.t(language, "iterationName"));
for (LayoutConstraint constraint : constraints) {
FlexibleElement element = constraint.getElement();
headers.add(element.getLabel());
}
putHeaders(sheet, headers.toArray(new String[headers.size()]));
final CommandHandler<GetLayoutGroupIterations, ListResult<LayoutGroupIterationDTO>> iterationsHandler = injector.getInstance(GetLayoutGroupIterationsHandler.class);
final CommandHandler<GetValue, ValueResult> handler = injector.getInstance(GetValueHandler.class);
try {
final ListResult<LayoutGroupIterationDTO> iterationsResult = iterationsHandler.execute(command, new UserExecutionContext(context));
int rowIndex = 1;
for (final LayoutGroupIterationDTO iteration : iterationsResult.getList()) {
final List<ExportDataCell> values = new ArrayList<>();
values.add(new ExportStringCell(iteration.getName()));
values.addAll(ExporterUtil.getCellsForIteration(iteration, constraints, container, entityManager, i18nTranslator, language, data));
putLine(sheet, rowIndex++, values.toArray(new ExportDataCell[values.size()]));
}
} catch(Exception e) {
}
return true;
}
private void putHeaders(HSSFSheet sheet, String[] values) {
int lineHeight = -1;
row = sheet.createRow(0);
for (int i = 0; i < values.length; i++) {
utils.putHeader(row, i, values[i]);
int cellHeight = utils.calculateLineCount(values[i], labelColWidth);
if (cellHeight > lineHeight) {
lineHeight = cellHeight;
}
}
row.setHeightInPoints(lineHeight * defHeight);
}
private void putLine(HSSFSheet sheet, int rowIndex, ExportDataCell[] values) {
int lineHeight = -1;
row = sheet.createRow(rowIndex);
for (int i = 0; i < values.length; i++) {
ExportDataCell cell = values[i];
if (cell instanceof ExportStringCell) {
utils.putBorderedBasicCell(sheet, rowIndex, i, cell.toCSVString());
} else {
ExportLinkCell link = (ExportLinkCell)cell;
utils.createLinkCell(sheet.getRow(rowIndex).createCell(i), link.getText(), link.getTarget(), true);
}
int cellHeight = utils.calculateLineCount(cell.toCSVString(), labelColWidth);
if (cellHeight > lineHeight) {
lineHeight = cellHeight;
}
}
row.setHeightInPoints(lineHeight * defHeight);
}
private void putElement(HSSFSheet sheet, int rowIndex, ValueLabel pair, boolean isMessage) {
row = sheet.createRow(rowIndex);
utils.putBorderedBasicCell(sheet, rowIndex, 2, pair.getFormattedLabel());
utils.putBorderedBasicCell(sheet, rowIndex, 3, pair.getValue());
if (isMessage) {
row.getCell(3).getCellStyle().setFont(utils.getItalicFont(wb, (short) 11));
}
int lineCount = Math.max(pair.getLines(), utils.calculateLineCount(pair.getFormattedLabel(), labelColWidth));
if (pair.getValue() instanceof String) {
lineCount = Math.max(lineCount, utils.calculateLineCount((String) pair.getValue(), labelColWidth));
}
row.setHeightInPoints(lineCount * defHeight);
}
@Override
public void write(OutputStream output) throws Throwable {
wb.write(output);
}
}