gernotbelger@9145: /* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde gernotbelger@9145: * Software engineering by gernotbelger@9145: * Björnsen Beratende Ingenieure GmbH gernotbelger@9145: * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt gernotbelger@9145: * gernotbelger@9145: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@9145: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@9145: * documentation coming with Dive4Elements River for details. gernotbelger@9145: */ gernotbelger@9145: package org.dive4elements.river.artifacts.sinfo.flood_duration; gernotbelger@9145: gernotbelger@9205: import java.text.NumberFormat; gernotbelger@9150: import java.util.ArrayList; gernotbelger@9145: import java.util.Collection; mschaefer@9202: import java.util.Collections; mschaefer@9202: import java.util.List; gernotbelger@9145: gernotbelger@9265: import org.apache.commons.collections.Predicate; mschaefer@9176: import org.dive4elements.river.artifacts.common.AbstractCalculationExportableResult; gernotbelger@9205: import org.dive4elements.river.artifacts.common.AbstractExportContext; gernotbelger@9150: import org.dive4elements.river.artifacts.common.ExportContextCSV; gernotbelger@9195: import org.dive4elements.river.artifacts.common.ExportContextPDF; gernotbelger@9150: import org.dive4elements.river.artifacts.common.GeneralResultType; mschaefer@9202: import org.dive4elements.river.artifacts.common.IResultType; gernotbelger@9150: import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource; gernotbelger@9145: import org.dive4elements.river.artifacts.common.ResultRow; gernotbelger@9150: import org.dive4elements.river.artifacts.sinfo.common.SInfoResultType; gernotbelger@9150: import org.dive4elements.river.artifacts.sinfo.util.RiverInfo; mschaefer@9229: import org.dive4elements.river.model.Attribute.AttributeKey; gernotbelger@9145: mschaefer@9202: import gnu.trove.TDoubleArrayList; mschaefer@9202: gernotbelger@9145: /** mschaefer@9176: * Contains the result of a {@link FloodDurationCalculation}. gernotbelger@9145: * gernotbelger@9145: * @author Gernot Belger gernotbelger@9145: */ mschaefer@9202: public final class FloodDurationCalculationResult extends AbstractCalculationExportableResult { gernotbelger@9145: gernotbelger@9265: private final static class RiversidePredicate implements Predicate { gernotbelger@9265: gernotbelger@9265: private final AttributeKey riverside; gernotbelger@9265: gernotbelger@9265: public RiversidePredicate(final AttributeKey riverside) { gernotbelger@9265: this.riverside = riverside; gernotbelger@9265: } gernotbelger@9265: gernotbelger@9265: @Override gernotbelger@9265: public boolean evaluate(final Object object) { gernotbelger@9265: final ResultRow row = (ResultRow) object; gernotbelger@9265: gernotbelger@9265: return row.getValue(SInfoResultType.riverside) == this.riverside; gernotbelger@9265: } gernotbelger@9265: } gernotbelger@9265: gernotbelger@9585: private final static class HasInfrastructurePredicate implements Predicate { gernotbelger@9585: gernotbelger@9585: @Override gernotbelger@9585: public boolean evaluate(final Object object) { gernotbelger@9585: final ResultRow row = (ResultRow) object; gernotbelger@9585: gernotbelger@9585: return row.getValue(SInfoResultType.riverside) != null; gernotbelger@9585: } gernotbelger@9585: } gernotbelger@9585: gernotbelger@9145: private static final long serialVersionUID = 1L; gernotbelger@9150: gernotbelger@9492: private final boolean isUseWspl; gernotbelger@9492: mschaefer@9285: private final String[] waterlevelLabels; mschaefer@9176: gernotbelger@9205: private final int maxWaterlevelPdf = 3; gernotbelger@9205: gernotbelger@9208: public interface ValueGetter { gernotbelger@9215: double getValue(DurationWaterlevel waterlevel); gernotbelger@9208: } gernotbelger@9208: gernotbelger@9205: private enum ExportMode { gernotbelger@9205: pdf, csv gernotbelger@9205: } mschaefer@9202: gernotbelger@9492: public FloodDurationCalculationResult(final String label, final String[] mainvalueLabels, final Collection rows, final boolean isUseWspl) { mschaefer@9176: super(label, rows); mschaefer@9285: this.waterlevelLabels = mainvalueLabels; gernotbelger@9492: this.isUseWspl = isUseWspl; mschaefer@9202: } mschaefer@9202: mschaefer@9202: /** mschaefer@9202: * Collection of the result rows containing only the rows describing an infrastructure mschaefer@9202: */ gernotbelger@9265: // FIXME: bad to override, instead make new method 'getInfrastructureRows' or similar? mschaefer@9202: @Override mschaefer@9202: public Collection getRows() { gernotbelger@9265: gernotbelger@9265: final Collection rows = super.getRows(); gernotbelger@9265: mschaefer@9202: final List infrasOnlyRows = new ArrayList<>(); gernotbelger@9265: for (final ResultRow row : rows) { mschaefer@9202: if (row.getValue(SInfoResultType.infrastructuretype) != null) mschaefer@9202: infrasOnlyRows.add(row); gernotbelger@9265: } mschaefer@9202: return Collections.unmodifiableCollection(infrasOnlyRows); mschaefer@9202: } mschaefer@9202: mschaefer@9298: /** mschaefer@9298: * Collection of all result rows mschaefer@9298: */ mschaefer@9298: public Collection getAllRows() { mschaefer@9298: mschaefer@9298: return super.getRows(); mschaefer@9298: } mschaefer@9298: mschaefer@9176: @Override gernotbelger@9195: protected void writeCSVResultMetadata(final ExportContextCSV exportContextCSV) { gernotbelger@9294: /* nothing to do, as we never have several results, everything is written into the general header */ mschaefer@9176: } mschaefer@9176: mschaefer@9176: @Override mschaefer@9176: protected String getJasperFile() { mschaefer@9229: if (this.getWaterlevelCount() <= 1) gernotbelger@9205: return "/jasper/templates/sinfo.floodduration.jrxml"; gernotbelger@9265: gernotbelger@9265: return "/jasper/templates/sinfo.floodduration2.jrxml"; mschaefer@9176: } mschaefer@9176: gernotbelger@9205: protected String[] formatRow(final AbstractExportContext exportContextCSV, final ResultRow row, final ExportMode mode) { mschaefer@9176: gernotbelger@9492: final Collection lines = new ArrayList<>(20); mschaefer@9176: mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.station)); mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.riverside)); mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.floodDuration)); mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.floodDischarge)); mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructureHeight)); mschaefer@9176: lines.add(exportContextCSV.formatRowValue(row, SInfoResultType.infrastructuretype)); mschaefer@9176: gernotbelger@9205: final List waterlevelList = (List) row.getValue(SInfoResultType.customMultiRowColWaterlevel); gernotbelger@9205: gernotbelger@9492: final int expectedSizetoGaugelabel = lines.size() + (waterlevelList.size() < 2 ? 4 : 12); // removing columns only works for fixed gernotbelger@9492: // indices gernotbelger@9205: gernotbelger@9492: final NumberFormat wFormatter = exportContextCSV.getFlowDepthFormatter(); gernotbelger@9492: final NumberFormat qFormatter = exportContextCSV.getQFormatter(); gernotbelger@9492: final NumberFormat durFormatter = exportContextCSV.getFloodDurationFormatter(); gernotbelger@9492: gernotbelger@9492: for (int i = 0; i < waterlevelList.size(); i++) { gernotbelger@9492: gernotbelger@9492: if (i == this.maxWaterlevelPdf && mode == ExportMode.pdf) gernotbelger@9492: break; gernotbelger@9492: gernotbelger@9492: final DurationWaterlevel item = waterlevelList.get(i); gernotbelger@9492: lines.add(item.getWFormatted(wFormatter)); gernotbelger@9492: lines.add(item.getFloodDurDaysPerYearFormatted(durFormatter)); gernotbelger@9492: lines.add(item.getQFormatted(qFormatter)); gernotbelger@9492: lines.add(item.getBezeichnung()); mschaefer@9202: } mschaefer@9176: gernotbelger@9492: final int lineSize = lines.size(); gernotbelger@9492: while (mode == ExportMode.pdf && lines.size() < expectedSizetoGaugelabel) gernotbelger@9492: lines.add(""); gernotbelger@9492: gernotbelger@9492: if (isUseWspl() || mode == ExportMode.pdf) gernotbelger@9492: lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.gaugeLabel)); // PDF: necessary, because if removed, location would not be shown! gernotbelger@9492: gernotbelger@9312: lines.add(exportContextCSV.formatRowValue(row, GeneralResultType.location)); mschaefer@9176: mschaefer@9176: return lines.toArray(new String[lines.size()]); gernotbelger@9150: } gernotbelger@9150: gernotbelger@9150: @Override gernotbelger@9195: public void writeCSVHeader(final ExportContextCSV exportContextCSV, final RiverInfo river) { gernotbelger@9150: mschaefer@9176: final Collection header = new ArrayList<>(20); gernotbelger@9150: gernotbelger@9150: header.add(exportContextCSV.formatCsvHeader(GeneralResultType.station)); gernotbelger@9150: header.add(exportContextCSV.formatCsvHeader(SInfoResultType.riverside)); mschaefer@9176: header.add(exportContextCSV.formatCsvHeader(SInfoResultType.floodDuration)); mschaefer@9176: header.add(exportContextCSV.msgUnitCSV(SInfoResultType.floodDischarge, SInfoResultType.floodDischarge.getUnit())); mschaefer@9297: header.add(exportContextCSV.msgUnitCSV(SInfoResultType.infrastructureHeight, river.getWstUnit())); gernotbelger@9150: header.add(exportContextCSV.formatCsvHeader(SInfoResultType.infrastructuretype)); gernotbelger@9150: gernotbelger@9205: // add dynamic headers gernotbelger@9205: final int waterlevelCount = // results. gernotbelger@9205: getWaterlevelCount(); gernotbelger@9205: for (int i = 0; i < waterlevelCount; i++) { mschaefer@9229: final String appendIndex = "_" + Integer.toString(i + 1); mschaefer@9297: header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderWCsv(), appendIndex, river.getWstUnit())); mschaefer@9229: header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderFloodDurPerYearCsv(), appendIndex)); mschaefer@9229: header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderQ(), appendIndex)); mschaefer@9229: header.add(exportContextCSV.msg(DurationWaterlevel.getHeaderBezeichnCsv(), appendIndex)); mschaefer@9202: } gernotbelger@9150: gernotbelger@9492: if (isUseWspl()) gernotbelger@9492: header.add(exportContextCSV.formatCsvHeader(GeneralResultType.gaugeLabel)); gernotbelger@9492: gernotbelger@9312: header.add(exportContextCSV.formatCsvHeader(GeneralResultType.location)); gernotbelger@9150: gernotbelger@9150: exportContextCSV.writeCSVLine(header.toArray(new String[header.size()])); gernotbelger@9265: } gernotbelger@9145: gernotbelger@9265: public List getValidDurationChartKilometers() { gernotbelger@9585: gernotbelger@9585: // Wunsch BfG (Testung MS3): nur stationen mit infrastruktur gernotbelger@9585: final Predicate filter = new HasInfrastructurePredicate(); gernotbelger@9585: return getValues(GeneralResultType.station, filter); gernotbelger@9145: } gernotbelger@9145: gernotbelger@9150: @Override gernotbelger@9195: protected String[] formatCSVRow(final ExportContextCSV exportContextCSV, final ResultRow row) { gernotbelger@9150: gernotbelger@9205: return this.formatRow(exportContextCSV, row, ExportMode.csv); gernotbelger@9150: } gernotbelger@9150: gernotbelger@9150: @Override gernotbelger@9195: protected String[] formatPDFRow(final ExportContextPDF exportContextPDF, final ResultRow row) { gernotbelger@9150: gernotbelger@9205: return this.formatRow(exportContextPDF, row, ExportMode.pdf); gernotbelger@9145: } gernotbelger@9145: mschaefer@9176: @Override gernotbelger@9195: protected void addJRTableHeader(final ExportContextPDF exportContextPDF, final MetaAndTableJRDataSource source) { gernotbelger@9150: mschaefer@9176: /* column headings */ mschaefer@9176: exportContextPDF.addJRMetadata(source, "station_header", GeneralResultType.station); mschaefer@9176: exportContextPDF.addJRMetadata(source, "riverside_header", SInfoResultType.riverside); mschaefer@9176: exportContextPDF.addJRMetadata(source, "inundationduration_header", SInfoResultType.floodDuration); mschaefer@9176: exportContextPDF.addJRMetadata(source, "inundationduration_q_header", SInfoResultType.floodDischarge); mschaefer@9202: exportContextPDF.addJRMetadata(source, "infrastructure_height_header", SInfoResultType.infrastructureHeight); mschaefer@9176: exportContextPDF.addJRMetadata(source, "infrastructure_type_header", SInfoResultType.infrastructuretype); gernotbelger@9150: mschaefer@9229: for (int i = 1; i <= this.getWaterlevelCount(); i++) { gernotbelger@9205: mschaefer@9229: final String appendIndex = "_" + Integer.toString(i); mschaefer@9229: exportContextPDF.addJRMetadata(source, getPdfHeader("w", i), exportContextPDF.msg(DurationWaterlevel.getHeaderWPdf(), appendIndex)); mschaefer@9229: exportContextPDF.addJRMetadata(source, getPdfHeader("duration", i), mschaefer@9229: exportContextPDF.msg(DurationWaterlevel.getHeaderFloodDurPerYearPdf(), appendIndex)); mschaefer@9229: exportContextPDF.addJRMetadata(source, getPdfHeader("q", i), exportContextPDF.msg(DurationWaterlevel.getHeaderQ(), appendIndex)); mschaefer@9229: exportContextPDF.addJRMetadata(source, getPdfHeader("bezeichnung", i), mschaefer@9229: exportContextPDF.msg(DurationWaterlevel.getHeaderBezeichnPdf(), appendIndex)); gernotbelger@9205: } gernotbelger@9150: gernotbelger@9318: exportContextPDF.addJRMetadata(source, "gauge_header", GeneralResultType.gaugeLabel); gernotbelger@9312: exportContextPDF.addJRMetadata(source, "location_header", GeneralResultType.location); gernotbelger@9150: } gernotbelger@9205: gernotbelger@9205: private final String getPdfHeader(final String rootStr, final int index) { gernotbelger@9205: final String hd = "_header"; gernotbelger@9205: final StringBuilder builder = new StringBuilder(); gernotbelger@9205: return builder.append(rootStr).append("_").append(index).append(hd).toString(); gernotbelger@9205: } gernotbelger@9205: mschaefer@9229: public final int getWaterlevelCount() { mschaefer@9285: return (this.waterlevelLabels != null) ? this.waterlevelLabels.length : 0; mschaefer@9229: } mschaefer@9229: mschaefer@9285: public String getWaterlevelLabel(final int j) { mschaefer@9285: if (this.waterlevelLabels != null && j < this.waterlevelLabels.length) mschaefer@9285: return this.waterlevelLabels[j]; gernotbelger@9205: return ""; gernotbelger@9205: } gernotbelger@9208: mschaefer@9229: /** mschaefer@9229: * Gets the longitudinal section of a result value type for one river side mschaefer@9229: */ mschaefer@9229: public final double[][] getInfrastructurePoints(final IResultType type, final AttributeKey riverside) { gernotbelger@9265: return getPoints(GeneralResultType.station, type, new RiversidePredicate(riverside)); mschaefer@9229: } mschaefer@9229: mschaefer@9229: /** mschaefer@9229: * Gets a longitudinal section of W, Q, or flood duration of one of the waterlevels mschaefer@9229: */ gernotbelger@9265: public final double[][] getMainValueDurationPoints(final ValueGetter valuegetter, final int dataIndex) { gernotbelger@9208: mschaefer@9298: final Collection rows = getAllRows(); gernotbelger@9208: gernotbelger@9265: final TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); gernotbelger@9265: final TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); gernotbelger@9265: gernotbelger@9265: for (final ResultRow row : rows) { gernotbelger@9208: gernotbelger@9208: final double station = row.getDoubleValue(GeneralResultType.station); gernotbelger@9208: gernotbelger@9208: final List waterlevels = (List) row.getValue(SInfoResultType.customMultiRowColWaterlevel); gernotbelger@9208: final DurationWaterlevel waterlevel = waterlevels.get(dataIndex); gernotbelger@9208: gernotbelger@9208: final Double value = valuegetter.getValue(waterlevel); gernotbelger@9208: gernotbelger@9208: xPoints.add(station); gernotbelger@9208: yPoints.add(value); gernotbelger@9208: } gernotbelger@9208: gernotbelger@9208: return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; gernotbelger@9208: } gernotbelger@9492: gernotbelger@9492: public boolean isUseWspl() { gernotbelger@9492: return this.isUseWspl; gernotbelger@9492: } gernotbelger@9145: }