package au.com.acpfg.misc.jemboss.local;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.knime.core.data.DataCell;
import org.knime.core.data.DataColumnSpec;
import org.knime.core.data.DataColumnSpecCreator;
import org.knime.core.data.DataTable;
import org.knime.core.data.DataTableSpec;
import org.knime.core.data.DataType;
import org.knime.core.data.def.IntCell;
import org.knime.core.data.def.StringCell;
import au.com.acpfg.misc.jemboss.settings.DummySetting;
import au.com.acpfg.misc.jemboss.settings.ProgramSetting;
/**
* Responsible for holding the results from the EMBOSS program invocation and distributing
* them amongst the various KNIME table cells as required to faithfully represent the results.
* Collaborates with the node model to build up a list of available columns in the input and output tables
*
* @author andrew.cassin
*
*/
public abstract class AbstractTableMapper {
private final List<DataColumnSpec> m_raw_cols = new ArrayList<DataColumnSpec>();
private final List<DataColumnSpec> m_formatted_cols = new ArrayList<DataColumnSpec>();
private final HashMap<DataColumnSpec,ProgramSetting> m_col2ps = new HashMap<DataColumnSpec,ProgramSetting>();
private final HashMap<String,DataColumnSpec> m_ps2col = new HashMap<String,DataColumnSpec>();
private final HashMap<String,Integer> m_ps2idx = new HashMap<String,Integer>();
// formatted data columns may provide many columns for just a single setting, so that results in List<...> everywhere
private final HashMap<DataColumnSpec,ProgramSetting> m_f_col2ps = new HashMap<DataColumnSpec,ProgramSetting>();
private final HashMap<String,List<DataColumnSpec>> m_f_ps2cols = new HashMap<String,List<DataColumnSpec>>();
private final HashMap<String,List<Integer>> m_f_ps2idx = new HashMap<String,List<Integer>>();
private DataCell[] m_raw_cells;
private DataCell[] m_formatted_cells;
public AbstractTableMapper() {
// always present - useful to use for join
DataColumnSpec rowid_col = new DataColumnSpecCreator("RowID", StringCell.TYPE).createSpec();
HashMap<String,String> ds_attrs = new HashMap<String,String>();
ds_attrs.put("name", "RowID");
ds_attrs.put("type", "RowID");
DummySetting ds = new DummySetting(ds_attrs);
List<DataColumnSpec> cols = new ArrayList<DataColumnSpec>();
cols.add(rowid_col);
addFormattedColumns(ds, cols);
m_raw_cols.add(new DataColumnSpecCreator("RowID", StringCell.TYPE).createSpec());
m_raw_cols.add(new DataColumnSpecCreator("Run status", IntCell.TYPE).createSpec());
m_raw_cols.add(new DataColumnSpecCreator("Runtime Output (if any)", StringCell.TYPE).createSpec()); // stdout
m_raw_cols.add(new DataColumnSpecCreator("Runtime Errors (includes description)", StringCell.TYPE).createSpec()); // stderr for each invocation ie. batch
m_raw_cells = null;
m_formatted_cells = null;
}
public void addRawColumn(ProgramSetting ps, DataColumnSpec colspec) {
assert(colspec != null && ps != null);
m_col2ps.put(colspec, ps);
// NB: these maps must use the name rather than the program setting as some settings
// create new instances (ie. class) of setting depending on their configuration
m_ps2col.put(ps.getName(),colspec);
m_ps2idx.put(ps.getName(), new Integer(m_raw_cols.size()));
m_raw_cols.add(colspec);
}
public void addFormattedColumns(ProgramSetting ps, List<DataColumnSpec> columns) {
assert(ps != null && columns != null);
for (DataColumnSpec col : columns) {
m_f_col2ps.put(col, ps);
m_formatted_cols.add(col);
}
m_f_ps2cols.put(ps.getName(), columns);
List<Integer> indices = new ArrayList<Integer>();
for (DataColumnSpec col : columns) {
indices.add(new Integer(m_formatted_cols.indexOf(col)));
}
m_f_ps2idx.put(ps.getName(), indices);
}
public void setRawOutputCell(ProgramSetting ps, DataCell dc) {
assert(ps != null && dc != null);
int idx = m_ps2idx.get(ps.getName()).intValue();
m_raw_cells[idx] = dc;
}
public DataTableSpec getRawTableSpec() {
DataTableSpec dt = new DataTableSpec(m_raw_cols.toArray(new DataColumnSpec[0]));
m_raw_cells = new DataCell[m_raw_cols.size()];
for (int i=0; i<m_raw_cells.length; i++) {
m_raw_cells[i] = DataType.getMissingCell();
}
return dt;
}
public DataTableSpec getFormattedTableSpec() {
DataTableSpec dt = new DataTableSpec(m_formatted_cols.toArray(new DataColumnSpec[0]));
m_formatted_cells = new DataCell[m_formatted_cols.size()];
return dt;
}
public void addRequiredCells(String row_id, int exit_status, String stdout, String stderr) {
m_raw_cells[0] = new StringCell(row_id);
m_raw_cells[1] = new IntCell(exit_status);
m_raw_cells[2] = new StringCell("<html><pre>"+stdout);
m_raw_cells[3] = new StringCell("<html><pre>"+stderr);
m_formatted_cells[0] = m_raw_cells[0];
}
protected DataCell[] getRawCells() {
for (int i=0; i<m_raw_cells.length; i++) {
if (m_raw_cells[i] == null)
m_raw_cells[i] = DataType.getMissingCell();
}
return m_raw_cells;
}
protected DataCell[] getFormattedCells() {
for (int i=0; i<m_formatted_cells.length; i++) {
if (m_formatted_cells[i] == null)
m_formatted_cells[i] = DataType.getMissingCell();
}
return m_formatted_cells;
}
/**
* Must emit the same number of cells as defined by <code>getRawTableSpec()</code>
* @return
*/
public abstract void emitRawRow();
public void setFormattedCells(HashMap<String, DataCell> cellmap) {
if (cellmap != null) {
for (DataColumnSpec s : m_f_col2ps.keySet()) {
if (cellmap.containsKey(s.getName())) {
int idx = m_formatted_cols.indexOf(s);
m_formatted_cells[idx] = cellmap.get(s.getName());
} else {
int idx = m_formatted_cols.indexOf(s);
m_formatted_cells[idx] = DataType.getMissingCell();
}
}
}
}
public abstract void emitFormattedRow();
/**
* Returns the string representation of the current rowID
* @return
*/
public abstract String getCurrentRow();
}