001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.control.cyclone;
030
031import java.awt.BorderLayout;
032import java.awt.Dimension;
033import java.awt.Insets;
034import java.awt.event.ActionEvent;
035import java.awt.event.ActionListener;
036import java.util.ArrayList;
037import java.util.Hashtable;
038import java.util.List;
039import java.util.Vector;
040
041import javax.swing.BorderFactory;
042import javax.swing.JButton;
043import javax.swing.JCheckBox;
044import javax.swing.JComponent;
045import javax.swing.JLabel;
046import javax.swing.JList;
047import javax.swing.JPanel;
048import javax.swing.JScrollPane;
049import javax.swing.ListSelectionModel;
050import javax.swing.event.ListSelectionEvent;
051import javax.swing.event.ListSelectionListener;
052
053import ucar.unidata.data.storm.StormDataSource;
054import ucar.unidata.data.storm.StormParam;
055import ucar.unidata.data.storm.StormTrack;
056import ucar.unidata.data.storm.StormTrackPoint;
057import ucar.unidata.data.storm.Way;
058import ucar.unidata.idv.control.chart.LineState;
059import ucar.unidata.idv.control.chart.TimeSeriesChart;
060import ucar.unidata.util.GuiUtils;
061import ucar.unidata.util.Misc;
062import ucar.unidata.util.Range;
063import ucar.unidata.util.TwoFacedObject;
064import visad.DateTime;
065import visad.Real;
066import visad.RealType;
067import visad.Unit;
068
069/**
070 * 
071 * @author Unidata Development Team
072 * @version $Revision$
073 */
074
075public class StormTrackChart {
076
077        /** _more_ */
078        public static final int MODE_FORECASTTIME = 0;
079
080        /** _more_ */
081        public static final int MODE_FORECASTHOUR = 1;
082
083        /** _more_ */
084        private StormDisplayState stormDisplayState;
085
086        /** _more_ */
087        private int mode;
088
089        /** _more_ */
090        private TimeSeriesChart timeSeries;
091
092        /** _more_ */
093        private JPanel chartLeft;
094
095        /** _more_ */
096        private JPanel chartTop;
097
098        /** _more_ */
099        private boolean madeChart = false;
100
101        /** _more_ */
102        private List<DateTime> forecastTimes;
103
104        /** _more_ */
105        private List<Integer> forecastHours;
106
107        /** _more_ */
108        private List<StormParam> chartParams = new ArrayList<StormParam>();
109
110        /** _more_ */
111        private List<Way> chartWays = new ArrayList();
112
113        /** _more_ */
114        private boolean chartDifference = false;
115
116        /** _more_ */
117        private JList chartTimeBox;
118
119        /** _more_ */
120        private boolean ignoreChartTimeChanges = false;
121
122        /** _more_ */
123        private JComponent contents;
124
125        /** _more_ */
126        private String name;
127
128        /**
129         * _more_
130         */
131        public StormTrackChart() {
132        }
133
134        /**
135         * _more_
136         * 
137         * @param stormDisplayState
138         *            _more_
139         * @param name
140         *            _more_
141         * 
142         */
143        public StormTrackChart(StormDisplayState stormDisplayState, String name) {
144                this(stormDisplayState, name, MODE_FORECASTTIME);
145        }
146
147        /**
148         * _more_
149         * 
150         * @param stormDisplayState
151         *            _more_
152         * @param name
153         *            _more_
154         * @param mode
155         *            _more_
156         */
157        public StormTrackChart(StormDisplayState stormDisplayState, String name,
158                        int mode) {
159                this.stormDisplayState = stormDisplayState;
160                this.name = name;
161                this.mode = mode;
162        }
163
164        /**
165         * _more_
166         * 
167         * @return _more_
168         */
169        protected boolean isHourly() {
170                return mode == MODE_FORECASTHOUR;
171        }
172
173        /**
174         * _more_
175         */
176        public void deactivate() {
177                madeChart = false;
178                contents = null;
179        }
180
181        /**
182         * _more_
183         * 
184         * @return _more_
185         */
186        protected JComponent getContents() {
187                if (contents == null) {
188                        contents = doMakeContents();
189                }
190                return contents;
191        }
192
193        /**
194         * _more_
195         * 
196         * @return _more_
197         */
198        private JComponent doMakeContents() {
199                chartTop = new JPanel(new BorderLayout());
200                chartLeft = new JPanel(new BorderLayout());
201                JComponent chartComp = GuiUtils.leftCenter(chartLeft, GuiUtils
202                                .topCenter(chartTop, getChart().getContents()));
203                return chartComp;
204        }
205
206        /**
207         * Get the chart
208         * 
209         * @return The chart_
210         */
211        public TimeSeriesChart getChart() {
212                if (timeSeries == null) {
213                        timeSeries = new TimeSeriesChart(stormDisplayState
214                                        .getStormTrackControl(), "Track Charts") {
215                                protected void makeInitialChart() {
216                                }
217                        };
218                        // TODO make this work:
219                        // timeSeries.setAlwaysShowFirstChart(false);
220                        timeSeries.showAnimationTime(true);
221                        timeSeries.setDateFormat("MM/dd HH:mm z");
222                }
223                return timeSeries;
224        }
225
226        /**
227         * _more_
228         * 
229         * @param time
230         *            _more_
231         */
232        protected void timeChanged(Real time) {
233                getChart().timeChanged();
234        }
235
236        /**
237         * _more_
238         * 
239         * @return _more_
240         */
241        private List<DateTime> findForecastTimes() {
242                List<DateTime> forecastTimes = new ArrayList<DateTime>();
243                Hashtable seenForecastTime = new Hashtable();
244                for (StormTrack track : stormDisplayState.getTrackCollection()
245                                .getTracks()) {
246                        if (track.getWay().isObservation()) {
247                                continue;
248                        }
249                        if (!chartWays.contains(track.getWay())) {
250                                continue;
251                        }
252                        DateTime dttm = track.getStartTime();
253                        if (seenForecastTime.get(dttm) == null) {
254                                seenForecastTime.put(dttm, dttm);
255                                forecastTimes.add(dttm);
256                        }
257                }
258                return (List<DateTime>) Misc.sort(forecastTimes);
259        }
260
261        /**
262         * _more_
263         * 
264         * @return _more_
265         */
266        private List<Integer> findForecastHours() {
267                List<Integer> forecastHours = new ArrayList<Integer>();
268                Hashtable seenForecastHour = new Hashtable();
269                Hashtable seen = new Hashtable();
270                for (StormTrack track : stormDisplayState.getTrackCollection()
271                                .getTracks()) {
272                        if (track.getWay().isObservation()) {
273                                continue;
274                        }
275                        if (!chartWays.contains(track.getWay())) {
276                                continue;
277                        }
278                        for (StormTrackPoint stormTrackPoint : track.getTrackPoints()) {
279                                Integer forecastHour = new Integer(stormTrackPoint
280                                                .getForecastHour());
281                                if (seenForecastHour.get(forecastHour) == null) {
282                                        seenForecastHour.put(forecastHour, forecastHour);
283                                        forecastHours.add(forecastHour);
284                                }
285                        }
286                }
287                return (List<Integer>) Misc.sort(forecastHours);
288        }
289
290        /**
291         * _more_
292         */
293        protected void createChart() {
294
295                if (madeChart) {
296                        return;
297                }
298                madeChart = true;
299                final JCheckBox chartDiffCbx = new JCheckBox("Use Difference",
300                                chartDifference);
301                chartDiffCbx.addActionListener(new ActionListener() {
302                        public void actionPerformed(ActionEvent ae) {
303                                chartDifference = chartDiffCbx.isSelected();
304                                updateChart();
305                        }
306                });
307
308                chartTimeBox = new JList();
309                chartTimeBox.setVisibleRowCount(3);
310                chartTimeBox
311                                .setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
312                chartTimeBox.addListSelectionListener(new ListSelectionListener() {
313                        public void valueChanged(ListSelectionEvent e) {
314                                if (ignoreChartTimeChanges) {
315                                        return;
316                                }
317
318                                updateChart();
319                        }
320                });
321
322                List<StormParam> params = getStormTrackParams();
323
324                Insets inset = new Insets(3, 7, 7, 0);
325                List chartComps = new ArrayList();
326
327                List<Way> ways = Misc.sort(stormDisplayState.getTrackCollection()
328                                .getWayList());
329                List wayComps = new ArrayList();
330                for (Way way : ways) {
331                        final Way theWay = way;
332                        if (way.isObservation() && !chartWays.contains(way)) {
333                                chartWays.add(way);
334                        }
335                        final JCheckBox cbx = new JCheckBox(way.toString(), chartWays
336                                        .contains(theWay));
337                        cbx.addActionListener(new ActionListener() {
338                                public void actionPerformed(ActionEvent ae) {
339                                        if (cbx.isSelected()) {
340                                                addChartWay(theWay);
341                                        } else {
342                                                removeChartWay(theWay);
343                                        }
344                                }
345                        });
346                        if (!way.isObservation()) {
347                                wayComps.add(cbx);
348                        } else {
349                                wayComps.add(0, cbx);
350                        }
351                }
352
353                chartComps.add(new JLabel(stormDisplayState.getStormTrackControl()
354                                .getWaysName()
355                                + ":"));
356                JComponent chartWayComp = GuiUtils.vbox(wayComps);
357                if (wayComps.size() > 6) {
358                        chartWayComp = makeScroller(chartWayComp, 100, 150);
359                }
360                chartComps.add(GuiUtils.inset(chartWayComp, inset));
361                chartComps.add(GuiUtils.lLabel((isHourly() ? "Forecast Hour:"
362                                : "Forecast Time:")));
363                JScrollPane sp = new JScrollPane(chartTimeBox);
364                chartComps.add(GuiUtils.inset(sp, inset));
365
366                List paramComps = new ArrayList();
367                for (StormParam param : params) {
368                        // if (param.getIsChartParam() == false) {
369                        // continue;
370                        // }
371                        final StormParam theParam = param;
372                        boolean useChartParam = chartParams.contains(theParam);
373                        final JCheckBox cbx = new JCheckBox(param.toString(), useChartParam);
374                        cbx.addActionListener(new ActionListener() {
375                                public void actionPerformed(ActionEvent ae) {
376                                        if (cbx.isSelected()) {
377                                                addChartParam(theParam);
378                                        } else {
379                                                removeChartParam(theParam);
380                                        }
381                                }
382                        });
383                        paramComps.add(cbx);
384                }
385                chartComps.add(new JLabel("Parameters:"));
386                JComponent paramComp = GuiUtils.vbox(paramComps);
387                if (paramComps.size() > 6) {
388                        paramComp = makeScroller(paramComp, 100, 150);
389                }
390                chartComps.add(GuiUtils.inset(paramComp, inset));
391                chartComps.add(chartDiffCbx);
392
393                JButton removeBtn = GuiUtils.makeButton("Remove Chart", this,
394                                "removeChart");
395                chartComps.add(GuiUtils.filler(5, 10));
396                chartComps.add(removeBtn);
397
398                // JComponent top = GuiUtils.left(GuiUtils.hbox(
399                // GuiUtils.label("Forecast Time: ", chartTimeBox),
400                // chartDiffCbx));
401                // top = GuiUtils.inset(top,5);
402                // chartTop.add(BorderLayout.NORTH, top);
403                JComponent left = GuiUtils.doLayout(chartComps, 1, GuiUtils.WT_N,
404                                new double[] { 0, 1, 0, 1, 0 });
405                chartLeft.add(BorderLayout.CENTER, GuiUtils.inset(left, 5));
406
407                chartLeft.invalidate();
408                chartLeft.validate();
409                chartLeft.repaint();
410
411        }
412
413        /**
414         * _more_
415         * 
416         * @return _more_
417         */
418        protected List getStormTrackParams() {
419                // Get the types from the first forecast track
420                List<StormParam> params = stormDisplayState.getStormChartParams();
421                if ((params == null) || (params.size() == 0)) {
422                        for (StormTrack track : stormDisplayState.getTrackCollection()
423                                        .getTracks()) {
424                                if (track == null) {
425                                        continue;
426                                }
427                                if (!track.isObservation()) {
428                                        params = track.getParams();
429                                        break;
430                                }
431                        }
432
433                        // If we didn't get any from the forecast track use the obs track
434                        if (params.size() == 0) {
435                                StormTrack obsTrack = stormDisplayState.getTrackCollection()
436                                                .getObsTrack();
437                                if (obsTrack != null) {
438                                        params = obsTrack.getParams();
439                                }
440                        }
441                }
442                return params;
443
444        }
445
446        /**
447         * _more_
448         */
449        public void removeChart() {
450                if (GuiUtils.askOkCancel("Remove Chart",
451                                "Do you want to remove this chart?")) {
452                        stormDisplayState.removeChart(this);
453
454                }
455
456        }
457
458        /**
459         * _more_
460         * 
461         * @param comp
462         *            _more_
463         * @param width
464         *            _more_
465         * @param height
466         *            _more_
467         * 
468         * @return _more_
469         */
470        JScrollPane makeScroller(JComponent comp, int width, int height) {
471                JScrollPane scroller = GuiUtils.makeScrollPane(comp, width, height);
472                scroller.setBorder(BorderFactory.createLoweredBevelBorder());
473                scroller.setPreferredSize(new Dimension(width, height));
474                scroller.setMinimumSize(new Dimension(width, height));
475                return scroller;
476        }
477
478        /**
479         * _more_
480         * 
481         * @param stormTrack
482         *            _more_
483         * @param param
484         *            _more_
485         * 
486         * @return _more_
487         */
488        protected LineState makeLine(StormTrack stormTrack, StormParam param) {
489                List<Real> values = new ArrayList<Real>();
490                List<DateTime> times = stormTrack.getTrackTimes();
491                List<StormTrackPoint> trackPoints = stormTrack.getTrackPoints();
492                double min = 0;
493                double max = 0;
494                Unit unit = null;
495                for (int pointIdx = 0; pointIdx < times.size(); pointIdx++) {
496                        Real value = trackPoints.get(pointIdx).getAttribute(param);
497                        if (value == null) {
498                                continue;
499                        }
500                        if (unit == null) {
501                                unit = ((RealType) value.getType()).getDefaultUnit();
502                        }
503                        values.add(value);
504                        double dvalue = value.getValue();
505                        // System.err.print(","+dvalue);
506                        if ((pointIdx == 0) || (dvalue > max)) {
507                                max = dvalue;
508                        }
509                        if ((pointIdx == 0) || (dvalue < min)) {
510                                min = dvalue;
511                        }
512                }
513                if (values.size() == 0) {
514                        return null;
515                }
516                // System.err.println("");
517                String paramLabel = param.toString();
518                String label = stormTrack.getWay().toString(); // +":" + paramLabel;
519                LineState lineState = new LineState();
520                lineState.setRangeIncludesZero(true);
521                if (stormTrack.getWay().isObservation()) {
522                        lineState.setWidth(2);
523                } else {
524                        lineState.setWidth(1);
525                }
526                lineState.setRange(new Range(min, max));
527                lineState.setChartName(paramLabel);
528                lineState.setAxisLabel("[" + unit + "]");
529
530                // System.err.println (param + " " +
531                // StormDataSource.TYPE_STORMCATEGORY);
532                if (Misc.equals(param, StormDataSource.PARAM_STORMCATEGORY)) {
533                        // lineState.setShape(LineState.LINETYPE_BAR);
534                        lineState.setLineType(LineState.LINETYPE_BAR);
535                        lineState.setLineType(LineState.LINETYPE_AREA);
536                } else {
537                        lineState.setLineType(LineState.LINETYPE_SHAPES_AND_LINES);
538                        lineState.setShape(LineState.SHAPE_LARGEPOINT);
539                }
540
541                lineState.setColor(stormDisplayState.getWayDisplayState(
542                                stormTrack.getWay()).getColor());
543                lineState.setName(label);
544                lineState.setTrack(times, values);
545                return lineState;
546
547        }
548
549        /**
550         * _more_
551         * 
552         * 
553         * @param param
554         *            _more_
555         */
556        private void removeChartParam(StormParam param) {
557                while (chartParams.contains(param)) {
558                        chartParams.remove(param);
559                }
560                updateChart();
561        }
562
563        /**
564         * _more_
565         * 
566         * 
567         * @param param
568         *            _more_
569         */
570        private void addChartParam(StormParam param) {
571                if (!chartParams.contains(param)) {
572                        chartParams.add(param);
573                }
574                updateChart();
575        }
576
577        /**
578         * _more_
579         * 
580         * @param way
581         *            _more_
582         */
583        private void removeChartWay(Way way) {
584                while (chartWays.contains(way)) {
585                        chartWays.remove(way);
586                }
587                updateChart();
588        }
589
590        /**
591         * _more_
592         * 
593         * @param way
594         *            _more_
595         */
596        private void addChartWay(Way way) {
597                if (!chartWays.contains(way)) {
598                        chartWays.add(way);
599                }
600                updateChart();
601        }
602
603        /**
604         * _more_
605         */
606        private void getSelectedTimes() {
607                if (isHourly()) {
608                        Object[] selects = chartTimeBox.getSelectedValues();
609                        if (forecastHours == null) {
610                                forecastHours = new ArrayList();
611                        }
612                        for (int i = 0; i < selects.length; i++) {
613                                Object select = selects[i];
614                                TwoFacedObject tfo = (TwoFacedObject) select;
615                                Integer hour = (Integer) tfo.getId();
616                                forecastHours.add(hour);
617                        }
618
619                } else {
620                        forecastTimes = (List<DateTime>) Misc.toList(chartTimeBox
621                                        .getSelectedValues());
622
623                }
624        }
625
626        /**
627         * _more_
628         */
629        protected void updateChart() {
630
631                try {
632                        if (!madeChart) {
633                                createChart();
634                        }
635                        ignoreChartTimeChanges = true;
636
637                        if (isHourly()) {
638                                List<Integer> fHours = findForecastHours();
639                                List<TwoFacedObject> tfos = new ArrayList<TwoFacedObject>();
640                                for (Integer i : fHours) {
641                                        tfos.add(new TwoFacedObject(i + "H", i));
642                                }
643
644                                Object[] selected = chartTimeBox.getSelectedValues();
645                                chartTimeBox.setListData(new Vector(tfos));
646                                GuiUtils.setSelectedItems(chartTimeBox, Misc.toList(selected));
647
648                                if ((selected == null) && (tfos.size() > 0)) {
649                                        TwoFacedObject selected0 = tfos.get(0);
650                                        forecastHours.add((Integer) selected0.getId());
651                                }
652
653                                // chartTimeBox.setSelectedItem(selected);
654                        } else {
655                                List<DateTime> fTimes = findForecastTimes();
656
657                                Object[] selected = chartTimeBox.getSelectedValues();
658
659                                chartTimeBox.setListData(new Vector(fTimes));
660                                GuiUtils.setSelectedItems(chartTimeBox, Misc.toList(selected));
661
662                                if ((selected == null) && (fTimes.size() > 0)) {
663                                        DateTime dt0 = fTimes.get(0);
664                                        forecastTimes.add(dt0);
665                                }
666
667                                // chartTimeBox.setSelectedItem(forecastTime);
668                        }
669                        ignoreChartTimeChanges = false;
670                        getSelectedTimes();
671                        chartTimeBox.repaint();
672                        Hashtable<Way, List> wayToTracks = new Hashtable<Way, List>();
673                        for (Way way : chartWays) {
674                                wayToTracks.put(way, new ArrayList<Way>());
675                        }
676
677                        List<StormTrack> tracksToUse = new ArrayList<StormTrack>();
678                        for (StormTrack track : stormDisplayState.getTrackCollection()
679                                        .getTracks()) {
680                                List trackList = wayToTracks.get(track.getWay());
681                                if (trackList == null) {
682                                        continue;
683                                }
684                                if (track.getWay().isObservation()) {
685                                        tracksToUse.add(track);
686                                } else {
687                                        trackList.add(track);
688                                }
689                        }
690
691                        StormTrack obsTrack = stormDisplayState.getTrackCollection()
692                                        .getObsTrack();
693
694                        if (isHourly()) {
695                                for (Way way : chartWays) {
696                                        List<StormTrack> tracksFromWay = wayToTracks.get(way);
697
698                                        for (Integer fHour : forecastHours) {
699                                                List<StormTrackPoint> points = new ArrayList<StormTrackPoint>();
700                                                for (StormTrack track : tracksFromWay) {
701                                                        StormTrackPoint stp = track
702                                                                        .findPointWithForecastHour(fHour.intValue());
703                                                        if (stp != null) {
704                                                                // TODO: What time do we use???
705                                                                points.add(stp);
706                                                        }
707
708                                                }
709                                                if (points.size() > 0) {
710                                                        points = (List<StormTrackPoint>) Misc.sort(points);
711                                                        tracksToUse.add(new StormTrack(stormDisplayState
712                                                                        .getStormInfo(), way, points, null));
713                                                }
714                                        }
715                                }
716
717                        } else {
718                                for (Way way : chartWays) {
719                                        List<StormTrack> tracksFromWay = wayToTracks.get(way);
720                                        for (StormTrack track : tracksFromWay) {
721                                                for (DateTime fTime : forecastTimes) {
722                                                        if (Misc.equals(fTime, track.getStartTime())) {
723                                                                tracksToUse.add(track);
724                                                        }
725                                                }
726                                        }
727                                }
728                        }
729
730                        List<LineState> lines = new ArrayList<LineState>();
731
732                        for (StormParam param : chartParams) {
733                                Hashtable seenWays = new Hashtable();
734                                List<LineState> linesForParam = new ArrayList<LineState>();
735                                for (StormTrack track : tracksToUse) {
736                                        LineState lineState = null;
737                                        if (chartDifference && param.getCanDoDifference()) {
738                                                if (track.getWay().isObservation()) {
739                                                        continue;
740                                                }
741                                                track = StormDataSource.difference(obsTrack, track,
742                                                                param);
743                                                if (track != null) {
744                                                        lineState = makeLine(track, param);
745                                                }
746                                        } else {
747                                                lineState = makeLine(track, param);
748                                        }
749                                        if (lineState == null) {
750                                                continue;
751                                        }
752                                        // Only add it if there are values
753                                        if (lineState.getRange().getMin() == lineState.getRange()
754                                                        .getMin()) {
755                                                if (seenWays.get(track.getWay()) != null) {
756                                                        lineState.setVisibleInLegend(false);
757                                                } else {
758                                                        seenWays.put(track.getWay(), "");
759                                                }
760
761                                                linesForParam.add(lineState);
762                                        }
763                                }
764                                double max = Double.NEGATIVE_INFINITY;
765                                double min = Double.POSITIVE_INFINITY;
766                                ;
767                                for (LineState lineState : linesForParam) {
768                                        Range r = lineState.getRange();
769                                        min = Math.min(min, r.getMin());
770                                        max = Math.max(max, r.getMax());
771                                }
772                                // System.err.println(param + " min/max:" + min + "/" + max);
773                                boolean first = true;
774                                for (LineState lineState : linesForParam) {
775                                        lineState.setAxisVisible(first);
776                                        first = false;
777                                        lineState.setRange(new Range(min, max));
778                                }
779                                lines.addAll(linesForParam);
780                        }
781                        getChart().setTracks(lines);
782                } catch (Exception exc) {
783                        stormDisplayState.getStormTrackControl().logException(
784                                        "Updating chart", exc);
785                }
786
787        }
788
789        /**
790         * Set the ChartParams property.
791         * 
792         * @param value
793         *            The new value for ChartParams
794         */
795        public void setChartParams(List<StormParam> value) {
796                chartParams = value;
797        }
798
799        /**
800         * Get the ChartParams property.
801         * 
802         * @return The ChartParams
803         */
804        public List<StormParam> getChartParams() {
805                return chartParams;
806        }
807
808        /**
809         * Set the ChartWays property.
810         * 
811         * @param value
812         *            The new value for ChartWays
813         */
814        public void setChartWays(List<Way> value) {
815                chartWays = value;
816        }
817
818        /**
819         * Get the ChartWays property.
820         * 
821         * @return The ChartWays
822         */
823        public List<Way> getChartWays() {
824                return chartWays;
825        }
826
827        /**
828         * Set the ChartForecastTime property.
829         * 
830         * @param value
831         *            The new value for ChartForecastTime
832         */
833        public void setForecastTime(DateTime value) {
834                forecastTimes = (List<DateTime>) Misc.newList(value);
835        }
836
837        /**
838         * _more_
839         * 
840         * @param value
841         *            _more_
842         */
843        public void setForecastTimes(List<DateTime> value) {
844                forecastTimes = value;
845        }
846
847        /**
848         * _more_
849         * 
850         * @return _more_
851         */
852        public List<DateTime> getForecastTimes() {
853                return forecastTimes;
854        }
855
856        /**
857         * Set the ChartDifference property.
858         * 
859         * @param value
860         *            The new value for ChartDifference
861         */
862        public void setChartDifference(boolean value) {
863                chartDifference = value;
864        }
865
866        /**
867         * Get the ChartDifference property.
868         * 
869         * @return The ChartDifference
870         */
871        public boolean getChartDifference() {
872                return chartDifference;
873        }
874
875        /**
876         * Set the Name property.
877         * 
878         * @param value
879         *            The new value for Name
880         */
881        public void setName(String value) {
882                name = value;
883        }
884
885        /**
886         * Get the Name property.
887         * 
888         * @return The Name
889         */
890        public String getName() {
891                return name;
892        }
893
894        /**
895         * Set the StormDisplayState property.
896         * 
897         * @param value
898         *            The new value for StormDisplayState
899         */
900        public void setStormDisplayState(StormDisplayState value) {
901                stormDisplayState = value;
902        }
903
904        /**
905         * Get the StormDisplayState property.
906         * 
907         * @return The StormDisplayState
908         */
909        public StormDisplayState getStormDisplayState() {
910                return stormDisplayState;
911        }
912
913        /**
914         * Set the Mode property.
915         * 
916         * @param value
917         *            The new value for Mode
918         */
919        public void setMode(int value) {
920                mode = value;
921        }
922
923        /**
924         * Get the Mode property.
925         * 
926         * @return The Mode
927         */
928        public int getMode() {
929                return mode;
930        }
931
932        /**
933         * Set the ForecastHour property.
934         * 
935         * @param value
936         *            The new value for ForecastHour
937         */
938        public void setForecastHour(int value) {
939                forecastHours = (List<Integer>) Misc.newList(new Integer(value));
940        }
941
942        /**
943         * _more_
944         * 
945         * @param value
946         *            _more_
947         */
948        public void setForecastHours(List<Integer> value) {
949                forecastHours = value;
950        }
951
952        /**
953         * _more_
954         * 
955         * @return _more_
956         */
957        public List<Integer> getForecastHours() {
958                return forecastHours;
959        }
960}