package org.nextprot.api.web.service.impl.writer;
import com.google.common.base.Preconditions;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.hssf.util.HSSFColor;
import org.nextprot.api.core.domain.Entry;
import org.nextprot.api.core.service.export.format.EntryBlock;
import org.nextprot.api.core.service.fluent.EntryConfig;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* An abstract class to export nextprot entries in XLS format.
*
* Need an implementation of <code>EntryDataProvider</code> to handle extraction of data in Records
* for XLS sheet rows and cells to be properly created.
*
* Created by fnikitin on 11/08/15.
*/
public abstract class EntryXLSWriter extends EntryOutputStreamWriter {
private final HSSFWorkbook workbook;
private final HSSFSheet worksheet;
private final HSSFCellStyle hlinkStyle;
private int rowIndex;
/** A record represents field values to be written into an XLS row */
public static class Record {
private final Object[] values;
private int[] stringValueIndices = new int[0];
private int[] intValueIndices = new int[0];
private int[] doubleValueIndices = new int[0];
private int[] booleanValueIndices = new int[0];
private Map<Integer, String> hyperLinks = new HashMap<>();
public Record(Object[] values) {
Preconditions.checkNotNull(values);
this.values = values;
}
public Object[] getValues() {
return values;
}
// @return indices which values are of type String
public int[] getStringValueIndices() {
return stringValueIndices;
}
public void setStringValueIndices(int[] stringValueIndices) {
this.stringValueIndices = stringValueIndices;
}
// @return indices which values are of type int
public int[] getIntValueIndices() {
return intValueIndices;
}
public void setIntValueIndices(int[] intValueIndices) {
this.intValueIndices = intValueIndices;
}
// @return indices which values are of type float or double
public int[] getDoubleValueIndices() {
return doubleValueIndices;
}
public void setDoubleValueIndices(int[] doubleValueIndices) {
this.doubleValueIndices = doubleValueIndices;
}
// @return indices which values are boolean
public int[] getBooleanValueIndices() {
return booleanValueIndices;
}
public void setBooleanValueIndices(int[] booleanValueIndices) {
this.booleanValueIndices = booleanValueIndices;
}
// Define hyperlinks for specific cells
public Map<Integer, String> getHyperLinks() {
return hyperLinks;
}
public void addHyperLinks(int index, String address) {
hyperLinks.put(index, address);
}
}
/** Provides nextprot entry data to this XLS writer */
public interface EntryDataProvider {
// @return the EntryBlocks needed to get data (equivalent to view names)
List<EntryBlock> getSourceEntryBlocks();
// @return the field names
String[] getFieldNames();
// @return a list of data records (a record contain the field values) of the given entry
List<Record> getRecords(Entry entry);
}
private final EntryDataProvider entryDataProvider;
protected EntryXLSWriter(OutputStream stream, String sheetName, EntryDataProvider entryDataProvider) {
super(stream);
Preconditions.checkNotNull(entryDataProvider);
workbook = new HSSFWorkbook();
hlinkStyle = createHLinkStyle(workbook);
worksheet = workbook.createSheet(sheetName);
rowIndex = 0;
this.entryDataProvider = entryDataProvider;
}
public static EntryXLSWriter newNPEntryXLSWriter(OutputStream os, String viewName) {
if (viewName.equals("isoforms"))
return new EntryIsoformXLSWriter(os);
else
return new EntryOverviewXLSWriter(os);
}
private static HSSFCellStyle createHLinkStyle(HSSFWorkbook workbook) {
HSSFCellStyle ls = workbook.createCellStyle();
HSSFFont hlinkFont = workbook.createFont();
hlinkFont.setUnderline(HSSFFont.U_SINGLE);
hlinkFont.setColor(HSSFColor.BLUE.index);
ls.setFont(hlinkFont);
return ls;
}
@Override
public void write(Collection<String> entries, Map<String, Object> headerParams) throws IOException {
super.write(entries, headerParams);
workbook.write(getStream());
}
@Override
protected void writeHeader(Map<String, Object> headerParams) throws IOException {
String[] headers = entryDataProvider.getFieldNames();
HSSFRow row = worksheet.createRow(rowIndex);
for (int i=0 ; i<headers.length ; i++) {
HSSFCell accCodeCell = row.createCell(i);
accCodeCell.setCellValue(headers[i]);
}
rowIndex++;
}
@Override
protected void writeEntry(String entryName) throws IOException {
EntryConfig config = EntryConfig.newConfig(entryName);
for (EntryBlock block : entryDataProvider.getSourceEntryBlocks()) {
config.withBlock(block);
}
Entry entry = entryBuilderService.build(config);
for (Record record : entryDataProvider.getRecords(entry)) {
HSSFRow row = worksheet.createRow(rowIndex);
writeRecord(row, record);
rowIndex++;
}
}
private void writeRecord(HSSFRow row, Record record) {
Object[] values = record.getValues();
HSSFCell[] cells = new HSSFCell[values.length];
for (int index : record.getStringValueIndices()) {
cells[index] = row.createCell(index);
cells[index].setCellValue((String)values[index]);
}
for (int index : record.getBooleanValueIndices()) {
cells[index] = row.createCell(index);
cells[index].setCellValue((boolean)values[index]);
}
for (int index : record.getIntValueIndices()) {
cells[index] = row.createCell(index);
cells[index].setCellValue((int)values[index]);
}
for (int index : record.getDoubleValueIndices()) {
cells[index] = row.createCell(index);
cells[index].setCellValue((double) values[index]);
}
Map<Integer, String> links = record.getHyperLinks();
for (int index : links.keySet()) {
setHyperLink(cells[index], links.get(index));
}
}
// No need to flush after each entry has been written
protected void flush() throws IOException { }
private void setHyperLink(HSSFCell cell, String address) {
HSSFHyperlink link = new HSSFHyperlink(HSSFHyperlink.LINK_URL);
link.setAddress(address);
cell.setHyperlink(link);
cell.setCellStyle(hlinkStyle);
}
@Override
public void close() throws IOException {
workbook.close();
}
}