ingo@389: package de.intevation.flys.exports; ingo@389: ingo@446: import java.io.IOException; ingo@389: import java.io.OutputStream; ingo@2045: import java.text.DateFormat; ingo@418: import java.text.NumberFormat; ingo@389: import java.util.ArrayList; raimund@2176: import java.util.Map; raimund@2176: import java.util.HashMap; ingo@2045: import java.util.Date; ingo@389: import java.util.List; ingo@2045: import java.util.Locale; ingo@2035: import java.util.regex.Matcher; ingo@2035: import java.util.regex.Pattern; ingo@389: ingo@389: import org.w3c.dom.Document; ingo@389: ingo@389: import org.apache.log4j.Logger; ingo@389: ingo@389: import au.com.bytecode.opencsv.CSVWriter; ingo@389: teichmann@4836: import de.intevation.flys.artifacts.model.ConstantWQKms; teichmann@4836: raimund@2176: import net.sf.jasperreports.engine.JasperExportManager; raimund@2176: import net.sf.jasperreports.engine.JasperFillManager; raimund@2176: import net.sf.jasperreports.engine.JasperPrint; raimund@2176: import net.sf.jasperreports.engine.JRException; raimund@2176: ingo@389: import de.intevation.artifacts.CallContext; ingo@2045: import de.intevation.artifacts.CallMeta; raimund@2185: import de.intevation.artifacts.common.utils.Config; ingo@389: ingo@2066: import de.intevation.flys.model.Gauge; ingo@2066: felix@5103: import de.intevation.flys.artifacts.access.FixRealizingAccess; felix@4859: import de.intevation.flys.artifacts.access.RangeAccess; felix@5103: import de.intevation.flys.artifacts.FixationArtifact; ingo@2045: import de.intevation.flys.artifacts.FLYSArtifact; ingo@2035: import de.intevation.flys.artifacts.WINFOArtifact; sascha@709: import de.intevation.flys.artifacts.model.CalculationResult; felix@5103: import de.intevation.flys.artifacts.model.Segment; ingo@749: import de.intevation.flys.artifacts.model.WQCKms; ingo@389: import de.intevation.flys.artifacts.model.WQKms; raimund@2176: import de.intevation.flys.artifacts.model.WKmsJRDataSource; felix@4405: import de.intevation.flys.artifacts.model.WQKmsResult; ingo@2045: import de.intevation.flys.artifacts.resources.Resources; sascha@706: ingo@2035: import de.intevation.flys.utils.FLYSUtils; ingo@2065: import de.intevation.flys.utils.FLYSUtils.WQ_MODE; ingo@445: import de.intevation.flys.utils.Formatter; ingo@389: ingo@389: /** felix@3252: * Generates different output formats (wst, csv, pdf) of data that resulted from felix@3252: * a waterlevel computation. felix@3252: * ingo@389: * @author Ingo Weinzierl ingo@389: */ ingo@391: public class WaterlevelExporter extends AbstractExporter { ingo@389: ingo@389: /** The logger used in this exporter.*/ ingo@389: private static Logger logger = Logger.getLogger(WaterlevelExporter.class); ingo@389: ingo@446: public static final String FACET_WST = "wst"; ingo@446: ingo@416: public static final String CSV_KM_HEADER = ingo@416: "export.waterlevel.csv.header.km"; ingo@416: ingo@416: public static final String CSV_W_HEADER = ingo@416: "export.waterlevel.csv.header.w"; ingo@416: ingo@416: public static final String CSV_Q_HEADER = ingo@416: "export.waterlevel.csv.header.q"; ingo@416: ingo@2063: public static final String CSV_Q_DESC_HEADER = ingo@2063: "export.waterlevel.csv.header.q.desc"; ingo@2063: ingo@2068: public static final String CSV_W_DESC_HEADER = ingo@2068: "export.waterlevel.csv.header.w.desc"; ingo@2068: ingo@2063: public static final String CSV_LOCATION_HEADER = ingo@2063: "export.waterlevel.csv.header.location"; ingo@2063: ingo@2063: public static final String CSV_GAUGE_HEADER = ingo@2063: "export.waterlevel.csv.header.gauge"; ingo@2063: ingo@2045: public static final String CSV_META_RESULT = ingo@2045: "export.waterlevel.csv.meta.result"; ingo@2045: ingo@2045: public static final String CSV_META_CREATION = ingo@2045: "export.waterlevel.csv.meta.creation"; ingo@2045: ingo@2045: public static final String CSV_META_CALCULATIONBASE = ingo@2045: "export.waterlevel.csv.meta.calculationbase"; ingo@2045: ingo@2045: public static final String CSV_META_RIVER = ingo@2045: "export.waterlevel.csv.meta.river"; ingo@2045: ingo@2045: public static final String CSV_META_RANGE = ingo@2045: "export.waterlevel.csv.meta.range"; ingo@2045: ingo@2045: public static final String CSV_META_GAUGE = ingo@2045: "export.waterlevel.csv.meta.gauge"; ingo@2045: ingo@2045: public static final String CSV_META_Q = ingo@2045: "export.waterlevel.csv.meta.q"; ingo@2045: ingo@2045: public static final String CSV_META_W = ingo@2045: "export.waterlevel.csv.meta.w"; ingo@2045: ingo@2066: public static final String CSV_NOT_IN_GAUGE_RANGE = ingo@2066: "export.waterlevel.csv.not.in.gauge.range"; ingo@2066: ingo@2035: public static final Pattern NUMBERS_PATTERN = ingo@2035: Pattern.compile("\\D*(\\d++.\\d*)\\D*"); ingo@2035: ingo@2063: public static final String DEFAULT_CSV_KM_HEADER = "Fluss-Km"; ingo@2063: public static final String DEFAULT_CSV_W_HEADER = "W [NN + m]"; ingo@2063: public static final String DEFAULT_CSV_Q_HEADER = "Q [m\u00b3/s]"; ingo@2063: public static final String DEFAULT_CSV_Q_DESC_HEADER = "Bezeichnung"; ingo@2068: public static final String DEFAULT_CSV_W_DESC_HEADER = "W/Pegel [cm]"; ingo@2063: public static final String DEFAULT_CSV_LOCATION_HEADER = "Lage"; ingo@2063: public static final String DEFAULT_CSV_GAUGE_HEADER = "Bezugspegel"; ingo@2066: public static final String DEFAULT_CSV_NOT_IN_GAUGE_RANGE = ingo@2066: "außerhalb des gewählten Bezugspegels"; ingo@416: raimund@2176: public static final String PDF_HEADER_MODE = "export.waterlevel.pdf.mode"; felix@2284: public static final String JASPER_FILE = "export.waterlevel.pdf.file"; ingo@416: ingo@389: /** The storage that contains all WQKms objects for the different facets.*/ ingo@389: protected List data; ingo@389: ingo@389: ingo@389: public void init(Document request, OutputStream out, CallContext context) { ingo@389: logger.debug("WaterlevelExporter.init"); ingo@389: ingo@391: super.init(request, out, context); ingo@389: ingo@391: this.data = new ArrayList(); ingo@389: } ingo@389: ingo@389: ingo@446: @Override ingo@446: public void generate() ingo@446: throws IOException ingo@446: { ingo@446: logger.debug("WaterlevelExporter.generate"); ingo@446: ingo@446: if (facet != null && facet.equals(AbstractExporter.FACET_CSV)) { ingo@446: generateCSV(); ingo@446: } ingo@446: else if (facet != null && facet.equals(FACET_WST)) { ingo@446: generateWST(); ingo@446: } raimund@2176: else if (facet != null && facet.equals(AbstractExporter.FACET_PDF)) { raimund@2176: generatePDF(); raimund@2176: } ingo@446: else { ingo@446: throw new IOException("invalid facet for exporter"); ingo@446: } ingo@446: } ingo@446: ingo@446: sascha@701: @Override sascha@701: protected void addData(Object d) { sascha@709: if (d instanceof CalculationResult) { sascha@709: d = ((CalculationResult)d).getData(); sascha@709: if (d instanceof WQKms []) { sascha@709: data.add((WQKms [])d); sascha@709: } felix@4405: else if (d instanceof WQKmsResult) { felix@4405: data.add(((WQKmsResult) d).getWQKms()); ingo@3462: } sascha@701: } ingo@389: } ingo@389: ingo@389: ingo@2035: /** ingo@2035: * This method is used to prepare the column titles of waterlevel exports. ingo@2035: * Titles in this export include the Q value. If a Q value matches a named ingo@2035: * main value (as HQ100 or MNQ) this named main value should be used as ingo@2035: * title. This method resets the name of the wqkms object if such ingo@2035: * named main value fits to the chosen Q. ingo@2035: * ingo@2035: * @param winfo A WINFO Artifact. ingo@2035: * @param wqkms A WQKms object that should be prepared. ingo@2035: */ ingo@2038: protected String getColumnTitle(WINFOArtifact winfo, WQKms wqkms) { felix@5131: logger.debug("WaterlevelExporter.getColumnTitle"); ingo@2035: ingo@2035: String name = wqkms.getName(); ingo@2035: ingo@2035: logger.debug("Name of WQKms = '" + name + "'"); ingo@2035: ingo@2038: if (name.indexOf("W=") >= 0) { ingo@2038: return name; ingo@2038: } ingo@2038: ingo@2035: Matcher m = NUMBERS_PATTERN.matcher(name); ingo@2035: ingo@2035: if (m.matches()) { ingo@2035: String raw = m.group(1); ingo@2035: ingo@2035: try { ingo@2035: double v = Double.valueOf(raw); ingo@2035: ingo@2038: String nmv = FLYSUtils.getNamedMainValue(winfo, v); ingo@2035: ingo@2035: if (nmv != null && nmv.length() > 0) { ingo@2596: nmv = FLYSUtils.stripNamedMainValue(nmv); ingo@2596: nmv += "=" + String.valueOf(v); ingo@2035: logger.debug("Set named main value '" + nmv + "'"); ingo@2035: ingo@2038: return nmv; ingo@2035: } ingo@2035: } ingo@2035: catch (NumberFormatException nfe) { ingo@2035: // do nothing here ingo@2035: } ingo@2035: } ingo@2038: ingo@2038: return name; ingo@2035: } ingo@2035: ingo@2035: ingo@2087: protected String getCSVRowTitle(WINFOArtifact winfo, WQKms wqkms) { ingo@2087: logger.debug("WaterlevelExporter.prepareNamedValue"); ingo@2087: ingo@2087: String name = wqkms.getName(); ingo@2087: ingo@2087: logger.debug("Name of WQKms = '" + name + "'"); ingo@2087: ingo@2087: WQ_MODE wqmode = FLYSUtils.getWQMode(winfo); ingo@2087: ingo@2087: if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.QGAUGE) { ingo@2087: return localizeWQKms(winfo, wqkms); ingo@2087: } ingo@2087: ingo@2087: Double v = wqkms.getRawValue(); ingo@2087: ingo@2087: String nmv = FLYSUtils.getNamedMainValue(winfo, v); ingo@2087: ingo@2087: if (nmv != null && nmv.length() > 0) { ingo@2087: nmv = FLYSUtils.stripNamedMainValue(nmv); ingo@2087: logger.debug("Set named main value '" + nmv + "'"); ingo@2087: ingo@2087: return nmv; ingo@2087: } ingo@2087: ingo@2087: return localizeWQKms(winfo, wqkms); ingo@2087: } ingo@2087: ingo@2087: felix@3252: /** felix@3252: * Get a string like 'W=' or 'Q=' with a number following in localized felix@3252: * format. felix@3252: */ ingo@2087: protected String localizeWQKms(WINFOArtifact winfo, WQKms wqkms) { ingo@2087: WQ_MODE wqmode = FLYSUtils.getWQMode(winfo); ingo@2087: Double rawValue = wqkms.getRawValue(); ingo@2087: ingo@2087: if (rawValue == null) { ingo@2087: return wqkms.getName(); ingo@2087: } ingo@2087: ingo@2087: NumberFormat nf = Formatter.getRawFormatter(context); ingo@2087: ingo@2087: if (wqmode == WQ_MODE.WFREE || wqmode == WQ_MODE.WGAUGE) { ingo@2087: return "W=" + nf.format(rawValue); ingo@2087: } ingo@2087: else { ingo@2087: return "Q=" + nf.format(rawValue); ingo@2087: } ingo@2087: } ingo@2087: ingo@2087: sascha@701: @Override ingo@391: protected void writeCSVData(CSVWriter writer) { ingo@391: logger.info("WaterlevelExporter.writeData"); ingo@389: felix@3252: WQ_MODE mode = FLYSUtils.getWQMode((FLYSArtifact)master); felix@3252: boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; felix@3252: boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; ingo@2423: FLYSUtils.WQ_INPUT input ingo@2423: = FLYSUtils.getWQInputMode((FLYSArtifact)master); ingo@2065: ingo@2045: writeCSVMeta(writer); ingo@2068: writeCSVHeader(writer, atGauge, isQ); ingo@416: ingo@389: for (WQKms[] tmp: data) { ingo@389: for (WQKms wqkms: tmp) { felix@3252: wQKms2CSV(writer, wqkms, atGauge, isQ); ingo@389: } ingo@389: } ingo@389: } ingo@389: ingo@389: ingo@2045: protected void writeCSVMeta(CSVWriter writer) { ingo@2045: logger.info("WaterlevelExporter.writeCSVMeta"); ingo@2045: felix@4859: // TODO use Access instead of FLYSUtils felix@4859: ingo@2045: CallMeta meta = context.getMeta(); ingo@2045: ingo@2045: FLYSArtifact flys = (FLYSArtifact) master; ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_RESULT, ingo@2045: CSV_META_RESULT, ingo@2045: new Object[] { FLYSUtils.getRivername(flys) }) ingo@2045: }); ingo@2045: ingo@2045: Locale locale = Resources.getLocale(meta); ingo@2045: DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_CREATION, ingo@2045: CSV_META_CREATION, ingo@2045: new Object[] { df.format(new Date()) }) ingo@2045: }); ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_CALCULATIONBASE, ingo@2045: CSV_META_CALCULATIONBASE, ingo@2045: new Object[] { "" }) // TODO what is required at this place? ingo@2045: }); ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_RIVER, ingo@2045: CSV_META_RIVER, ingo@2045: new Object[] { FLYSUtils.getRivername(flys) }) ingo@2045: }); ingo@2045: felix@4859: RangeAccess rangeAccess = new RangeAccess(flys, null); felix@4859: double[] kms = rangeAccess.getKmRange(); ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_RANGE, ingo@2045: CSV_META_RANGE, ingo@2045: new Object[] { kms[0], kms[kms.length-1] }) ingo@2045: }); ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_GAUGE, ingo@2045: CSV_META_GAUGE, ingo@2045: new Object[] { FLYSUtils.getGaugename(flys) }) ingo@2045: }); ingo@2045: ingo@2045: FLYSUtils.WQ_MODE wq = FLYSUtils.getWQMode(flys); ingo@2045: if (wq == FLYSUtils.WQ_MODE.QFREE || wq == FLYSUtils.WQ_MODE.QGAUGE) { ingo@2045: double[] qs = FLYSUtils.getQs(flys); ingo@2423: FLYSUtils.WQ_INPUT input = FLYSUtils.getWQInputMode(flys); ingo@2045: ingo@2423: String data = ""; ingo@2045: ingo@2423: if ((input == FLYSUtils.WQ_INPUT.ADAPTED || ingo@2423: input == FLYSUtils.WQ_INPUT.RANGE) && ingo@2423: qs != null && qs.length > 0) ingo@2423: { ingo@2423: data = String.valueOf(qs[0]); ingo@2423: data += " - " + String.valueOf(qs[qs.length-1]); ingo@2423: } ingo@2423: else if (input == FLYSUtils.WQ_INPUT.SINGLE && qs != null){ ingo@2423: data = String.valueOf(qs[0]); ingo@2423: for (int i = 1; i < qs.length; i++) { ingo@2423: data += ", " + String.valueOf(qs[i]); ingo@2423: } ingo@2045: } ingo@2045: else { ingo@2045: logger.warn("Could not determine Q range!"); ingo@2045: } ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_Q, ingo@2045: CSV_META_Q, ingo@2423: new Object[] {data}) ingo@2045: }); ingo@2045: } ingo@2045: else { ingo@2045: double[] ws = FLYSUtils.getWs(flys); ingo@2045: ingo@2045: String lower = ""; ingo@2045: String upper = ""; ingo@2045: ingo@2045: if (ws != null && ws.length > 0) { ingo@2045: lower = String.valueOf(ws[0]); ingo@2045: upper = String.valueOf(ws[ws.length-1]); ingo@2045: } ingo@2045: else { ingo@2045: logger.warn("Could not determine W range!"); ingo@2045: } ingo@2045: ingo@2045: writer.writeNext(new String[] { ingo@2045: Resources.getMsg( ingo@2045: meta, ingo@2045: CSV_META_W, ingo@2045: CSV_META_W, ingo@2045: new Object[] { lower, upper }) ingo@2045: }); ingo@2045: } ingo@2045: ingo@2045: writer.writeNext(new String[] { "" }); ingo@2045: } ingo@2045: ingo@2045: felix@4979: /** felix@4979: * Write the header, with different headings depending on whether at a felix@4979: * gauge or at a location. felix@4979: */ ingo@2068: protected void writeCSVHeader( ingo@2068: CSVWriter writer, ingo@2068: boolean atGauge, ingo@2068: boolean isQ ingo@2068: ) { ingo@416: logger.info("WaterlevelExporter.writeCSVHeader"); ingo@416: felix@5133: String unit = FLYSUtils.getRiver((FLYSArtifact) master).getWstUnit().getName(); felix@5133: ingo@2065: if (atGauge) { ingo@2065: writer.writeNext(new String[] { ingo@2065: msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), felix@5133: msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), ingo@2065: msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), ingo@2068: (isQ ingo@2068: ? msg(CSV_Q_DESC_HEADER, DEFAULT_CSV_Q_DESC_HEADER) ingo@2068: : msg(CSV_W_DESC_HEADER, DEFAULT_CSV_W_DESC_HEADER)), ingo@2065: msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER), ingo@2065: msg(CSV_GAUGE_HEADER, DEFAULT_CSV_GAUGE_HEADER) ingo@2065: }); ingo@2065: } ingo@2065: else { ingo@2065: writer.writeNext(new String[] { ingo@2065: msg(CSV_KM_HEADER, DEFAULT_CSV_KM_HEADER), felix@5133: // TODO flys/issue1128 (unit per river) felix@5133: msg(CSV_W_HEADER, DEFAULT_CSV_W_HEADER, new Object[] { unit }), ingo@2065: msg(CSV_Q_HEADER, DEFAULT_CSV_Q_HEADER), ingo@2065: msg(CSV_LOCATION_HEADER, DEFAULT_CSV_LOCATION_HEADER) ingo@2065: }); ingo@2065: } ingo@416: } ingo@416: ingo@416: felix@5112: /** Linearly search for gauge which is valid at km. */ teichmann@5587: private static Gauge findGauge(double km, List gauges) { felix@5112: for (Gauge gauge: gauges) { teichmann@5587: if (gauge.getRange().contains(km)) { felix@5112: return gauge; felix@5112: } felix@5112: } felix@5112: return null; felix@5112: } felix@5112: teichmann@5587: private static Segment findSegment(double km, List segments) { teichmann@5587: for (Segment segment: segments) { teichmann@5587: if (segment.inside(km)) { teichmann@5587: return segment; teichmann@5587: } teichmann@5587: } teichmann@5587: return null; teichmann@5587: } teichmann@5587: felix@5112: felix@5112: private void writeRow4(CSVWriter writer, double wqkm[], FLYSArtifact flys) { felix@5112: NumberFormat kmf = getKmFormatter(); felix@5112: NumberFormat wf = getWFormatter(); felix@5112: NumberFormat qf = getQFormatter(); felix@5112: felix@5112: writer.writeNext(new String[] { felix@5112: kmf.format(wqkm[2]), felix@5112: wf.format(wqkm[0]), felix@5112: qf.format(wqkm[1]), felix@5112: FLYSUtils.getLocationDescription(flys, wqkm[2]) felix@5112: }); felix@5112: } felix@5112: felix@5112: felix@5112: /** Write an csv-row at gauge location. */ felix@5112: private void writeRow6(CSVWriter writer, double wqkm[], String wOrQDesc, felix@5112: FLYSArtifact flys, String gaugeName) { felix@5112: NumberFormat kmf = getKmFormatter(); felix@5112: NumberFormat wf = getWFormatter(); felix@5112: NumberFormat qf = getQFormatter(); felix@5112: felix@5112: writer.writeNext(new String[] { felix@5112: kmf.format(wqkm[2]), felix@5112: wf.format(wqkm[0]), felix@5112: qf.format(wqkm[1]), felix@5112: wOrQDesc, felix@5112: FLYSUtils.getLocationDescription(flys, wqkm[2]), felix@5112: gaugeName felix@5112: }); felix@5112: } felix@5112: felix@5112: felix@3252: /** felix@3252: * Write "rows" of csv data from wqkms with writer. felix@3252: */ ingo@2068: protected void wQKms2CSV( ingo@2068: CSVWriter writer, ingo@2068: WQKms wqkms, ingo@2068: boolean atGauge, felix@3252: boolean isQ ingo@2068: ) { ingo@389: logger.debug("WaterlevelExporter.wQKms2CSV"); ingo@389: teichmann@4836: // Skip constant data. teichmann@4836: if (wqkms instanceof ConstantWQKms) { teichmann@4836: return; teichmann@4836: } teichmann@4836: ingo@418: NumberFormat kmf = getKmFormatter(); ingo@418: NumberFormat wf = getWFormatter(); ingo@418: NumberFormat qf = getQFormatter(); ingo@418: ingo@389: int size = wqkms.size(); ingo@389: double[] result = new double[3]; ingo@389: ingo@2066: FLYSArtifact flys = (FLYSArtifact) master; felix@5112: List gauges = FLYSUtils.getGauges(flys); ingo@2066: Gauge gauge = FLYSUtils.getGauge(flys); ingo@2066: String gaugeName = gauge.getName(); ingo@2066: String desc = ""; ingo@2066: String notinrange = msg( ingo@2066: CSV_NOT_IN_GAUGE_RANGE, ingo@2066: DEFAULT_CSV_NOT_IN_GAUGE_RANGE); ingo@2066: ingo@2066: double a = gauge.getRange().getA().doubleValue(); ingo@2066: double b = gauge.getRange().getB().doubleValue(); ingo@2065: ingo@2068: if (flys instanceof WINFOArtifact && isQ) { ingo@2087: desc = getCSVRowTitle((WINFOArtifact)flys, wqkms); ingo@2065: } ingo@2068: else if (!isQ) { ingo@2068: Double value = FLYSUtils.getValueFromWQ(wqkms); ingo@2068: desc = value != null ingo@2068: ? Formatter.getWaterlevelW(context).format(value) : null; ingo@2068: } ingo@2063: sascha@2144: long startTime = System.currentTimeMillis(); sascha@2144: felix@3313: String colDesc = desc; felix@5103: List segments = null; felix@5112: boolean isFixRealize = false; felix@3313: if (flys instanceof WINFOArtifact) { felix@3313: if (wqkms != null && wqkms.getRawValue() != null) { felix@3313: WINFOArtifact winfo = (WINFOArtifact) flys; felix@3313: colDesc = FLYSUtils.getNamedMainValue(winfo, wqkms.getRawValue()); felix@3313: } felix@3313: } felix@5103: else if (flys instanceof FixationArtifact) { felix@5103: // Get W/Q input per gauge for this case. felix@5103: FixRealizingAccess fixAccess = new FixRealizingAccess(flys, getCallContext()); felix@5103: segments = fixAccess.getSegments(); teichmann@5587: if (segments != null && !segments.isEmpty()) { felix@5112: isFixRealize = true; felix@5112: } felix@5103: } sascha@2612: teichmann@5587: if (atGauge) { // "At gauge" needs more output. ingo@389: teichmann@5587: // Kms tend to be close together so caching the last sector teichmann@5587: // is a good time saving heuristic. teichmann@5587: Segment lastSegment = null; teichmann@5587: Gauge lastGauge = null; teichmann@5587: teichmann@5587: NumberFormat nf = teichmann@5587: Formatter.getFormatter(context.getMeta(), 0, 0); teichmann@5587: teichmann@5587: for (int i = 0; i < size; ++i) { teichmann@5587: result = wqkms.get(i, result); teichmann@5587: double km = result[2]; teichmann@5587: teichmann@5587: if (segments != null) { teichmann@5587: Segment found = lastSegment != null teichmann@5587: && lastSegment.inside(km) teichmann@5587: ? lastSegment teichmann@5587: : findSegment(km, segments); teichmann@5587: teichmann@5587: if (found != null) { teichmann@5587: colDesc = nf.format(found.getValues()[0]); felix@5103: } teichmann@5587: lastSegment = found; felix@5103: } felix@5103: felix@5112: String gaugeN; felix@5112: if (isFixRealize) { teichmann@5587: Gauge found = lastGauge != null teichmann@5587: && lastGauge.getRange().contains(km) teichmann@5587: ? lastGauge teichmann@5587: : findGauge(km, gauges); teichmann@5587: teichmann@5587: gaugeN = found != null ? found.getName() : notinrange; teichmann@5587: lastGauge = found; felix@5112: } felix@5112: else { felix@4979: // TODO issue1114: Take correct gauge teichmann@5587: gaugeN = km >= a && km <= b ingo@2066: ? gaugeName felix@5112: : notinrange; felix@5112: } felix@5112: writeRow6(writer, result, colDesc, flys, gaugeN); ingo@2065: } teichmann@5587: } teichmann@5587: else { // Not at gauge. teichmann@5587: for (int i = 0; i < size; ++i) { teichmann@5587: result = wqkms.get(i, result); felix@5112: writeRow4(writer, result, flys); ingo@2065: } ingo@389: } sascha@2144: sascha@2144: long stopTime = System.currentTimeMillis(); sascha@2144: sascha@2144: if (logger.isDebugEnabled()) { sascha@2144: logger.debug("Writing CSV took " + sascha@2144: (float)(stopTime-startTime)/1000f + " secs."); sascha@2144: } ingo@389: } ingo@418: ingo@418: ingo@418: /** ingo@446: * Generates the output in WST format. ingo@446: */ ingo@446: protected void generateWST() ingo@446: throws IOException ingo@446: { ingo@446: logger.info("WaterlevelExporter.generateWST"); ingo@446: ingo@446: int cols = data.get(0).length; ingo@446: WstWriter writer = new WstWriter(cols); ingo@446: ingo@446: writeWSTData(writer); ingo@446: ingo@446: writer.write(out); ingo@446: } ingo@446: ingo@446: ingo@446: protected void writeWSTData(WstWriter writer) { ingo@446: logger.debug("WaterlevelExporter.writeWSTData"); ingo@446: ingo@749: double[] result = new double[4]; ingo@446: ingo@446: for (WQKms[] tmp: data) { ingo@446: for (WQKms wqkms: tmp) { rrenkert@5105: if (wqkms instanceof ConstantWQKms) { rrenkert@5105: continue; rrenkert@5105: } ingo@446: int size = wqkms != null ? wqkms.size() : 0; ingo@446: ingo@450: addWSTColumn(writer, wqkms); ingo@447: ingo@446: for (int i = 0; i < size; i++) { ingo@446: result = wqkms.get(i, result); ingo@446: ingo@446: writer.add(result); ingo@446: } ingo@749: ingo@749: if (wqkms instanceof WQCKms) { ingo@749: addWSTColumn(writer, wqkms); ingo@749: ingo@749: for (int c = 0; c < size; c++) { ingo@749: result = wqkms.get(c, result); ingo@749: ingo@749: writer.addCorrected(result); ingo@749: } ingo@749: } ingo@446: } ingo@446: } ingo@446: } ingo@446: ingo@446: ingo@2038: /** ingo@2038: * This method is used to register a new column at writer. The name / ingo@2038: * title of the column depends on the Q or W value of wqkms. If a Q ingo@2038: * was selected and the Q fits to a named main value, the title is set to ingo@2038: * the named main value. Otherwise, the name returned by ingo@2038: * WQKms.getName() is set. ingo@2038: * ingo@2038: * @param writer The WstWriter. ingo@2038: * @param wqkms The new WST column. ingo@2038: */ ingo@450: protected void addWSTColumn(WstWriter writer, WQKms wqkms) { teichmann@4836: if (wqkms instanceof ConstantWQKms) { teichmann@4836: return; teichmann@4836: } ingo@2038: if (master instanceof WINFOArtifact) { ingo@2038: writer.addColumn(getColumnTitle((WINFOArtifact) master, wqkms)); ingo@2038: } ingo@2038: else { ingo@2038: writer.addColumn(wqkms.getName()); ingo@2038: } ingo@450: } ingo@450: ingo@450: ingo@446: /** raimund@2176: * raimund@2176: */ raimund@2176: @Override raimund@2176: protected void writePDF(OutputStream out) { raimund@2176: logger.debug("write PDF"); raimund@2176: WKmsJRDataSource source = createJRData(); raimund@2185: raimund@2185: String jasperFile = Resources.getMsg( raimund@2185: context.getMeta(), raimund@2185: JASPER_FILE, raimund@2185: "/jasper/waterlevel_en.jasper"); raimund@2185: String confPath = Config.getConfigDirectory().toString(); raimund@2185: raimund@2185: raimund@2176: Map parameters = new HashMap(); raimund@2176: parameters.put("ReportTitle", "Exported Data"); raimund@2176: try { raimund@2176: JasperPrint print = JasperFillManager.fillReport( raimund@2185: confPath + jasperFile, raimund@2176: parameters, raimund@2176: source); raimund@2176: JasperExportManager.exportReportToPdfStream(print, out); raimund@2176: } raimund@2176: catch(JRException je) { teichmann@4836: logger.warn("Error generating PDF Report!", je); raimund@2176: } raimund@2176: } raimund@2176: raimund@2176: protected WKmsJRDataSource createJRData() { raimund@2176: WKmsJRDataSource source = new WKmsJRDataSource(); raimund@2176: raimund@2176: WQ_MODE mode = FLYSUtils.getWQMode((FLYSArtifact)master); raimund@2176: boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; raimund@2176: boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; raimund@2176: raimund@2176: addMetaData(source); raimund@2176: for (WQKms[] tmp: data) { raimund@2176: for (WQKms wqkms: tmp) { raimund@2176: addWKmsData(wqkms, atGauge, isQ, source); raimund@2176: } raimund@2176: } raimund@2176: return source; raimund@2176: } raimund@2176: raimund@2176: protected void addMetaData(WKmsJRDataSource source) { raimund@2176: CallMeta meta = context.getMeta(); raimund@2176: raimund@2176: FLYSArtifact flys = (FLYSArtifact) master; raimund@2176: raimund@2176: source.addMetaData ("river", FLYSUtils.getRivername(flys)); raimund@2176: raimund@2176: Locale locale = Resources.getLocale(meta); raimund@2176: DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); raimund@2176: raimund@2176: source.addMetaData("date", df.format(new Date())); raimund@2176: felix@4859: RangeAccess rangeAccess = new RangeAccess(flys, null); felix@4859: double[] kms = rangeAccess.getKmRange(); raimund@2176: source.addMetaData("range", kms[0] + " - " + kms[kms.length-1]); raimund@2176: raimund@2176: source.addMetaData("gauge", FLYSUtils.getGaugename(flys)); raimund@2176: raimund@2176: source.addMetaData("calculation", Resources.getMsg( raimund@2176: locale, raimund@2176: PDF_HEADER_MODE, raimund@2176: "Waterlevel")); raimund@2176: } raimund@2176: raimund@2176: protected void addWKmsData( raimund@2176: WQKms wqkms, raimund@2176: boolean atGauge, raimund@2176: boolean isQ, raimund@2176: WKmsJRDataSource source) raimund@2176: { raimund@2176: logger.debug("WaterlevelExporter.addWKmsData"); raimund@2176: teichmann@4836: // Skip constant data. teichmann@4836: if (wqkms instanceof ConstantWQKms) { teichmann@4836: return; teichmann@4836: } teichmann@4836: raimund@2176: NumberFormat kmf = getKmFormatter(); raimund@2176: NumberFormat wf = getWFormatter(); raimund@2176: NumberFormat qf = getQFormatter(); raimund@2176: raimund@2176: int size = wqkms.size(); raimund@2176: double[] result = new double[3]; raimund@2176: raimund@2176: FLYSArtifact flys = (FLYSArtifact) master; raimund@2176: Gauge gauge = FLYSUtils.getGauge(flys); raimund@2176: String gaugeName = gauge.getName(); raimund@2176: String desc = ""; raimund@2176: String notinrange = msg( raimund@2176: CSV_NOT_IN_GAUGE_RANGE, raimund@2176: DEFAULT_CSV_NOT_IN_GAUGE_RANGE); raimund@2176: raimund@2176: double a = gauge.getRange().getA().doubleValue(); raimund@2176: double b = gauge.getRange().getB().doubleValue(); raimund@2176: raimund@2176: if (flys instanceof WINFOArtifact && isQ) { raimund@2176: desc = getCSVRowTitle((WINFOArtifact)flys, wqkms); raimund@2176: } raimund@2176: else if (!isQ) { raimund@2176: Double value = FLYSUtils.getValueFromWQ(wqkms); raimund@2176: desc = value != null raimund@2176: ? Formatter.getWaterlevelW(context).format(value) : null; raimund@2176: } raimund@2176: raimund@2176: long startTime = System.currentTimeMillis(); raimund@2176: raimund@2176: for (int i = 0; i < size; i ++) { raimund@2176: result = wqkms.get(i, result); raimund@2176: raimund@2176: if (atGauge) { raimund@2176: source.addData(new String[] { raimund@2176: kmf.format(result[2]), raimund@2176: wf.format(result[0]), raimund@2176: qf.format(result[1]), raimund@2176: desc, raimund@2176: FLYSUtils.getLocationDescription(flys, result[2]), raimund@2176: result[2] >= a && result[2] <= b raimund@2176: ? gaugeName raimund@2176: : notinrange raimund@2176: }); raimund@2176: } raimund@2176: else { raimund@2176: source.addData(new String[] { raimund@2176: kmf.format(result[2]), raimund@2176: wf.format(result[0]), raimund@2176: qf.format(result[1]), raimund@2764: desc, raimund@2764: FLYSUtils.getLocationDescription(flys, result[2]), raimund@2764: result[2] >= a && result[2] <= b raimund@2764: ? gaugeName raimund@2764: : notinrange raimund@2176: }); raimund@2176: } raimund@2176: } raimund@2176: raimund@2176: long stopTime = System.currentTimeMillis(); raimund@2176: raimund@2176: if (logger.isDebugEnabled()) { raimund@2176: logger.debug("Writing PDF data took " + raimund@2176: (float)(stopTime-startTime)/1000f + " secs."); raimund@2176: } raimund@2176: } ingo@389: } ingo@389: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :