view artifacts/src/main/java/org/dive4elements/river/exports/fixings/DeltaWtExporter.java @ 9415:9744ce3c3853

Rework of fixanalysis computation and dWt and WQ facets. Got rid of strange remapping and bitshifting code by explicitely saving the column information and using it in the facets. The facets also put the valid station range into their xml-metadata
author gernotbelger
date Thu, 16 Aug 2018 16:27:53 +0200
parents ddcd52d239cd
children
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde
 * Software engineering by Intevation GmbH
 *
 * This file is Free Software under the GNU AGPL (>=v3)
 * and comes with ABSOLUTELY NO WARRANTY! Check out the
 * documentation coming with Dive4Elements River for details.
 */

package org.dive4elements.river.exports.fixings;

import java.io.IOException;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.TreeMap;

import org.apache.log4j.Logger;
import org.dive4elements.artifacts.CallMeta;
import org.dive4elements.river.artifacts.D4EArtifact;
import org.dive4elements.river.artifacts.access.RangeAccess;
import org.dive4elements.river.artifacts.access.RiverAccess;
import org.dive4elements.river.artifacts.common.DefaultCalculationResults;
import org.dive4elements.river.artifacts.common.ExportContextPDF;
import org.dive4elements.river.artifacts.common.GeneralResultType;
import org.dive4elements.river.artifacts.common.JasperReporter;
import org.dive4elements.river.artifacts.common.MetaAndTableJRDataSource;
import org.dive4elements.river.artifacts.model.CalculationResult;
import org.dive4elements.river.artifacts.model.fixings.AnalysisPeriodEventResults;
import org.dive4elements.river.artifacts.model.fixings.FixAnalysisResult;
import org.dive4elements.river.artifacts.model.fixings.FixResultColumn;
import org.dive4elements.river.artifacts.model.fixings.FixResultColumns;
import org.dive4elements.river.artifacts.model.fixings.QWD;
import org.dive4elements.river.artifacts.resources.Resources;
import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils;
import org.dive4elements.river.artifacts.sinfo.util.RiverInfo;
import org.dive4elements.river.exports.AbstractExporter;
import org.dive4elements.river.utils.Formatter;
import org.dive4elements.river.utils.KMIndex;
import org.dive4elements.river.utils.KMIndex.Entry;

import au.com.bytecode.opencsv.CSVWriter;
import net.sf.jasperreports.engine.JRException;

/** Exports fixation analysis deltaw(t) computation results to csv. */
public class DeltaWtExporter extends AbstractExporter {
    /** Private log. */
    private static Logger log = Logger.getLogger(DeltaWtExporter.class);

    private static final String JASPER_FILE = "/jasper/templates/fixanalysis.delta_wt.jrxml";

    private static final String CSV_KM_HEADER = "export.fixings.deltawt.csv.header.km";

    private static final String CSV_DELTA_W_HEADER = "export.fixings.deltawt.csv.header.deltaw";

    private static final String CSV_Q_HEADER = "export.fixings.deltawt.csv.header.q";

    private static final String CSV_W_HEADER = "export.fixings.deltawt.csv.header.w";

    private static final String CSV_TRANGE_HEADER = "export.fixings.deltawt.csv.header.time.range";

    private static final String CSV_T_HEADER = "export.fixings.deltawt.csv.header.t";

    private static final String CSV_T_FORMAT = "export.fixings.deltawt.csv.t.format";

    private static final String DEFAULT_CSV_KM_HEADER = "km";

    private static final String DEFAULT_CSV_DELTA_W_HEADER = "\u0394 W [cm]";

    private static final String DEFAULT_CSV_W_HEADER = "Wasserstand [m]";

    private static final String DEFAULT_CSV_Q_HEADER = "Abfluss [m\u00b3/s]";

    private static final String DEFAULT_CSV_T_HEADER = "Datum";

    private static final String DEFAULT_CSV_TRANGE_DESC_HEADER = "Status";

    private static final String CSV_REFERENCE = "export.fixings.deltawt.csv.reference";

    private static final String CSV_ANALYSIS = "export.fixings.deltawt.csv.analysis";

    private static final String DEFAULT_CSV_REFERENCE = "B";

    private static final String DEFAULT_CSV_ANALYSIS = "A{0,number,integer}";

    private static final String DEFAULT_CSV_T_FORMAT = "dd.MM.yyyy";

    private final List<AnalysisPeriodEventResults> analysisEvents = new ArrayList<>();

    private final List<FixResultColumns> referenceEvents = new ArrayList<>();

    @Override
    protected void addData(final Object d) {
        log.debug("DeltaWtExporter.addData");
        if (!(d instanceof CalculationResult)) {
            log.warn("Invalid data type");
            return;
        }

        final Object data = ((CalculationResult) d).getData();
        if (!(data instanceof FixAnalysisResult)) {
            log.warn("Invalid data stored in result.");
            return;
        }

        final FixAnalysisResult result = (FixAnalysisResult) data;
        this.analysisEvents.add(result.getAnalysisEventResults());
        this.referenceEvents.add(result.getFixResultColumns());
    }

    @Override
    protected void writeCSVData(final CSVWriter writer) throws IOException {

        writeCSVHeader(writer);

        final TreeMap<Double, List<String[]>> sorted = getRows();
        for (final List<String[]> list : sorted.values()) {
            for (final String[] row : list)
                writer.writeNext(row);
        }

        writer.flush();
    }

    private TreeMap<Double, List<String[]>> getRows() {
        final NumberFormat kmF = getKMFormatter();
        final NumberFormat dwF = getDeltaWFormatter();
        final NumberFormat qF = getQFormatter();
        final NumberFormat wF = getWFormatter();

        final DateFormat dF = getDateFormatter();

        final TreeMap<Double, List<String[]>> sorted = new TreeMap<>();

        final String referenceS = getReference();

        for (final FixResultColumns referenceColumns : this.referenceEvents) {

            appendRows(sorted, referenceColumns, referenceS, kmF, dwF, qF, wF, dF);
        }

        final String analysisTemplate = getAnalysisTemplate();

        int analysisCount = 1;
        for (final AnalysisPeriodEventResults analysisPeriodEventResults : this.analysisEvents) {

            final Collection<FixResultColumns> analysisResults = analysisPeriodEventResults.getEventResults();
            for (final FixResultColumns analysisColumns : analysisResults) {

                final String analyisS = MessageFormat.format(analysisTemplate, analysisCount);
                appendRows(sorted, analysisColumns, analyisS, kmF, dwF, qF, wF, dF);
            }

            analysisCount++;
        }

        return sorted;
    }

    private void appendRows(final TreeMap<Double, List<String[]>> sorted, final FixResultColumns resultColumns, final String referenceS, final NumberFormat kmF,
            final NumberFormat dwF, final NumberFormat qF, final NumberFormat wF, final DateFormat dF) {

        final Collection<FixResultColumn> cols = resultColumns.getSortedColumns();
        for (final FixResultColumn column : cols) {

            final Date date = column.getDate();

            final KMIndex<QWD> qwds = column.getQWDs();
            for (final Entry<QWD> qwdEntry : qwds) {

                final double km = qwdEntry.getKm();
                final QWD qwd = qwdEntry.getValue();

                List<String[]> list = sorted.get(km);
                if (list == null) {
                    list = new ArrayList<>();
                    sorted.put(km, list);
                }

                if (!qwd.isOutlier()) {
                    final String kmS = kmF.format(km);
                    final String deltaWS = dwF.format(qwd.getDeltaW());
                    final String qS = qF.format(qwd.getQ());
                    final String wS = wF.format(qwd.getW());
                    final String dateS = dF.format(date);

                    list.add(new String[] { kmS, dateS, qS, wS, referenceS, deltaWS });
                }
            }
        }
    }

    /** Template to create "State" strings like A1,A2... */
    protected String getAnalysisTemplate() {
        return Resources.getMsg(this.context.getMeta(), CSV_ANALYSIS, DEFAULT_CSV_ANALYSIS);
    }

    protected String getReference() {
        return Resources.getMsg(this.context.getMeta(), CSV_REFERENCE, DEFAULT_CSV_REFERENCE);
    }

    protected NumberFormat getKMFormatter() {
        return Formatter.getFixDeltaWKM(this.context);
    }

    protected NumberFormat getDeltaWFormatter() {
        return Formatter.getFixDeltaWDeltaW(this.context);
    }

    @Override
    protected NumberFormat getQFormatter() {
        return Formatter.getFixDeltaWQ(this.context);
    }

    @Override
    protected NumberFormat getWFormatter() {
        return Formatter.getFixDeltaWW(this.context);
    }

    protected DateFormat getDateFormatter() {
        final CallMeta meta = this.context.getMeta();
        return Formatter.getDateFormatter(meta, Resources.getMsg(meta, CSV_T_FORMAT, DEFAULT_CSV_T_FORMAT));
    }

    protected void writeCSVHeader(final CSVWriter writer) {
        log.debug("DeltaWtExporter.writeCSVHeader");

        /*
         * issue825
         * km; Ereignis, Abfluss, GEMESSENER Wasserstand;
         * Status (RECHTSBÜNDIG), del W
         */
        final RiverAccess river = new RiverAccess((D4EArtifact) this.master);
        final String unit = river.getRiver().getWstUnit().getName();

        writer.writeNext(new String[] { msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), msg(CSV_T_HEADER, DEFAULT_CSV_T_HEADER),
                msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }),
                msg(CSV_TRANGE_HEADER, DEFAULT_CSV_TRANGE_DESC_HEADER), msg(CSV_DELTA_W_HEADER, DEFAULT_CSV_DELTA_W_HEADER) });
    }

    private void addMetaData(final MetaAndTableJRDataSource source) {
        final D4EArtifact flys = (D4EArtifact) this.master;
        final String user = CalculationUtils.findArtifactUser(this.context, flys);
        final RangeAccess ra = new RangeAccess(flys);
        final RiverInfo ri = new RiverInfo(ra.getRiver());

        final DefaultCalculationResults results = new DefaultCalculationResults(msg("calculation.analysis"), user, ri, ra.getRange());
        final ExportContextPDF contextPdf = new ExportContextPDF(this.context, results);
        contextPdf.addJRMetaDataDefaults(source);
        contextPdf.addJRMetaDataForModules(source);

        /* column headings */
        contextPdf.addJRMetadata(source, "station_header", GeneralResultType.station);
        contextPdf.addJRMetadata(source, "fix_date", msg(CSV_T_HEADER));
        contextPdf.addJRMetadata(source, "fix_q", msg(CSV_Q_HEADER));
        contextPdf.addJRMetadata(source, "fix_w", msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { ri.getWstUnit() }));
        contextPdf.addJRMetadata(source, "fix_state", msg(CSV_TRANGE_HEADER));
        contextPdf.addJRMetadata(source, "fix_delta_w", msg(CSV_DELTA_W_HEADER));
    }

    @Override
    protected void writePDF(final OutputStream out) {

        final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource();
        final String jasperFile = Resources.getMsg(this.context.getMeta(), JASPER_FILE);

        addMetaData(source);
        try {
            final TreeMap<Double, List<String[]>> sorted = getRows(); // Custom Result could be nice, too...
            for (final List<String[]> list : sorted.values()) {
                for (final String[] row : list)
                    source.addData(row);
            }

            final JasperReporter reporter = new JasperReporter();
            reporter.addReport(jasperFile, source);
            reporter.exportPDF(out);
        }
        catch (final JRException je) {
            log.warn("Error generating PDF Report!", je);
        }
    }
}

http://dive4elements.wald.intevation.org