/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.formatter.extended;
import java.io.FilterOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import reportgen.formatter.extended.range.RangeProcessor;
import reportgen.formatter.extended.cell.CellProcessor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import reportgen.utils.ReportException;
import reportgen.formatter.SupportHTML;
import reportgen.formatter.extended.order.RangeSorter;
import reportgen.ren.report.extendedformat.table.TableFormat;
/**
* Табличный процессор.
* Получает ссылку на формат таблицы.
* Из нее создает диапазонные процессоры RProcessor для каждого
* диапазона расширенного форматирования.
* При добавлении данных, проверяет на условие вхождения модели данных в таблицу,
* проверяет какие диапазонные процессоры соответствуют модели данных
* и если такие находятся, передает данные им
* @author axe
*/
public class TableProcessor implements SupportHTML {
private final TableFormat range;
private final List<RangeProcessor> rows;
private final List<RangeProcessor> cols;
private final HashMap<RangeProcessor, HashMap<RangeProcessor, CellProcessor>> col2cell
= new HashMap<RangeProcessor, HashMap<RangeProcessor, CellProcessor>>();
public TableProcessor(TableFormat table) throws ReportException {
range = table;
rows = Factory.getProcessors(range.getRows(), null);
cols = Factory.getProcessors(range.getCols(), null);
}
public List<RangeProcessor> getCols() {
return cols;
}
public TableFormat getRange() {
return range;
}
public List<RangeProcessor> getRows() {
return rows;
}
/**
* проверяет модель данных на условие вхождения в таблицу
* @param model
* @return
* @throws reportgen.exception.ReportException
*/
protected boolean isFit(Map model) throws ReportException {
if(range.getCriteria().getValue(model).equals(true)) {
return true;
}
return false;
}
/**
* Функция добавления модели данных в таблицу
* Строка должна подойти как минимум в 1 строку и 1 столбец, иначе
* она отбрасывается
* @param models
* @return
* @throws reportgen.exception.ReportException
*/
public boolean addRows(List<Map> models) throws ReportException {
boolean fit = false;
Set<RangeProcessor> rowset = new HashSet<RangeProcessor>();
Set<RangeProcessor> colset = new HashSet<RangeProcessor>();
Set<RangeProcessor> fullrowset = new HashSet<RangeProcessor>();
Set<RangeProcessor> fullcolset = new HashSet<RangeProcessor>();
for(Map model: models) {
if(!isFit(model)) {
continue;
}
rowset.clear();
colset.clear();
fullrowset.clear();
fullcolset.clear();
//rows
for(RangeProcessor row: rows) {
row.buildFitProcessors(model, rowset, fullrowset);
}
if(rowset.size() == 0) {
continue;
}
//cols
for(RangeProcessor col: cols) {
col.buildFitProcessors(model, colset, fullcolset);
}
if(colset.size() == 0) {
continue;
}
for(RangeProcessor r: rowset) {
r.setAttachedModel(model);
//prepare context row model
Map workModel = makeCompoundModel(model, r.getModel());
for(RangeProcessor c: colset) {
c.setAttachedModel(model);
//prepare cell model
Map cellModel = makeCompoundModel(workModel, c.getModel());
CellProcessor cell = createCell(c, r);
cell.addRow(cellModel);
}
}
}
makeAfterClean();
ensureCellCreated();
return fit;
}
/**
*
*/
private void ensureCellCreated() throws ReportException {
List<RangeProcessor> flatRows = new ArrayList<RangeProcessor>();
for (RangeProcessor r : rows) {
r.getFlat(flatRows);
}
List<RangeProcessor> flatCols = new ArrayList<RangeProcessor>();
for (RangeProcessor c : cols) {
c.getFlat(flatCols);
}
for (RangeProcessor r : flatRows) {
for (RangeProcessor c : flatCols) {
createCell(c, r);
}
}
}
private void makeAfterClean() {
makeAfterClean(rows);
makeAfterClean(cols);
}
private void makeAfterClean(List<RangeProcessor> lst) {
Iterator<RangeProcessor>rangeIt = lst.iterator();
while(rangeIt.hasNext()) {
RangeProcessor row = rangeIt.next();
if(!row.makeAfterClean()) {
rangeIt.remove();
}
}
RangeSorter.sort(lst);
}
/**
* сливает 2 модели данных в одну
* @param main
* @param extra
* @return
*/
private Map makeCompoundModel(Map main, Map extra) {
Map res = main;
if(extra != null) {
res = new HashMap(main);
res.putAll(extra);
}
return res;
}
@Override
public void toHTML(PrintStream stream) throws ReportException {
HtmlExporter.getInstance(this).toHTML(stream);
}
public CellProcessor getCell(RangeProcessor col, RangeProcessor row) {
HashMap<RangeProcessor, CellProcessor> selRow = col2cell.get(row);
CellProcessor cell = selRow.get(col);
return cell;
}
private CellProcessor createCell(RangeProcessor col, RangeProcessor row)
throws ReportException {
HashMap<RangeProcessor, CellProcessor> selRow = col2cell.get(row);
if(selRow == null) {
selRow = new HashMap<RangeProcessor, CellProcessor>();
col2cell.put(row, selRow);
}
CellProcessor cell = selRow.get(col);
if(cell == null) {
cell = new CellProcessor(range.getCell(col.getRange(), row.getRange()));
selRow.put(col, cell);
}
return cell;
}
}