/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.datasource.excel;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.obiba.magma.Attribute;
import org.obiba.magma.Disposable;
import org.obiba.magma.Value;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.Variable;
import org.obiba.magma.VariableEntity;
import org.obiba.magma.datasource.excel.support.ExcelUtil;
import org.obiba.magma.datasource.excel.support.VariableConverter;
import org.obiba.magma.type.TextType;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class ExcelValueTableWriter implements ValueTableWriter {
private final ExcelValueTable valueTable;
private ExcelVariableWriter excelVariableWriter;
private List<VariableWithMetadata> variablesWithMetadata = new ArrayList<>();
public ExcelValueTableWriter(ExcelValueTable valueTable, ExcelValueTableWriter excelValueTableWriter) {
this(valueTable);
this.variablesWithMetadata = excelValueTableWriter.variablesWithMetadata;
}
public ExcelValueTableWriter(ExcelValueTable valueTable) {
this.valueTable = valueTable;
}
@Override
public ExcelVariableWriter writeVariables() {
if (excelVariableWriter == null) {
excelVariableWriter = new ExcelVariableWriter();
}
return excelVariableWriter;
}
@NotNull
@Override
public ValueSetWriter writeValueSet(@NotNull VariableEntity entity) {
return new ExcelValueSetWriter(entity);
}
@Override
public void close() {
}
private class ExcelVariableWriter implements VariableWriter, Disposable {
private ExcelVariableWriter() {
}
private Sheet getVariablesSheet() {
return valueTable.getDatasource().getVariablesSheet();
}
private Sheet getCategoriesSheet() {
return valueTable.getDatasource().getCategoriesSheet();
}
@Override
public void writeVariable(@NotNull Variable variable) {
// prepare the header rows
Row headerRowVariables = getVariablesSheet().getRow(0);
if(headerRowVariables == null) {
headerRowVariables = getVariablesSheet().createRow(0);
}
updateVariableSheetHeaderRow(headerRowVariables);
Row headerRowCategories = getCategoriesSheet().getRow(0);
if(headerRowCategories == null) {
headerRowCategories = getCategoriesSheet().createRow(0);
}
updateCategorySheetHeaderRow(headerRowCategories);
variablesWithMetadata.add(new VariableWithMetadata(variable, headerRowVariables, headerRowCategories, valueTable.getName()));
}
@Override
public void dispose() {
VariableConverter converter = valueTable.getVariableConverter();
List<Attribute> variablesAttributes = variablesWithMetadata.stream()
.map(t -> t.getVariable().getAttributes())
.flatMap(Collection::stream)
.collect(Collectors.toList());
List<Attribute> categoriesAttributes = variablesWithMetadata.stream()
.flatMap(variableWithMetadata -> variableWithMetadata.getVariable().getCategories().stream())
.flatMap(attributes -> attributes.getAttributes().stream())
.collect(Collectors.toList());
converter.createVariablesHeaders(variablesAttributes, getVariablesSheet().getRow(0));
converter.createCategoriesHeaders(categoriesAttributes, getCategoriesSheet().getRow(0));
for (VariableWithMetadata variableWithMetadata : variablesWithMetadata) {
converter.marshall(variableWithMetadata);
}
}
@Override
public void removeVariable(@NotNull Variable variable) {
throw new UnsupportedOperationException("Variable cannot be removed from a Excel file");
}
private void updateVariableSheetHeaderRow(Row headerRow) {
VariableConverter converter = valueTable.getVariableConverter();
for(String reservedAttributeName : VariableConverter.reservedVariableHeaders) {
if(converter.getVariableHeaderIndex(reservedAttributeName) == null) {
converter.putVariableHeaderIndex(reservedAttributeName, getLastCellNum(headerRow));
createHeaderCell(headerRow, reservedAttributeName);
}
}
}
private void updateCategorySheetHeaderRow(Row headerRow) {
VariableConverter converter = valueTable.getVariableConverter();
for(String reservedAttributeName : VariableConverter.reservedCategoryHeaders) {
if(converter.getCategoryHeaderIndex(reservedAttributeName) == null) {
converter.putCategoryHeaderIndex(reservedAttributeName, getLastCellNum(headerRow));
createHeaderCell(headerRow, reservedAttributeName);
}
}
}
private void createHeaderCell(Row headerRow, String header) {
Cell headerCell = headerRow.createCell(getLastCellNum(headerRow));
headerCell.setCellValue(header);
headerCell.setCellStyle(valueTable.getDatasource().getHeaderCellStyle());
}
private int getLastCellNum(Row row) {
return row.getLastCellNum() == -1 ? 0 : row.getLastCellNum();
}
@Override
public void close() {
}
}
private class ExcelValueSetWriter implements ValueSetWriter {
private final Row entityRow;
private ExcelValueSetWriter(VariableEntity entity) {
Sheet tableSheet = valueTable.getValueTableSheet();
entityRow = tableSheet.createRow(tableSheet.getPhysicalNumberOfRows());
ExcelUtil.setCellValue(entityRow.createCell(0), TextType.get(), entity.getIdentifier());
}
@Override
public void writeValue(@NotNull Variable variable, Value value) {
// Will create the column if it doesn't exist.
int variableColumn = valueTable.getVariableColumn(variable);
ExcelUtil.setCellValue(entityRow.createCell(variableColumn), value);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
}
}
public class VariableWithMetadata {
private Variable variable;
private Row headerRowVariables;
private Row headerRowCategories;
private String tableName;
VariableWithMetadata(Variable variable, Row headerRowVariables, Row headerRowCategories, String tableName) {
this.variable = variable;
this.headerRowVariables = headerRowVariables;
this.headerRowCategories = headerRowCategories;
this.tableName = tableName;
}
public Variable getVariable() {
return variable;
}
public Row getHeaderRowVariables() {
return headerRowVariables;
}
public Row getHeaderRowCategories() {
return headerRowCategories;
}
public String getTableName() {
return tableName;
}
}
}