/**
* AnalyzerBeans
* Copyright (C) 2014 Neopost - Customer Information Management
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.eobjects.analyzer.result;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeSet;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.eobjects.analyzer.beans.api.Description;
import org.eobjects.analyzer.data.InputColumn;
import org.eobjects.analyzer.data.InputRow;
import org.eobjects.analyzer.storage.InMemoryRowAnnotationFactory;
import org.eobjects.analyzer.storage.RowAnnotation;
import org.eobjects.analyzer.storage.RowAnnotationFactory;
import org.apache.metamodel.util.Ref;
import org.apache.metamodel.util.SerializableRef;
/**
* Represents a typical "drill to detail" result consisting of a set of
* annotated rows.
*
* Furthermore, if classes inherit from {@link AnnotatedRowsResult}, they can be
* annotated with the {@link Description} annotation to provide a labeling
* description, used often in rendering.
*
*
*/
public class AnnotatedRowsResult implements AnalyzerResult, TableModelResult {
private static final long serialVersionUID = 1L;
private final Ref<RowAnnotationFactory> _annotationFactoryRef;
private final InputColumn<?>[] _highlightedColumns;
private final RowAnnotation _annotation;
private transient InputRow[] _rows;
private transient TableModel _tableModel;
private transient List<InputColumn<?>> _inputColumns;
public AnnotatedRowsResult(RowAnnotation annotation, RowAnnotationFactory annotationFactory,
InputColumn<?>... highlightedColumns) {
_annotationFactoryRef = new SerializableRef<RowAnnotationFactory>(annotationFactory);
_annotation = annotation;
_highlightedColumns = highlightedColumns;
}
public List<InputColumn<?>> getInputColumns() {
if (_inputColumns == null) {
InputRow[] rows = getRows();
if (rows.length > 0) {
InputRow firstRow = rows[0];
_inputColumns = firstRow.getInputColumns();
} else {
_inputColumns = new ArrayList<InputColumn<?>>(0);
}
}
return _inputColumns;
}
public InputRow[] getRows() {
if (_rows == null) {
RowAnnotationFactory annotationFactory = _annotationFactoryRef.get();
if (annotationFactory != null) {
_rows = annotationFactory.getRows(getAnnotation());
}
if (_rows == null) {
_rows = new InputRow[0];
}
}
return _rows;
}
/**
* Creates a table model containing only distinct values from a particular
* input column, and the counts of those distinct values. Note that the
* counts may only be the count from the data that is available in the
* annotation row storage, which may just be a preview/subset of the actual
* data.
*
* @param inputColumnOfInterest
* @return
*/
public TableModel toDistinctValuesTableModel(InputColumn<?> inputColumnOfInterest) {
final Map<Object, Integer> valueCounts;
final RowAnnotationFactory annotationFactory = _annotationFactoryRef.get();
if (annotationFactory == null) {
valueCounts = Collections.emptyMap();
} else {
valueCounts = annotationFactory.getValueCounts(getAnnotation(), inputColumnOfInterest);
}
DefaultTableModel tableModel = new DefaultTableModel(new String[] { inputColumnOfInterest.getName(),
"Count in dataset" }, valueCounts.size());
// sort the set
TreeSet<Entry<Object, Integer>> set = new TreeSet<Entry<Object, Integer>>(
new Comparator<Entry<Object, Integer>>() {
@Override
public int compare(Entry<Object, Integer> o1, Entry<Object, Integer> o2) {
int countDiff = o2.getValue().intValue() - o1.getValue().intValue();
if (countDiff == 0) {
return -1;
}
return countDiff;
}
});
set.addAll(valueCounts.entrySet());
int i = 0;
for (Entry<Object, Integer> entry : set) {
tableModel.setValueAt(entry.getKey(), i, 0);
tableModel.setValueAt(entry.getValue(), i, 1);
i++;
}
return tableModel;
}
/**
*
* @param maxRows
* @return
*/
public TableModel toTableModel(int maxRows) {
if (maxRows < 0) {
maxRows = Integer.MAX_VALUE;
}
final InputRow[] rows = getRows();
final List<InputColumn<?>> inputColumns = getInputColumns();
final String[] headers = new String[inputColumns.size()];
for (int i = 0; i < headers.length; i++) {
headers[i] = inputColumns.get(i).getName();
}
final int actualRows = Math.min(maxRows, rows.length);
final TableModel tableModel = new DefaultTableModel(headers, actualRows);
int row = 0;
for (InputRow inputRow : rows) {
if (actualRows == row) {
break;
}
for (int i = 0; i < inputColumns.size(); i++) {
InputColumn<?> inputColumn = inputColumns.get(i);
Object value = inputRow.getValue(inputColumn);
tableModel.setValueAt(value, row, i);
}
row++;
}
return tableModel;
}
@Override
public TableModel toTableModel() {
if (_tableModel == null) {
_tableModel = toTableModel(-1);
}
return _tableModel;
}
public InputColumn<?>[] getHighlightedColumns() {
return _highlightedColumns;
}
public int getColumnIndex(InputColumn<?> col) {
List<InputColumn<?>> inputColumns = getInputColumns();
int i = 0;
for (InputColumn<?> inputColumn : inputColumns) {
if (col.equals(inputColumn)) {
return i;
}
i++;
}
return -1;
}
public RowAnnotation getAnnotation() {
if (_annotation == null) {
// only occurs for deserialized instances
return new InMemoryRowAnnotationFactory().createAnnotation();
}
return _annotation;
}
public int getAnnotatedRowCount() {
return getAnnotation().getRowCount();
}
}