raimund@3131: package de.intevation.flys.exports.fixings; raimund@3131: sascha@3139: import de.intevation.artifactdatabase.state.ArtifactAndFacet; sascha@3139: import de.intevation.artifacts.ArtifactNamespaceContext; sascha@3139: import de.intevation.artifacts.CallContext; sascha@3139: import de.intevation.artifacts.common.utils.XMLUtils; sascha@3139: import de.intevation.flys.artifacts.FLYSArtifact; christian@3279: import de.intevation.flys.artifacts.access.FixationArtifactAccess; sascha@3210: import de.intevation.flys.artifacts.model.DateRange; sascha@3139: import de.intevation.flys.artifacts.model.FacetTypes; sascha@3139: import de.intevation.flys.artifacts.model.fixings.QWD; christian@3279: import de.intevation.flys.artifacts.resources.Resources; sascha@3139: import de.intevation.flys.exports.TimeseriesChartGenerator; christian@3212: import de.intevation.flys.jfree.CollisionFreeXYTextAnnotation; christian@3212: import de.intevation.flys.jfree.FLYSAnnotation; christian@3254: import de.intevation.flys.jfree.StyledDomainMarker; sascha@3139: import de.intevation.flys.jfree.StyledTimeSeries; christian@3254: import de.intevation.flys.jfree.StyledValueMarker; felix@3238: import de.intevation.flys.utils.ThemeUtil; sascha@3139: sascha@3139: import java.io.OutputStream; christian@3212: import java.util.ArrayList; christian@3212: import java.util.HashMap; christian@3212: import java.util.List; christian@3212: import java.util.Map; christian@3212: import java.util.Set; christian@3212: sascha@3139: import javax.xml.xpath.XPathConstants; raimund@3131: raimund@3131: import org.apache.log4j.Logger; raimund@3131: import org.jfree.chart.JFreeChart; christian@3212: import org.jfree.chart.annotations.XYTextAnnotation; raimund@3131: import org.jfree.chart.title.TextTitle; raimund@3131: import org.jfree.data.time.Day; raimund@3131: import org.jfree.data.time.Month; raimund@3131: import org.jfree.data.time.RegularTimePeriod; raimund@3131: import org.jfree.data.time.TimeSeries; raimund@3131: import org.jfree.data.time.TimeSeriesCollection; sascha@3139: import org.w3c.dom.Document; sascha@3139: import org.w3c.dom.Element; raimund@3131: christian@3251: raimund@3131: /** christian@3251: * Generator for Delta W(t) charts. raimund@3131: * @author Raimund Renkert raimund@3131: */ raimund@3131: public class FixDeltaWtGenerator raimund@3131: extends TimeseriesChartGenerator raimund@3131: implements FacetTypes raimund@3131: { raimund@3131: private static Logger logger = raimund@3131: Logger.getLogger(FixDeltaWtGenerator.class); raimund@3131: raimund@3131: public static final String XPATH_CHART_CURRENTKM = raimund@3131: "/art:action/art:attributes/art:currentKm"; raimund@3131: raimund@3131: public static final String I18N_CHART_TITLE = raimund@3131: "chart.fix.deltawt.title"; raimund@3131: raimund@3131: public static final String I18N_CHART_SUBTITLE = raimund@3131: "chart.fix.deltawt.subtitle"; raimund@3131: raimund@3131: public static final String I18N_XAXIS_LABEL = raimund@3131: "chart.fix.deltawt.xaxis.label"; raimund@3131: raimund@3131: public static final String I18N_YAXIS_LABEL = raimund@3131: "chart.fix.deltawt.yaxis.label"; raimund@3131: raimund@3131: public static final String I18N_YAXIS_SECOND_LABEL = raimund@3131: "chart.fix.deltawt.yaxis.second.label"; raimund@3131: raimund@3131: raimund@3131: public static enum YAXIS { raimund@3131: dW(0); raimund@3131: protected int idx; raimund@3131: private YAXIS(int c) { raimund@3131: idx = c; raimund@3131: } raimund@3131: } christian@3279: christian@3279: christian@3279: private FLYSArtifact artifact = null; raimund@3131: raimund@3131: raimund@3131: @Override raimund@3131: protected YAxisWalker getYAxisWalker() { raimund@3131: return new YAxisWalker() { raimund@3131: @Override raimund@3131: public int length() { raimund@3131: return YAXIS.values().length; raimund@3131: } raimund@3131: raimund@3131: @Override raimund@3131: public String getId(int idx) { raimund@3131: YAXIS[] yaxes = YAXIS.values(); raimund@3131: return yaxes[idx].toString(); raimund@3131: } raimund@3131: }; raimund@3131: } raimund@3131: raimund@3131: raimund@3131: @Override raimund@3131: protected String getDefaultChartTitle() { raimund@3131: return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: @Override raimund@3131: protected String getDefaultChartSubtitle() { christian@3279: FixationArtifactAccess access = new FixationArtifactAccess(artifact); christian@3279: DateRange range = access.getDateRange(); christian@3279: return Resources.format( christian@3279: context.getMeta(), christian@3279: I18N_CHART_SUBTITLE, christian@3279: "", christian@3279: access.getRiver(), christian@3279: range.getFrom(), christian@3279: range.getTo()); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: /** raimund@3131: * Empty (suppress subtitle). raimund@3131: */ raimund@3131: @Override raimund@3131: protected void addSubtitles(JFreeChart chart) { raimund@3131: String subtitle = getChartSubtitle(); raimund@3131: raimund@3131: if (subtitle != null && subtitle.length() > 0) { raimund@3131: chart.addSubtitle(new TextTitle(subtitle)); raimund@3131: } raimund@3131: } raimund@3131: raimund@3131: raimund@3131: @Override raimund@3131: protected String getDefaultXAxisLabel() { raimund@3131: return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); raimund@3131: } raimund@3131: raimund@3131: @Override raimund@3131: protected String getDefaultYAxisLabel(int pos) { raimund@3131: if (pos == 0) { raimund@3131: return msg(I18N_YAXIS_LABEL, I18N_YAXIS_LABEL); raimund@3131: } raimund@3131: else if (pos == 1) { raimund@3131: return msg(I18N_YAXIS_SECOND_LABEL, I18N_YAXIS_SECOND_LABEL); raimund@3131: } raimund@3131: else { raimund@3131: return "NO TITLE FOR Y AXIS: " + pos; raimund@3131: } raimund@3131: } raimund@3131: raimund@3131: christian@3251: @Override raimund@3131: public void doOut( raimund@3131: ArtifactAndFacet artifactFacet, raimund@3131: Document theme, raimund@3131: boolean visible raimund@3131: ) { raimund@3131: String name = artifactFacet.getFacetName(); raimund@3131: logger.debug("FixDeltaWtGenerator.doOut: " + name); raimund@3131: logger.debug("Theme description is: " + artifactFacet.getFacetDescription()); christian@3279: christian@3279: this.artifact = (FLYSArtifact)artifactFacet.getArtifact(); raimund@3131: raimund@3131: if (name.contains(FIX_SECTOR_AVERAGE_DWT)) { raimund@3131: doSectorAverageOut( raimund@3131: (FLYSArtifact) artifactFacet.getArtifact(), raimund@3131: artifactFacet.getData(context), raimund@3131: artifactFacet.getFacetDescription(), raimund@3131: theme, raimund@3131: visible); raimund@3131: } raimund@3131: else if (name.equals(FIX_REFERENCE_EVENTS_DWT)) { raimund@3131: doReferenceEventsOut( raimund@3131: (FLYSArtifact) artifactFacet.getArtifact(), raimund@3131: artifactFacet.getData(context), raimund@3131: artifactFacet.getFacetDescription(), raimund@3131: theme, raimund@3131: visible); raimund@3131: } raimund@3131: else if (name.equals(FIX_ANALYSIS_EVENTS_DWT)) { raimund@3131: doAnalysisEventsOut( raimund@3131: (FLYSArtifact) artifactFacet.getArtifact(), raimund@3131: artifactFacet.getData(context), raimund@3131: artifactFacet.getFacetDescription(), raimund@3131: theme, raimund@3131: visible); raimund@3131: } raimund@3131: else if (name.equals(FIX_DEVIATION_DWT)) { raimund@3131: doDeviationOut( raimund@3131: (FLYSArtifact) artifactFacet.getArtifact(), raimund@3131: artifactFacet.getData(context), raimund@3131: artifactFacet.getFacetDescription(), raimund@3131: theme, raimund@3131: visible); raimund@3131: } raimund@3131: else if (name.equals(FIX_ANALYSIS_PERIODS_DWT)) { raimund@3131: doAnalysisPeriodsOut( raimund@3131: (FLYSArtifact) artifactFacet.getArtifact(), raimund@3131: artifactFacet.getData(context), raimund@3131: artifactFacet.getFacetDescription(), raimund@3131: theme, raimund@3131: visible); raimund@3131: } raimund@3131: else { raimund@3131: logger.warn("doOut(): unknown facet name: " + name); raimund@3131: return; raimund@3131: } raimund@3131: } raimund@3131: raimund@3131: raimund@3131: protected void doSectorAverageOut( raimund@3131: FLYSArtifact artifact, raimund@3131: Object data, raimund@3131: String desc, raimund@3131: Document theme, raimund@3131: boolean visible) raimund@3131: { raimund@3131: logger.debug("doSectorAverageOut(): description = " + desc); raimund@3131: raimund@3131: QWD qwd = (QWD) data; raimund@3131: TimeSeriesCollection tsc = new TimeSeriesCollection(); raimund@3131: TimeSeries series = new StyledTimeSeries(desc, theme); raimund@3131: raimund@3131: if (qwd == null) { raimund@3131: return; raimund@3131: } raimund@3131: RegularTimePeriod rtp = new Day(qwd.getDate()); felix@3234: double value = qwd.getDeltaW(); raimund@3131: series.add(rtp, value); raimund@3131: tsc.addSeries(series); raimund@3131: raimund@3131: addAxisDataset(tsc, 0, visible); raimund@3168: addAttribute(desc, "outline"); felix@3234: Map annoIdxMap = new HashMap(); felix@3234: annoIdxMap.put (0, new int[]{0,0}); felix@3234: doQWDTextAnnotations(annoIdxMap, tsc, new QWD[]{qwd}, theme, visible); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: protected void doAnalysisEventsOut( raimund@3131: FLYSArtifact artifact, raimund@3131: Object data, raimund@3131: String desc, raimund@3131: Document theme, raimund@3131: boolean visible raimund@3131: ) { raimund@3131: logger.debug("doAnalysisEventsOut: desc = " + desc); raimund@3131: raimund@3131: QWD[] qwds = (QWD[]) data; raimund@3131: TimeSeriesCollection tsc = new TimeSeriesCollection(); raimund@3134: raimund@3134: TimeSeries series = new StyledTimeSeries(desc, theme); raimund@3134: TimeSeries interpol = new StyledTimeSeries(desc + "interpol", theme); raimund@3131: raimund@3131: if (qwds == null) { christian@3212: logger.debug("doAnalysisEventsOut: qwds == null"); raimund@3131: return; raimund@3131: } christian@3212: christian@3212: if (qwds.length == 0) { christian@3212: logger.debug("doAnalysisEventsOut: qwds.length == 0"); christian@3212: return; christian@3212: } christian@3212: christian@3212: Map annoIdxMap = new HashMap(); christian@3212: felix@3237: int idxInterpol = 0; felix@3237: int idxRegular = 0; raimund@3131: for (int i = 0; i < qwds.length; i++) { raimund@3131: if (qwds[i] == null) { christian@3212: logger.debug("doAnalysisEventsOut: qwds[" + i + "] == null"); raimund@3131: continue; raimund@3131: } raimund@3131: RegularTimePeriod rtp = new Day(qwds[i].getDate()); raimund@3131: double value = qwds[i].getDeltaW(); raimund@3134: boolean interpolate = qwds[i].getInterpolated(); raimund@3134: if (interpolate) { raimund@3134: interpol.add(rtp, value); felix@3234: annoIdxMap.put( felix@3234: i, felix@3237: new int[]{1, idxInterpol++}); raimund@3134: } raimund@3134: else { felix@3234: series.add(rtp, value); christian@3212: annoIdxMap.put( christian@3212: i, felix@3237: new int[]{0, idxRegular++}); raimund@3134: } raimund@3131: } raimund@3131: tsc.addSeries(series); raimund@3134: tsc.addSeries(interpol); raimund@3131: addAxisDataset(tsc, 0, visible); raimund@3134: addAttribute(desc + "interpol", "interpolate"); raimund@3168: addAttribute(desc, "outline"); christian@3212: christian@3242: if (visible) { christian@3242: doQWDTextAnnotations(annoIdxMap, tsc, qwds, theme, visible); christian@3242: } christian@3212: } christian@3212: christian@3212: felix@3234: /** felix@3234: * @param annoIdxMap map of index in qwds to series/dataitem indices in tsc. felix@3234: */ christian@3212: protected void doQWDTextAnnotations(Map annoIdxMap, felix@3234: TimeSeriesCollection tsc, QWD[] qwds, Document theme, felix@3234: boolean visible) { christian@3242: logger.debug("doQWDTextAnnotation()"); christian@3242: christian@3242: if (!ThemeUtil.parseShowLineLabel(theme)) { christian@3242: logger.debug("doQWDTextAnnotation: annotation not visible"); felix@3238: return; christian@3242: } christian@3242: christian@3212: List textAnnos = new ArrayList(); christian@3212: Set> entries = annoIdxMap.entrySet(); christian@3242: christian@3212: for(Map.Entry entry : entries) { christian@3212: QWD qwd = qwds[entry.getKey()]; christian@3212: int[] idxs = entry.getValue(); christian@3212: double x = tsc.getXValue(idxs[0], idxs[1]); felix@3234: XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( felix@3234: qwd.getQ() + " m\u00B3/s", felix@3234: x, felix@3234: qwd.getDeltaW()); felix@3234: textAnnos.add(anno); christian@3212: logger.debug("annotation: " + x + "/" + qwd.getDeltaW()); christian@3212: } christian@3212: christian@3251: if(visible) { christian@3251: FLYSAnnotation flysAnno = new FLYSAnnotation(null, null, null, theme); christian@3251: flysAnno.setTextAnnotations(textAnnos); christian@3251: addAnnotations(flysAnno); christian@3251: } raimund@3131: } raimund@3131: raimund@3131: raimund@3131: protected void doReferenceEventsOut( raimund@3131: FLYSArtifact artifact, raimund@3131: Object data, raimund@3131: String desc, raimund@3131: Document theme, raimund@3131: boolean visible raimund@3131: ) { raimund@3131: logger.debug("doReferenceEventsOut: desc = " + desc); raimund@3131: raimund@3131: QWD[] qwds = (QWD[]) data; raimund@3131: TimeSeriesCollection tsc = new TimeSeriesCollection(); raimund@3134: raimund@3134: TimeSeries series = new StyledTimeSeries(desc, theme); raimund@3134: TimeSeries interpol = new StyledTimeSeries(desc + "interpol", theme); raimund@3131: raimund@3131: if (qwds == null) { raimund@3131: return; raimund@3131: } christian@3212: christian@3212: Map annoIdxMap = new HashMap(); christian@3212: felix@3237: int idxInterpol = 0; felix@3237: int idxRegular = 0; raimund@3131: for (int i = 0; i < qwds.length; i++) { raimund@3131: if (qwds[i] == null) { raimund@3131: continue; raimund@3131: } raimund@3131: RegularTimePeriod rtp = new Day(qwds[i].getDate()); raimund@3131: double value = qwds[i].getDeltaW(); raimund@3134: boolean interpolate = qwds[i].getInterpolated(); raimund@3134: if (interpolate) { christian@3251: if(interpol.addOrUpdate(rtp, value) == null) { christian@3251: annoIdxMap.put( christian@3251: i, christian@3251: new int[]{1, idxInterpol}); christian@3251: idxInterpol++; christian@3251: } raimund@3134: } raimund@3134: else { christian@3251: if(series.addOrUpdate(rtp, value) == null) { christian@3251: annoIdxMap.put( christian@3251: i, christian@3251: new int[]{0, idxRegular}); christian@3251: idxRegular++; christian@3251: } raimund@3134: } raimund@3131: } raimund@3131: tsc.addSeries(series); raimund@3134: tsc.addSeries(interpol); raimund@3131: raimund@3131: addAxisDataset(tsc, 0, visible); raimund@3134: addAttribute(desc + "interpol", "interpolate"); raimund@3168: addAttribute(desc, "outline"); christian@3212: felix@3234: doQWDTextAnnotations(annoIdxMap, tsc, qwds, theme, visible); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: protected void doDeviationOut( raimund@3131: FLYSArtifact artifact, raimund@3131: Object data, raimund@3131: String desc, raimund@3131: Document theme, raimund@3131: boolean visible raimund@3131: ) { raimund@3131: logger.debug("doDeviationOut: desc = " + desc); raimund@3131: raimund@3131: if (data == null || !visible) { raimund@3131: logger.debug("no standard deviation"); raimund@3131: return; raimund@3131: } raimund@3131: double[] value = (double[]) data; christian@3254: StyledDomainMarker lower = new StyledDomainMarker((value[0] * -1), 0, theme); christian@3254: StyledDomainMarker upper = new StyledDomainMarker(0, value[0], theme); raimund@3131: raimund@3131: valueMarker.add(lower); raimund@3131: valueMarker.add(upper); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: protected void doAnalysisPeriodsOut( raimund@3131: FLYSArtifact artifact, raimund@3131: Object data, raimund@3131: String desc, raimund@3131: Document theme, raimund@3131: boolean visible raimund@3131: ) { raimund@3131: logger.debug("doHistoricalDischargeDifferenceOut: desc = " + desc); raimund@3131: raimund@3131: DateRange[] ranges = (DateRange[]) data; raimund@3131: if (ranges == null || !visible) { raimund@3131: return; raimund@3131: } raimund@3131: for (int i = 0; i < ranges.length; i++) { raimund@3131: logger.debug("creating domain marker"); raimund@3131: RegularTimePeriod start = new Month(ranges[i].getFrom()); raimund@3131: RegularTimePeriod end = new Month(ranges[i].getTo()); christian@3254: StyledDomainMarker marker = christian@3254: new StyledDomainMarker(start.getMiddleMillisecond(), christian@3254: end.getMiddleMillisecond(), theme); christian@3254: marker.useSecondColor(i % 2 == 0); raimund@3131: domainMarker.add(marker); raimund@3131: } raimund@3131: logger.debug("domainmarkers: " + domainMarker.size()); raimund@3131: } raimund@3131: raimund@3131: raimund@3131: @Override raimund@3131: public void init(Document request, OutputStream out, CallContext context) { raimund@3131: super.init(request, out, context); raimund@3131: raimund@3131: logger.debug("currentKm = " + new Double(getCurrentKmFromRequest())); raimund@3131: context.putContextValue("currentKm", new Double(getCurrentKmFromRequest())); raimund@3131: christian@3254: StyledValueMarker marker = new StyledValueMarker(0, request); raimund@3131: valueMarker.add(marker); raimund@3131: } raimund@3131: raimund@3131: public double getCurrentKmFromRequest() { raimund@3131: Element km = (Element)XMLUtils.xpath( raimund@3131: request, raimund@3131: XPATH_CHART_CURRENTKM, raimund@3131: XPathConstants.NODE, raimund@3131: ArtifactNamespaceContext.INSTANCE); raimund@3131: raimund@3131: if (km == null) { raimund@3131: return -1d; raimund@3131: } raimund@3131: raimund@3131: String uri = ArtifactNamespaceContext.NAMESPACE_URI; raimund@3131: raimund@3131: String currentKm = km.getAttributeNS(uri, "km"); raimund@3131: try { raimund@3131: double d = Double.valueOf(currentKm).doubleValue(); raimund@3131: return d; raimund@3131: } raimund@3131: catch(NumberFormatException nfe) { raimund@3131: return -1d; raimund@3131: } raimund@3131: } raimund@3131: raimund@3131: raimund@3131: } raimund@3131: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 :