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