/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package reportgen.ren.executer;
import java.util.ArrayList;
import java.util.List;
import org.jdom.Element;
import reportgen.utils.SupportXMLRootImpl;
import reportgen.prototype.queryresults.QueryResults;
import reportgen.prototype.queryresults.ResultsRow;
import reportgen.prototype.context.Context;
import reportgen.ren.loader.SubQueryLoaderResult;
import reportgen.ren.report.ReportQuery;
import reportgen.utils.ReportException;
import reportgen.prototype.utils.RowCount;
import reportgen.ren.report.column.ReportResultColumn;
import reportgen.ren.report.userinput.UserInputSelect;
import reportgen.prototype.utils.ItemSelectorEditable;
import reportgen.utils.Atom;
import reportgen.utils.SupportXMLRoot;
import reportgen.utils.XML;
/**
*
* @author axe
*/
public class QueryExecuterSub implements SupportXMLRoot {
public static final String TAGNAME = "subreport";
private static final String ATTR_QUERYID = "id";
private static final String ATTR_TITLE = "selecttitle";
private static final String ATTR_DESCRIPTION = "selectdescription";
private static final String ATTR_SELECTCOLUMN = "col";
private static final String ATTR_CONSTANT = "const";
private static final String ATTR_CANBEOMMITED = "canBeOmitted";
private static final int IGNORE_ROW = -1;
/**
* Название выбора, которую нужно отобразить пользователю при выборе строк.
* (Выбирается пользователем при вставке подотчета в отчет)
*/
private String selectTitle;
/**
* Описание выбора, которую нужно отобразить пользователю при выборе строк.
* (Выбирается пользователем при вставке подотчета в отчет)
*/
private String selectDescription;
/**
* Индекс колонки в результатах отчета, которую нужно отобразить
* пользователю при выборе строк. (Выбирается пользователем при вставке
* подотчета в отчет)
*/
private int selectColumn;
/**
* РЕЖИМ СТРОК ВЫБОРКИ
* Количество строк, которых нужно выбрать пользователю.
*/
private RowCount rowCount;
/**
* Отчет будет выполнен при построении родительского отчета
* и результаты будут сохранены
*/
private boolean constant = false;
private boolean canBeOmitted = false;
private boolean isOmitted = false;
/**
* Должен ли пользователь выбрать результат отчета
*/
private boolean needUserActivity = true;
/**
* Результаты запроса. Назначаются после выполнения ядра запроса и парсинга
*/
private QueryResults queryResults;
/**
* Результаты запроса. Назначаются в момент составления отчета
*/
private QueryResults defaultResults;
/*
* Строки, выбранные пользователем. Инициализируется при назначении результатов
* отчета, при этом величина списка соответствует необходимому количеству строк
* кторые должен выбрать пользователь. (в некоторых случаях пользователь может
* выбрать иное количество строк)
*/
private ArrayList<Integer> selectedRows;
private final Atom atom;
private final QueryExecuter report;
/**
* @param id табельный номер отчета
* @param report ядро отчета
* @param selectTitle название отчета
* @param selectDescription описание отчета
* @param selectColumn индекс колонки при выборе
* @param activeRows активные строки отчета
*/
public QueryExecuterSub(int id, ReportQuery report, String title, String description,
String selectTitle, String selectDescription, int selectColumn, RowCount activeRows) {
this.report = new QueryExecuter(id, report, title, description);
this.selectTitle = selectTitle;
this.selectDescription = selectDescription;
this.selectColumn = selectColumn;
this.rowCount = activeRows;
this.atom = new Atom();
}
/**
*
* @param element
* @param sl
* @return
* @throws reportgen.ren.exception.ReportException
*/
public QueryExecuterSub(Element element, Context context) throws ReportException {
assert element.getName().equals(TAGNAME);
int reportId = XML.getIntAttribute(element, ATTR_QUERYID);
SubQueryLoaderResult rpt = context.getQueryLoader().loadSubReport(reportId);
report = new QueryExecuter(reportId, rpt.report, rpt.title, rpt.description);
atom = new Atom(element, context);
rowCount = new RowCount(element);
selectTitle = XML.getStringAttribute(element, ATTR_TITLE);
selectDescription = XML.getStringAttribute(element, ATTR_DESCRIPTION, "", false);
String selectCol = SupportXMLRootImpl.getStringAttribute(element, ATTR_SELECTCOLUMN);
selectColumn = -1;
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
for(int i=0; i<cols.size(); i++) {
if(cols.get(i).getTitle().equals(selectCol)) {
selectColumn = i;
}
}
if(selectColumn == -1) {
throw new ReportException("Неизвестная колонка выбора: " + selectCol);
}
constant = XML.getBoolAttribute(element, ATTR_CONSTANT, false, false);
canBeOmitted = XML.getBoolAttribute(element, ATTR_CANBEOMMITED, false, false);
Element resultsEl = element.getChild(QueryResults.TAG);
if(resultsEl != null) {
setDefaultResults(new QueryResults(resultsEl));
} else if(constant) {
throw new ReportException("Для подотчета '" + selectTitle + "' указано использовать"
+ " предварительно загруженные результаты, но они отсутствуют");
}
}
/**
*
* @return
* @throws reportgen.ren.exception.ReportException
*/
@Override
public Element toXML() {
Element element = new Element(TAGNAME);
atom.toXML(element);
element.setAttribute(ATTR_QUERYID, new Integer(report.getId()).toString());
element.setAttribute(ATTR_TITLE, selectTitle);
if(selectDescription.length() > 0) {
element.setAttribute(ATTR_DESCRIPTION, selectDescription);
}
element.setAttribute(ATTR_SELECTCOLUMN, getColTitle(selectColumn));
if(constant) {
element.setAttribute(ATTR_CONSTANT, new Boolean(constant).toString());
}
if(canBeOmitted) {
element.setAttribute(ATTR_CANBEOMMITED, new Boolean(canBeOmitted).toString());
}
rowCount.toXML(element);
if(defaultResults != null) {
element.addContent(defaultResults.toXML());
}
return element;
}
public QueryExecuter getReport() {
return report;
}
public int getReportId() {
return report.getId();
}
public String getReportTitle() {
return report.getTitle();
}
public Atom getAtom() {
return atom;
}
public boolean isCanBeOmitted() {
return canBeOmitted;
}
public void setCanBeOmitted(boolean canBeOmitted) {
this.canBeOmitted = canBeOmitted;
}
public boolean isOmitted() {
return isOmitted;
}
/**
*
*/
public void clearDefaultResults() {
defaultResults = null;
constant = false;
}
/**
*
* @param count
* @return
*/
private static ArrayList<Integer> buildInitialSelection(int count) {
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0; i<count; i++) {
list.add(i);
}
return list;
}
/**
* @return the canBeSelected
*/
public RowCount getActiveRows() {
return rowCount;
}
/**
* Назначается режим строк выборки, удаляет дефолтовые результаты.
* @param canBeSelected the canBeSelected to set
*/
public void setActiveRows(RowCount activeRows) {
clearDefaultResults();
this.rowCount = activeRows;
}
/**
* @return the selectTitle
*/
public String getSelectTitle() {
return selectTitle;
}
/**
* @param selectTitle the selectTitle to set
*/
public void setSelectTitle(String selectTitle) {
this.selectTitle = selectTitle;
}
/**
* @return the selectDescription
*/
public String getSelectDescription() {
return selectDescription;
}
/**
* @param selectDescription the selectDescription to set
*/
public void setSelectDescription(String selectDescription) {
this.selectDescription = selectDescription;
}
/**
* @return the selectColumn
*/
public int getSelectColumn() {
return selectColumn;
}
public void setSelectColumn(int index) {
this.selectColumn = index;
}
@Override
public String toString() {
return report.getTitle() + "(" + getSelectTitle() + ")";
}
public boolean isConstant() {
return constant;
}
public void setConstant(boolean constant) throws ReportException {
if(constant && defaultResults == null) {
throw new ReportException("Не заданы дефолтовые значения");
}
this.constant = constant;
}
/**
*
* @param index
* @return
* @throws reportgen.ren.exception.ReportException
*/
public Object getDefaultValue(int col) throws ReportException {
return getDefaultColValue(col, IGNORE_ROW);
}
/**
* @param index
* @return
* @throws reportgen.ren.exception.ReportException
*/
private Object getDefaultColValue(int col, int row) throws ReportException {
if(defaultResults == null || defaultResults.getRowCount() == 0) {
throw new ReportException("Отсутствуют результаты выборки по-умолчанию");
}
//only specified row
if(row != IGNORE_ROW ) {
return defaultResults.getRow(row).getValue(col);
}
if(getActiveRows().isSingle()) {
return defaultResults.getRow(0).getValue(col);
}
List set = new ArrayList();
for(int i=0; i<defaultResults.getRowCount(); i++) {
ResultsRow iRow = defaultResults.getRow(i);
set.add(iRow.getValue(col));
}
return set;
}
/**
* Назначение дефолтовых результатов для отчета.
* Контролируется соответствие режиму строк подотчета
* (назначаемому в панели списка подотчетов)
* данные готовы для использования в отчете и поэтому должны соответствовать
* критериям заданным в подотчете (количеству строк)
* @param results
* @param selectedRows
* @throws reportgen.ren.exception.ReportException
*/
public void setDefaultResults(QueryResults results)
throws ReportException {
assert results != null;
if(results.getRowCount() == 0) {
throw new ReportException("Нельзя назначать пустые результаты в качестве "
+ "дефолтного значения подотчета '" + report.getTitle() + "'");
}
//дефолтные результаты должны соответствовать количеству строк подотчета
if (rowCount.getMinimum() > results.getRowCount()) {
throw new ReportException("Должно быть выбрано, не менее " + rowCount.getMinimum() + " строк(и)");
}
if (rowCount.getMaximum() < results.getRowCount()) {
throw new ReportException("Должно быть выбрано, не более " + rowCount.getMaximum() + " строк(и)");
}
//назначаем результаты и отмечаем их как выброанные
defaultResults = results;
needUserActivity = false;
}
/**
* Назначение результатов для отчета.
* Проверка того, сколько строк вернул подотчет проверяется самим подотчетом
* в момент парсинга результатов.
* @param results
*/
public void setResults(QueryResults results) throws ReportException {
if(results.getRowCount() < rowCount.getMinimum()) {
throw new ReportException(
"Подотчет '" + report.getTitle() + "' вернул "+ results.getRowCount() + " строк(и),"
+ " а в условиях его использования предполагается выбрать "
+ " не менее " + rowCount.getMinimum() + "строк(и)");
}
this.queryResults = results;
if(results.getRowCount() == 1 || rowCount.isAny()) {
selectedRows = buildInitialSelection(results.getRowCount());
needUserActivity = false;
} else {
needUserActivity = true;
if(defaultResults == null) {
selectedRows = null;
} else {
//попробуем выбрать дефолтные строки
selectedRows = new ArrayList<Integer>();
for(int i=0; i<defaultResults.getRowCount(); i++) {
Object iDefaultValue = defaultResults.getRow(i).getValue(selectColumn);
assert iDefaultValue != null : "iDefaultValue == null";
for(int j=0; j<queryResults.getRowCount(); j++) {
Object iRowValue = queryResults.getRow(j).getValue(selectColumn);
if(iRowValue != null
&& iRowValue.equals(iDefaultValue)) {
selectedRows.add(j);
break;
}
}
}
if(selectedRows.size() == 0) {
selectedRows = null;
}
}
}
}
/**
*
*/
public void clearResults() {
this.queryResults = null;
//очистка выбора пользователя
selectedRows = null;
needUserActivity = true;
}
/**
* Возвращает объект - опция для выбора клиентом из списка.
* Список - результат выполнения отчета.
* @return null if report is constant and default values is present
* @throws reportgen.ren.ReportException
*/
UserInputSelect getResultInputValue() throws ReportException {
if(isDefaultConstant() || !needUserActivity) {
return null;
}
ArrayList<Object> options = new ArrayList<Object>();
for(int i=0; i<queryResults.getRowCount(); i++) {
ResultsRow row = queryResults.getRow(i);
options.add(row.getValue(selectColumn));
}
return new UserInputSelect(new Integer(report.getId()).toString(),
selectTitle, selectDescription, selectedRows, options, rowCount, canBeOmitted);
}
/**
* После того как пользователь выбрал нужные опции из списка,
* этой функцией они обновляются в отчете
* Контролируется соответствие режиму строк отчета
* @param ui
* @throws reportgen.ren.ReportException
*/
void setResultUserInput(UserInputSelect ui) throws ReportException {
ArrayList<Integer> selected = ui.getSelected();
if(selected.size() == 0) {
if(!canBeOmitted) {
throw new ReportException("Пользователь не сделал выбор");
}
isOmitted = true;
} else {
for(Integer index: selected) {
if(index < 0 || index >= queryResults.getRowCount()) {
throw new ReportException("Пользователь сделал некорректный выбор");
}
}
if(selected.size() > rowCount.getMaximum()) {
throw new ReportException("Пользователь выбрал " + selected.size()
+ " строк, а должен был выбрать не более" + rowCount.getMaximum());
}
if(selected.size() < rowCount.getMinimum()) {
throw new ReportException("Пользователь выбрал " + selected.size()
+ " строк, а должен был не менее " + rowCount.getMinimum());
}
selectedRows = selected;
isOmitted = false;
}
needUserActivity = false;
}
/**
*
* @return
*/
public boolean isResultsIsSet() {
return queryResults != null;
}
public String getColTitle(int index) {
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
return cols.get(index).getTitle();
}
public String getColDesc(int index) {
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
return cols.get(index).getDescription();
}
/**
* Возвращает класс столбца результата
* @param index индекс столбца
* @param forSingleRow true - рассматривать отчет построчно,
* false -если рассматривать отчет как единое целое,
* @return класс
* @throws reportgen.exception.ReportException
*/
public Class getColCls(int index, boolean forSingleRow) throws ReportException {
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
Class cls = cols.get(index).getCls();
if(forSingleRow) {
return cls;
}
if(rowCount.isSingle()) {
return cls;
}
//неизвестное количество строк
if(cls.equals(Long.class)) {
List<Long> set = new ArrayList<Long>();
return set.getClass();
} else if(cls.equals(String.class)) {
List<String> set = new ArrayList<String>();
return set.getClass();
}
return List.class;
}
/**
*
* @return
* @throws reportgen.exception.ReportException
*/
public int getResultsRowCount() throws ReportException {
if(isDefaultConstant()) {
return defaultResults.getRowCount();
}
return queryResults.getRowCount();
}
public int getColumnCount() {
return report.getQuery().getColumns().size();
}
public Object getColValue(int col) throws ReportException {
if(isDefaultConstant()) {
return getDefaultColValue(col, IGNORE_ROW);
}
return getResultsColValue(col, IGNORE_ROW);
}
/**
*
* @param index
* @return
* @throws reportgen.ren.exception.ReportException
*/
public Object getColValue(int col, int row) throws ReportException {
if(isDefaultConstant()) {
return getDefaultColValue(col, row);
}
return getResultsColValue(col, row);
}
/**
*
* @param results
* @param index
* @return
* @throws reportgen.ren.exception.ReportException
*/
private Object getResultsColValue(int col, int row) throws ReportException {
//ODZ
if(isOmitted) {
throw new ReportException("Пользователь не сделал свой выбор");
}
if(selectedRows == null || queryResults == null) {
throw new ReportException("Подотчет '" + getSelectTitle
()+ "(" + report.getTitle() +")' не выполнен, "
+ "или пользователь еще сделал свой выбор");
}
//only specified row
if(row != IGNORE_ROW ) {
return queryResults.getRow(selectedRows.get(row)).getValue(col);
}
//only single row
if(getActiveRows().isSingle()) {
return queryResults.getRow(selectedRows.get(0)).getValue(col);
}
//several rows
List set = new ArrayList();
for(int i=0; i<selectedRows.size(); i++) {
ResultsRow iRow = queryResults.getRow(selectedRows.get(i));
set.add(iRow.getValue(col));
}
return set;
}
/**
/**
Возвращает список доступных колонок подотчета
* @return
*/
public List<SubReportColumn> getAvailiableColumns() {
List<SubReportColumn> lst = new ArrayList<SubReportColumn>();
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
for(int i=0; i<cols.size(); i++) {
lst.add(new SubReportColumn(this, i));
}
return lst;
}
/**
* Возвращает индекс колонки по имени
* @param column
* @return
*/
public int getColumnIndex(String column) throws ReportException {
ItemSelectorEditable<ReportResultColumn> cols = report.getQuery().getColumns();
for(int i=0; i<cols.size(); i++) {
if(cols.get(i).getTitle().equals(column)) {
return i;
}
}
throw new ReportException("Колонка " + column + " в отчете "
+ report.getTitle() + " не найдена!");
}
private boolean isDefaultConstant() {
return constant && defaultResults != null;
}
public boolean isDefaultValuesPresent() {
return defaultResults != null;
}
}