/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.prototype.queryresults;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import reportgen.utils.ReportException;
import reportgen.math.complex.conditions.MathExpressionConditions;
import reportgen.math.ResultColumn;
import reportgen.prototype.utils.RowCount;
import reportgen.math.agregate.agregate.AggregateFunction;
/**
* Конструктор результатов отчета
* Создается парсером и им же заполняется.
* Парсер последовательно добавляет по строке результата, а после заполнения
* вызывает <code>commit</commit>, в результате чего применяются условия
* сортировки, группировки и вторичной выборки.
* @author axe
*/
public class ResultsRowList {
private final List<ResultColumn> cols;
private final MathExpressionConditions stage2Conditions;
private final RowCount rowCount;
private List<ResultsRow> resultRows = new ArrayList<ResultsRow>();
private Set<Integer> groupByCols;
private List<AggregateFunction> colsFunc = new ArrayList<AggregateFunction>();
private boolean commited = false;
public ResultsRowList(List<ResultColumn> cols,
MathExpressionConditions stage2Conditions, RowCount rowCount) {
this.cols = cols;
this.stage2Conditions = stage2Conditions;
this.rowCount = rowCount;
for(ResultColumn col: cols) {
colsFunc.add(col.getFunction());
}
groupByCols = getGroupCols();
}
/**
* возвращает набор столбцов по которым осуществляется группировка
* @return
*/
private Set<Integer> getGroupCols() {
Set<Integer> groupCols = new HashSet<Integer>();
for(int i=0; i<cols.size(); i++) {
ResultColumn col = cols.get(i);
if(col.getFunction().equals(AggregateFunction.GROUP)) {
groupCols.add(i);
}
}
return groupCols;
}
public void appendRow(ResultsRow rr) throws ReportException {
if(commited) {
throw new ReportException("Results already commited");
}
if(groupByCols.size() == 0) {
resultRows.add(rr);
} else {
//группируем, если нужно
boolean merged = false;
for (ResultsRow resultsRow: resultRows) {
if(resultsRow.merge(rr, groupByCols, colsFunc)) {
merged = true;
break;
}
}
if(!merged) {
rr.initGroup(colsFunc);
resultRows.add(rr);
}
}
}
public void commit() throws ReportException {
if(commited) {
return;
} else {
commited = true;
}
//нормализация после группировки
if(groupByCols.size() > 0) {
resultRows = normalize(resultRows, colsFunc);
}
//проверка расширенных условий
resultRows = checkConditions(resultRows);
//sorting
resultRows = sort(cols, resultRows);
if(rowCount != null) {
resultRows = cropToRowCount(resultRows, rowCount);
}
System.out.println("<<<<<<<<<< CONTINUE 2 ANALYZE RESULTS >>>>>>>>>>>>>>");
}
/**
*
* @return
* @throws reportgen.exception.ReportException
*/
public QueryResults getResults() throws ReportException {
if(!commited) {
commit();
}
return new QueryResults(cols.size(), resultRows);
}
/**
*
* @return
* @throws reportgen.exception.ReportException
*/
public List<ResultsRow> getResultRows() throws ReportException {
if(!commited) {
commit();
}
return resultRows;
}
/**
* нормализиция после группировки
* @throws reportgen.ren.exception.ReportException
*/
private List<ResultsRow> normalize(List<ResultsRow> rows, List<AggregateFunction> colsFunc) throws ReportException {
for(ResultsRow row: rows) {
row.normalize(colsFunc);
}
return rows;
}
/**
* проверка расширенных условий
* @param rows
* @return
* @throws reportgen.ren.exception.ReportException
*/
private List<ResultsRow> checkConditions(List<ResultsRow> rows) throws ReportException {
if(stage2Conditions == null) {
return rows;
}
List<ResultsRow> res = new ArrayList<ResultsRow>();
for (ResultsRow resultsRow : rows) {
Map<ResultColumn, Object> model = new HashMap<ResultColumn, Object>();
for(int i=0; i< cols.size(); i++) {
model.put(cols.get(i), resultsRow.getValue(i));
}
if(stage2Conditions.getValue(model).equals(true)) {
res.add(resultsRow);
}
}
return res;
}
/**
* отбрасывание строк
* @throws reportgen.ren.exception.ReportException
*/
private static List<ResultsRow> cropToRowCount(List<ResultsRow> rows, RowCount rowCount)
throws ReportException {
if(rowCount.getMinimum() > rows.size()) {
throw new ReportException("Запрос возвратил " + rows.size()
+ " строк, а должен был как минимум" + rowCount.getMinimum());
}
List<ResultsRow> resRows = rows;
if(rowCount.getMaximum() < rows.size()) {
resRows = new LinkedList<ResultsRow>();
for(int i=0; i<rowCount.getMaximum(); i++) {
resRows.add(rows.get(i));
}
}
return resRows;
}
/**
*
* @param rows
* @return
* @throws reportgen.exception.ReportException
*/
private static List<ResultsRow> sort(List<ResultColumn> cols, List<ResultsRow> rows) throws ReportException {
//column index -> priority
final ArrayList<ColumnPriority> orderByCols = new ArrayList<ColumnPriority>();
for(int i=0; i<cols.size(); i++) {
ResultColumn col = cols.get(i);
if(col.getOrderPriority() != 0) {
orderByCols.add(new ColumnPriority(i, col.getOrderPriority()));
}
}
Collections.sort(orderByCols);
Collections.sort(rows, new Comparator<ResultsRow>() {
@Override
public int compare(ResultsRow r1, ResultsRow r2) {
for (ColumnPriority p: orderByCols) {
Object v1 = r1.getValue(p.colIndex);
Object v2 = r2.getValue(p.colIndex);
if(v1 == null && v2 == null) {
continue;
} else if(v1 == null) {
return -1;
} else if(v2 == null) {
return 1;
} else if(v1.getClass().equals(v1.getClass())) {
int res = compareObj(v1, v2);
if(res != 0) {
if(p.priority < 0) {
return -res;
} else {
return res;
}
}
}
}
return 0;
}
private int compareObj(Object v1, Object v2) {
int res = 0;
if(v1 instanceof Long) {
Long d1 = (Long) v1;
Long d2 = (Long) v2;
res = d1.compareTo(d2);
} else if(v1 instanceof Double) {
Double d1 = (Double) v1;
Double d2 = (Double) v2;
res = d1.compareTo(d2);
} else if(v1 instanceof Date) {
Date d1 = (Date) v1;
Date d2 = (Date) v2;
res = d1.compareTo(d2);
} else if(v1 instanceof Boolean) {
Boolean d1 = (Boolean) v1;
Boolean d2 = (Boolean) v2;
res = d1.compareTo(d2);
} else if(v1 instanceof String) {
String d1 = (String) v1;
String d2 = (String) v2;
res = d1.compareTo(d2);
}
return res;
}
});
return rows;
}
private static class ColumnPriority implements Comparable<ColumnPriority> {
int colIndex;
int priority;
public ColumnPriority(int colIndex, int priority) {
this.colIndex = colIndex;
this.priority = priority;
}
@Override
public int compareTo(ColumnPriority o) {
return Math.abs(priority) - Math.abs(o.priority);
}
}
}