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.data.cyclone;
030
031import java.io.File;
032import java.sql.Connection;
033import java.sql.DriverManager;
034import java.sql.ResultSet;
035import java.sql.SQLException;
036import java.sql.Statement;
037import java.util.ArrayList;
038import java.util.Calendar;
039import java.util.GregorianCalendar;
040import java.util.HashMap;
041import java.util.Hashtable;
042import java.util.List;
043import java.util.Map;
044
045import ucar.unidata.data.BadDataException;
046import ucar.unidata.data.DataSourceDescriptor;
047import ucar.unidata.data.DataUtil;
048import ucar.unidata.sql.SqlUtil;
049import ucar.unidata.util.DateUtil;
050import ucar.unidata.util.IOUtil;
051import ucar.unidata.util.Misc;
052import ucar.visad.Util;
053import visad.CommonUnit;
054import visad.DateTime;
055import visad.Real;
056import visad.RealType;
057import visad.VisADException;
058import visad.georef.EarthLocation;
059import visad.georef.EarthLocationLite;
060
061/**
062 * Created by IntelliJ IDEA. User: yuanho Date: Apr 9, 2008 Time: 4:58:27 PM To
063 * change this template use File | Settings | File Templates.
064 */
065public class STIStormDataSource extends StormDataSource {
066
067        /** _more_ */
068        private static final Way DEFAULT_OBSERVATION_WAY = new Way("babj");
069
070        /* Use this for mysql: */
071
072        /** _more_ */
073        private static final String DEFAULT_URL = "jdbc:mysql://localhost:3306/typhoon?zeroDateTimeBehavior=convertToNull&user=yuanho&password=password";
074
075        // private static final String DEFAULT_URL =
076        // "jdbc:mysql://localhost:3306/typhoon?zeroDateTimeBehavior=convertToNull&user=yuanho&password=password";
077
078        /** _more_ */
079        private static final String DEFAULT_DERBY_URL = "jdbc:derby:test;create=true";
080
081        /** _more_ */
082        private static final String COL_DERBY_HOUR = "hh";
083
084        /** _more_ */
085        private static final String COL_DERBY_YEAR = "yyyy";
086
087        /**
088         * _more_
089         * 
090         * @return _more_
091         */
092        private boolean useDerby() {
093                if ((dbUrl != null) && (dbUrl.indexOf("derby") >= 0)) {
094                        return true;
095                }
096                return false;
097        }
098
099        /**
100         * _more_
101         * 
102         * @return _more_
103         */
104        public String getId() {
105                return "sti";
106        }
107
108        /**
109         * _more_
110         * 
111         * @return _more_
112         */
113        private String getColHour() {
114                if (useDerby()) {
115                        return COL_DERBY_HOUR;
116                }
117                return COL_TYPHOON_HOUR;
118        }
119
120        /**
121         * _more_
122         * 
123         * @return _more_
124         */
125        private String getColYear() {
126                if (useDerby()) {
127                        return COL_DERBY_YEAR;
128                }
129                return COL_TYPHOON_YEAR;
130        }
131
132        /** _more_ */
133        public static StormParam PARAM_MAXWINDSPEED;
134
135        /** _more_ */
136        public static StormParam PARAM_RADIUSMODERATEGALE;
137
138        /** _more_ */
139        public static StormParam PARAM_RADIUSWHOLEGALE;
140
141        /** _more_ */
142        public static StormParam PARAM_PROBABILITY10RADIUS;
143
144        /** _more_ */
145        public static StormParam PARAM_PROBABILITY20RADIUS;
146
147        /** _more_ */
148        public static StormParam PARAM_PROBABILITY30RADIUS;
149
150        /** _more_ */
151        public static StormParam PARAM_PROBABILITY40RADIUS;
152
153        /** _more_ */
154        public static StormParam PARAM_PROBABILITY50RADIUS;
155
156        /** _more_ */
157        public static StormParam PARAM_PROBABILITY60RADIUS;
158
159        /** _more_ */
160        public static StormParam PARAM_PROBABILITY70RADIUS;
161
162        /** _more_ */
163        public static StormParam PARAM_PROBABILITY80RADIUS;
164
165        /** _more_ */
166        public static StormParam PARAM_PROBABILITY90RADIUS;
167
168        /** _more_ */
169        public static StormParam PARAM_DISTANCE_ERROR;
170
171        /** _more_ */
172        public static StormParam PARAM_PROBABILITY100RADIUS;
173
174        /** _more_ */
175        public static StormParam PARAM_PROBABILITYRADIUS;
176
177        /** _more_ */
178        public static StormParam PARAM_MOVEDIRECTION;
179
180        /** _more_ */
181        public static StormParam PARAM_MOVESPEED;
182
183        /** _more_ */
184        private static float MISSING = 9999.0f;
185
186        /** _more_ */
187        private static final String ZEROHOUR = "0";
188
189        /** _more_ */
190        private static final String TABLE_TRACK = "typhoon";
191
192        /** _more_ */
193        private static final String COL_TYPHOON_YEAR = "year";
194
195        /** _more_ */
196        private static final String COL_TYPHOON_HOUR = "hour";
197        /**/
198
199        /** _more_ */
200        private static final String COL_TYPHOON_STORMID = "nno";
201
202        /** _more_ */
203        private static final String COL_TYPHOON_TIME = "time";
204
205        /** _more_ */
206        private static final String COL_TYPHOON_LATITUDE = "lat";
207
208        /** _more_ */
209        private static final String COL_TYPHOON_LONGITUDE = "lon";
210
211        /** _more_ */
212        private static final String COL_TYPHOON_MONTH = "mon";
213
214        /** _more_ */
215        private static final String COL_TYPHOON_DAY = "day";
216
217        /** _more_ */
218        private static final String COL_TYPHOON_FHOUR = "fhour";
219
220        /** _more_ */
221        private static final String COL_TYPHOON_WAY = "way";
222
223        /** _more_ */
224        private static final String COL_TYPHOON_PRESSURE = "pressure";
225
226        /** _more_ */
227        private static final String COL_TYPHOON_WINDSPEED = "wind";
228
229        /** _more_ */
230        private static final String COL_TYPHOON_RADIUSMG = "xx1";
231
232        /** _more_ */
233        private static final String COL_TYPHOON_RADIUSWG = "xx2";
234
235        /** _more_ */
236        private static final String COL_TYPHOON_MOVEDIR = "xx3";
237
238        /** _more_ */
239        private static final String COL_TYPHOON_MOVESPEED = "xx4";
240
241        /** _more_ */
242        private static final String TABLE_PROBILITY = "probility";
243
244        /** _more_ */
245        private static final String COL_PROBILITY_WAYNAME = "wayname";
246
247        /** _more_ */
248        private static final String COL_PROBILITY_FHOUR = "fhour";
249
250        /** _more_ */
251        private static final String COL_PROBILITY_P10 = "p10";
252
253        /** _more_ */
254        private static final String COL_PROBILITY_P20 = "p20";
255
256        /** _more_ */
257        private static final String COL_PROBILITY_P30 = "p30";
258
259        /** _more_ */
260        private static final String COL_PROBILITY_P40 = "p40";
261
262        /** _more_ */
263        private static final String COL_PROBILITY_P50 = "p50";
264
265        /** _more_ */
266        private static final String COL_PROBILITY_P60 = "p60";
267
268        /** _more_ */
269        private static final String COL_PROBILITY_P70 = "p70";
270
271        /** _more_ */
272        private static final String COL_PROBILITY_P80 = "p80";
273
274        /** _more_ */
275        private static final String COL_PROBILITY_P90 = "p90";
276
277        /** _more_ */
278        private static final String COL_PROBILITY_P100 = "p100";
279
280        /** _more_ */
281        private static final String COL_DISTANCE_ERROR = "error";
282
283        /** _more_ */
284        private static final String COL_PROBILITY_REMARK = "remark";
285
286        /** _more_ */
287        private String dbUrl;
288
289        /** the db connection */
290        private Connection connection;
291
292        /** _more_ */
293        private String fromDate = "-1 year";
294
295        /** _more_ */
296        private String toDate = "now";
297
298        /** the stormInfo and track */
299        private List<StormInfo> stormInfos;
300
301        /** _more_ */
302        private HashMap<String, float[]> wayfhourToRadius;
303
304        /**
305         * constructor of sti storm data source
306         * 
307         * 
308         * @throws Exception
309         *             _more_
310         */
311
312        public STIStormDataSource() throws Exception {
313        }
314
315        /**
316         * _more_
317         * 
318         * @return _more_
319         */
320        public boolean isEditable() {
321                return true;
322        }
323
324        static {
325                try {
326                        // TODO: Make sure these are the right units
327                        PARAM_MAXWINDSPEED = new StormParam(makeRealType("maxwindspeed",
328                                        "Max_Windspeed", Util.parseUnit("m/s")));
329                        PARAM_RADIUSMODERATEGALE = new StormParam(makeRealType(
330                                        "radiusmoderategale", "Radius_of_Beaufort_Scale7", DataUtil
331                                                        .parseUnit("km")));
332                        PARAM_RADIUSWHOLEGALE = new StormParam(makeRealType(
333                                        "radiuswholegale", "Radius_of_Beaufort_Scale10", DataUtil
334                                                        .parseUnit("km")));
335                        PARAM_MOVEDIRECTION = new StormParam(makeRealType("movedirection",
336                                        "Storm_Direction", CommonUnit.degree));
337                        PARAM_MOVESPEED = new StormParam(makeRealType("movespeed",
338                                        "Storm_Speed", Util.parseUnit("m/s")));
339
340                        PARAM_PROBABILITY10RADIUS = new StormParam(makeRealType(
341                                        "probabilityradius10", "Probability_10%_Radius", DataUtil
342                                                        .parseUnit("km")), true, false, false);
343                        PARAM_PROBABILITY20RADIUS = new StormParam(makeRealType(
344                                        "probabilityradius20", "Probability_20%_Radius", DataUtil
345                                                        .parseUnit("km")), true, false, false);
346                        PARAM_PROBABILITY30RADIUS = new StormParam(makeRealType(
347                                        "probabilityradius30", "Probability_30%_Radius", DataUtil
348                                                        .parseUnit("km")), true, false, false);
349                        PARAM_PROBABILITY40RADIUS = new StormParam(makeRealType(
350                                        "probabilityradius40", "Probability_40%_Radius", DataUtil
351                                                        .parseUnit("km")), true, false, false);
352                        PARAM_PROBABILITY50RADIUS = new StormParam(makeRealType(
353                                        "probabilityradius50", "Probability_50%_Radius", DataUtil
354                                                        .parseUnit("km")), true, false, false);
355                        PARAM_PROBABILITY60RADIUS = new StormParam(makeRealType(
356                                        "probabilityradius60", "Probability_60%_Radius", DataUtil
357                                                        .parseUnit("km")), true, false, false);
358                        PARAM_PROBABILITY70RADIUS = new StormParam(makeRealType(
359                                        "probabilityradius70", "Probability_70%_Radius", DataUtil
360                                                        .parseUnit("km")), true, false, false);
361                        PARAM_PROBABILITY80RADIUS = new StormParam(makeRealType(
362                                        "probabilityradius80", "Probability_80%_Radius", DataUtil
363                                                        .parseUnit("km")), true, false, false);
364                        PARAM_PROBABILITY90RADIUS = new StormParam(makeRealType(
365                                        "probabilityradius90", "Probability_90%_Radius", DataUtil
366                                                        .parseUnit("km")), true, false, false);
367                        PARAM_PROBABILITY100RADIUS = new StormParam(makeRealType(
368                                        "probabilityradius100", "Probability_100%_Radius", DataUtil
369                                                        .parseUnit("km")), true, false, false);
370                        PARAM_DISTANCE_ERROR = new StormParam(makeRealType(
371                                        "meanDistanceError", "Mean_Distance_Error", DataUtil
372                                                        .parseUnit("km")), true, false, false);
373                } catch (Exception exc) {
374                        System.err.println("Error creating storm params:" + exc);
375                        exc.printStackTrace();
376
377                }
378        }
379
380        /**
381         * _more_
382         * 
383         * @throws VisADException
384         *             _more_
385         */
386        protected void initParams() throws VisADException {
387                super.initParams();
388
389                obsParams = new StormParam[] { PARAM_MAXWINDSPEED, PARAM_MINPRESSURE,
390                                PARAM_RADIUSMODERATEGALE, PARAM_RADIUSWHOLEGALE,
391                                PARAM_MOVEDIRECTION, PARAM_MOVESPEED };
392
393                forecastParams = new StormParam[] {
394                                PARAM_MAXWINDSPEED,
395                                PARAM_MINPRESSURE,
396                                PARAM_RADIUSMODERATEGALE,
397                                PARAM_RADIUSWHOLEGALE,
398                                PARAM_MOVEDIRECTION,
399                                PARAM_MOVESPEED, // PARAM_DISTANCEERROR,
400                                PARAM_PROBABILITY10RADIUS, PARAM_PROBABILITY20RADIUS,
401                                PARAM_PROBABILITY30RADIUS, PARAM_PROBABILITY40RADIUS,
402                                PARAM_PROBABILITY50RADIUS, PARAM_PROBABILITY60RADIUS,
403                                PARAM_PROBABILITY70RADIUS, PARAM_PROBABILITY80RADIUS,
404                                PARAM_PROBABILITY90RADIUS, PARAM_PROBABILITY100RADIUS,
405                                PARAM_DISTANCE_ERROR };
406        }
407
408        /**
409         * _more_
410         * 
411         * @param descriptor
412         *            _more_
413         * @param url
414         *            _more_
415         * @param properties
416         *            _more_
417         * 
418         * @throws Exception
419         *             _more_
420         */
421        public STIStormDataSource(DataSourceDescriptor descriptor, String url,
422                        Hashtable properties) throws Exception {
423                super(descriptor, "STI Storm Data", "STI Storm Data", properties);
424                if ((url != null) && url.trim().equals("test")) {
425                        url = DEFAULT_DERBY_URL;
426                }
427                if ((url == null) || url.trim().equalsIgnoreCase("default")
428                                || (url.trim().length() == 0)) {
429                        url = (useDerby() ? DEFAULT_DERBY_URL : DEFAULT_URL);
430                }
431                dbUrl = url;
432        }
433
434        /**
435         * _more_
436         */
437        protected void initializeStormData() {
438                try {
439                        initParams();
440                        File userDir = getDataContext().getIdv().getObjectStore()
441                                        .getUserDirectory();
442                        String derbyDir = IOUtil.joinDir(userDir, "derbydb");
443                        IOUtil.makeDirRecursive(new File(derbyDir));
444                        System.setProperty("derby.system.home", derbyDir);
445
446                        Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
447                        Class.forName("com.mysql.jdbc.Driver");
448                        if (!initConnection()) {
449                                setInError(true, true,
450                                                "Unable to initialize database connection:" + dbUrl);
451                        } else {
452                                stormInfos = getAllStormInfos();
453                        }
454                } catch (Exception exc) {
455                        logException("Error initializing STI database: " + dbUrl, exc);
456                }
457        }
458
459        /**
460         * _more_
461         * 
462         * @return _more_
463         */
464        public List<StormInfo> getStormInfos() {
465                List<StormInfo> sInfos = new ArrayList();
466                sInfos.addAll(stormInfos);
467                return sInfos;
468        }
469
470        /**
471         * _more_
472         * 
473         * @param stormInfo
474         *            _more_
475         * @param waysToUse
476         *            _more_
477         * @param observationWay
478         *            _more_
479         * 
480         * @return _more_
481         * 
482         * @throws Exception
483         *             _more_
484         */
485
486        public StormTrackCollection getTrackCollectionInner(StormInfo stormInfo,
487                        Hashtable<String, Boolean> waysToUse, Way observationWay)
488                        throws Exception {
489                if (observationWay == null) {
490                        observationWay = DEFAULT_OBSERVATION_WAY;
491                }
492
493                long t1 = System.currentTimeMillis();
494                StormTrackCollection trackCollection = new StormTrackCollection();
495                List<Way> forecastWays = getForecastWays(stormInfo);
496
497                getWayProbabilityRadius();
498                for (Way forecastWay : forecastWays) {
499                        if ((waysToUse != null) && (waysToUse.size() > 0)
500                                        && (waysToUse.get(forecastWay.getId()) == null)) {
501                                continue;
502                        }
503                        List forecastTracks = getForecastTracks(stormInfo, forecastWay);
504                        if (forecastTracks.size() > 0) {
505                                trackCollection.addTrackList(forecastTracks);
506                        }
507                }
508                StormTrack obsTrack = getObservationTrack(stormInfo, observationWay);
509                // (Way) forecastWays.get(0));
510                if (obsTrack != null) {
511                        List<StormTrack> tracks = trackCollection.getTracks();
512                        // for (StormTrack stk : tracks) {
513                        // addDistanceError(obsTrack, stk);
514                        // }
515                        long t2 = System.currentTimeMillis();
516                        // System.err.println("time:" + (t2 - t1));
517                        trackCollection.addTrack(obsTrack);
518                }
519                return trackCollection;
520        }
521
522        /**
523         * _more_
524         * 
525         * 
526         * 
527         * @param stormInfo
528         *            _more_
529         * @param forecastWay
530         *            _more_
531         * 
532         * @return _more_
533         * @throws Exception
534         *             _more_
535         */
536        private List<StormTrack> getForecastTracks(StormInfo stormInfo,
537                        Way forecastWay) throws Exception {
538
539                List<StormTrack> tracks = new ArrayList<StormTrack>();
540                List<DateTime> startDates = getForecastTrackStartDates(stormInfo,
541                                forecastWay);
542
543                int nstarts = startDates.size();
544                for (int i = 0; i < nstarts; i++) {
545                        DateTime dt = (DateTime) startDates.get(i);
546                        StormTrack tk = getForecastTrack(stormInfo, dt, forecastWay);
547                        if (tk != null) {
548                                int pn = tk.getTrackPoints().size();
549                                // Why > 1???
550                                if (pn > 1) {
551                                        tracks.add(tk);
552                                }
553                        }
554                }
555                return tracks;
556
557        }
558
559        /**
560         * If d is a missing value return NaN. Else return d
561         * 
562         * @param d
563         *            is checked if not missing return same value
564         * @param name
565         *            _more_
566         * 
567         * @return _more_
568         */
569
570        public double getValue(double d, String name) {
571                if ((d == 9999) || (d == 999)) {
572                        return Double.NaN;
573                }
574
575                if (name.equalsIgnoreCase(PARAM_MAXWINDSPEED.getName())) {
576                        if ((d < 0) || (d > 60)) {
577                                return Double.NaN;
578                        }
579                } else if (name.equalsIgnoreCase(PARAM_MINPRESSURE.getName())) {
580                        if ((d < 800) || (d > 1050)) {
581                                return Double.NaN;
582                        }
583                } else if (name.equalsIgnoreCase(PARAM_RADIUSMODERATEGALE.getName())) {
584                        if ((d < 0) || (d > 900)) {
585                                return Double.NaN;
586                        }
587                } else if (name.equalsIgnoreCase(PARAM_RADIUSWHOLEGALE.getName())) {
588                        if ((d < 0) || (d > 500)) {
589                                return Double.NaN;
590                        }
591                } else if (name.equalsIgnoreCase(PARAM_MOVESPEED.getName())) {
592                        if ((d < 0) || (d > 55)) {
593                                return Double.NaN;
594                        }
595                } else if (name.equalsIgnoreCase(PARAM_MOVEDIRECTION.getName())) {
596                        if ((d < 0) || (d > 360)) {
597                                return Double.NaN;
598                        }
599                }
600
601                return d;
602        }
603
604        /**
605         * _more_
606         * 
607         * @param d
608         *            _more_
609         * 
610         * @return _more_
611         */
612        public double getLatLonValue(double d) {
613                if ((d == 9999) || (d == 999)) {
614                        return Double.NaN;
615                }
616                return d;
617        }
618
619        /**
620         * _more_
621         * 
622         * 
623         * 
624         * @param stormInfo
625         *            _more_
626         * @param sTime
627         *            _more_
628         * @param forecastWay
629         *            _more_
630         * 
631         * @return _more_
632         * @throws Exception
633         *             _more_
634         */
635        private StormTrack getForecastTrack(StormInfo stormInfo, DateTime sTime,
636                        Way forecastWay) throws Exception {
637
638                // if(true) return getForecastTrackX(stormInfo, sTime, forecastWay);
639                String columns = SqlUtil.comma(new String[] { getColYear(),
640                                COL_TYPHOON_MONTH, COL_TYPHOON_DAY, getColHour(),
641                                COL_TYPHOON_FHOUR, COL_TYPHOON_LATITUDE, COL_TYPHOON_LONGITUDE,
642                                COL_TYPHOON_WINDSPEED, COL_TYPHOON_PRESSURE,
643                                COL_TYPHOON_RADIUSMG, COL_TYPHOON_RADIUSWG,
644                                COL_TYPHOON_MOVEDIR, COL_TYPHOON_MOVESPEED });
645
646                List whereList = new ArrayList();
647                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(stormInfo
648                                .getStormId())));
649                whereList.add(SqlUtil.eq(COL_TYPHOON_WAY, SqlUtil.quote(forecastWay
650                                .getId())));
651
652                addDateSelection(sTime, whereList);
653
654                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
655                                SqlUtil.makeAnd(whereList));
656                query = query
657                                + " order by  "
658                                + SqlUtil.comma(new String[] { getColYear(), COL_TYPHOON_MONTH,
659                                                COL_TYPHOON_DAY, getColHour(), COL_TYPHOON_FHOUR });
660                // System.err.println (query);
661                Statement statement = evaluate(query);
662                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
663                ResultSet results;
664                double radius = 0;
665                List<StormTrackPoint> pts = new ArrayList();
666
667                Real altReal = new Real(RealType.Altitude, 0);
668                while ((results = iter.getNext()) != null) {
669                        // System.err.println ("row " + cnt);
670                        List<Real> attrs = new ArrayList<Real>();
671                        int col = 1;
672                        int year = results.getInt(col++);
673                        int month = results.getInt(col++);
674                        int day = results.getInt(col++);
675                        int hour = results.getInt(col++);
676                        int fhour = results.getInt(col++);
677
678                        double latitude = getLatLonValue(results.getDouble(col++));
679                        if ((latitude > 90) || (latitude < -90)) {
680                                continue;
681                        }
682                        double longitude = getLatLonValue(results.getDouble(col++));
683                        if ((longitude > 360) || (longitude < -180)) {
684                                continue;
685                        }
686                        attrs.add(PARAM_MAXWINDSPEED.getReal(getValue(results
687                                        .getDouble(col++), PARAM_MAXWINDSPEED.getName())));
688                        attrs.add(PARAM_MINPRESSURE.getReal(getValue(results
689                                        .getDouble(col++), PARAM_MINPRESSURE.getName())));
690                        attrs.add(PARAM_RADIUSMODERATEGALE.getReal(getValue(results
691                                        .getDouble(col++), PARAM_RADIUSMODERATEGALE.getName())));
692                        attrs.add(PARAM_RADIUSWHOLEGALE.getReal(getValue(results
693                                        .getDouble(col++), PARAM_RADIUSWHOLEGALE.getName())));
694                        attrs.add(PARAM_MOVEDIRECTION.getReal(getValue(results
695                                        .getDouble(col++), PARAM_MOVEDIRECTION.getName())));
696                        attrs.add(PARAM_MOVESPEED.getReal(getValue(
697                                        results.getDouble(col++), PARAM_MOVESPEED.getName())));
698                        float[] radiuses = getProbabilityRadius(forecastWay, fhour);
699                        DateTime dttm = getDateTime(year, month, day, hour + fhour);
700                        EarthLocation elt = new EarthLocationLite(new Real(
701                                        RealType.Latitude, latitude), new Real(RealType.Longitude,
702                                        longitude), altReal);
703                        if (true) { // radiuses != null) {
704                                // radius = fhour * 50.0f / 24.0f;
705                                addProbabilityRadiusAttrs(attrs, radiuses);
706                        }
707                        StormTrackPoint stp = new StormTrackPoint(elt, dttm, fhour, attrs);
708                        if (!elt.isMissing()) {
709                                pts.add(stp);
710                        }
711                }
712
713                if (pts.size() == 0) {
714                        // We should never be here
715                        System.err.println("found no track data time=" + sTime
716                                        + " from query:" + SqlUtil.makeAnd(whereList));
717                }
718                if (pts.size() > 0) {
719                        return new StormTrack(stormInfo, forecastWay, pts, forecastParams);
720                } else {
721                        return null;
722                }
723
724        }
725
726        /**
727         * _more_
728         * 
729         * @param way
730         *            _more_
731         * @param forecastHour
732         *            _more_
733         * 
734         * @return _more_
735         */
736        private float[] getProbabilityRadius(Way way, int forecastHour) {
737                String key = way.getId().toUpperCase() + forecastHour;
738                // System.out.println("get:" + key + " "
739                // +(wayfhourToRadius.get(key)!=null));
740                return wayfhourToRadius.get(key);
741        }
742
743        /**
744         * _more_
745         * 
746         * @param way
747         *            _more_
748         * @param forecastHour
749         *            _more_
750         * @param radiuses
751         *            _more_
752         */
753        private void putProbabilityRadius(Way way, int forecastHour,
754                        float[] radiuses) {
755                String key = way.getId().toUpperCase() + forecastHour;
756                // System.out.println("put:" + key);
757                wayfhourToRadius.put(key, radiuses);
758        }
759
760        /**
761         * _more_
762         * 
763         * @param attrs
764         *            _more_
765         * @param radiuses
766         *            _more_
767         * 
768         * @throws Exception
769         *             _more_
770         */
771        private void addProbabilityRadiusAttrs(List<Real> attrs, float[] radiuses)
772                        throws Exception {
773                if (radiuses != null) {
774                        attrs.add(PARAM_PROBABILITY10RADIUS.getReal(radiuses[0]));
775                        attrs.add(PARAM_PROBABILITY20RADIUS.getReal(radiuses[1]));
776                        attrs.add(PARAM_PROBABILITY30RADIUS.getReal(radiuses[2]));
777                        attrs.add(PARAM_PROBABILITY40RADIUS.getReal(radiuses[3]));
778                        attrs.add(PARAM_PROBABILITY50RADIUS.getReal(radiuses[4]));
779                        attrs.add(PARAM_PROBABILITY60RADIUS.getReal(radiuses[5]));
780                        attrs.add(PARAM_PROBABILITY70RADIUS.getReal(radiuses[6]));
781                        attrs.add(PARAM_PROBABILITY80RADIUS.getReal(radiuses[7]));
782                        attrs.add(PARAM_PROBABILITY90RADIUS.getReal(radiuses[8]));
783                        attrs.add(PARAM_PROBABILITY100RADIUS.getReal(radiuses[9]));
784                        attrs.add(PARAM_DISTANCE_ERROR
785                                        .getReal(getLatLonValue(radiuses[10])));
786                } else {
787                        attrs.add(PARAM_PROBABILITY10RADIUS.getReal(Float.NaN));
788                        attrs.add(PARAM_PROBABILITY20RADIUS.getReal(Float.NaN));
789                        attrs.add(PARAM_PROBABILITY30RADIUS.getReal(Float.NaN));
790                        attrs.add(PARAM_PROBABILITY40RADIUS.getReal(Float.NaN));
791                        attrs.add(PARAM_PROBABILITY50RADIUS.getReal(Float.NaN));
792                        attrs.add(PARAM_PROBABILITY60RADIUS.getReal(Float.NaN));
793                        attrs.add(PARAM_PROBABILITY70RADIUS.getReal(Float.NaN));
794                        attrs.add(PARAM_PROBABILITY80RADIUS.getReal(Float.NaN));
795                        attrs.add(PARAM_PROBABILITY90RADIUS.getReal(Float.NaN));
796                        attrs.add(PARAM_PROBABILITY100RADIUS.getReal(Float.NaN));
797                        attrs.add(PARAM_DISTANCE_ERROR.getReal(Float.NaN));
798
799                }
800        }
801
802        /**
803         * _more_
804         * 
805         * @param sTime
806         *            _more_
807         * @param whereList
808         *            _more_
809         * 
810         * @throws VisADException
811         *             _more_
812         */
813        private void addDateSelection(DateTime sTime, List whereList)
814                        throws VisADException {
815                GregorianCalendar cal = new GregorianCalendar(DateUtil.TIMEZONE_GMT);
816                cal.setTime(ucar.visad.Util.makeDate(sTime));
817                int yy = cal.get(Calendar.YEAR);
818                // The MONTH is 0 based. The db month is 1 based
819                int mm = cal.get(Calendar.MONTH) + 1;
820                int dd = cal.get(Calendar.DAY_OF_MONTH);
821                int hh = cal.get(Calendar.HOUR_OF_DAY);
822                whereList.add(SqlUtil.eq(getColYear(), Integer.toString(yy)));
823                whereList.add(SqlUtil.eq(COL_TYPHOON_MONTH, Integer.toString(mm)));
824                whereList.add(SqlUtil.eq(COL_TYPHOON_DAY, Integer.toString(dd)));
825                whereList.add(SqlUtil.eq(getColHour(), Integer.toString(hh)));
826        }
827
828        /**
829         * _more_
830         * 
831         * @param year
832         *            _more_
833         * @param month
834         *            _more_
835         * @param day
836         *            _more_
837         * @param hour
838         *            _more_
839         * 
840         * @return _more_
841         * 
842         * @throws Exception
843         *             _more_
844         */
845        private DateTime getDateTime(int year, int month, int day, int hour)
846                        throws Exception {
847                GregorianCalendar convertCal = new GregorianCalendar(
848                                DateUtil.TIMEZONE_GMT);
849                convertCal.clear();
850                convertCal.set(Calendar.YEAR, year);
851                // The MONTH is 0 based. The incoming month is 1 based
852                convertCal.set(Calendar.MONTH, month - 1);
853                convertCal.set(Calendar.DAY_OF_MONTH, day);
854                convertCal.set(Calendar.HOUR_OF_DAY, hour);
855                return new DateTime(convertCal.getTime());
856        }
857
858        /**
859         * _more_
860         * 
861         * 
862         * 
863         * @param stormInfo
864         *            _more_
865         * @param way
866         *            _more_
867         * 
868         * @return _more_
869         * @throws Exception
870         *             _more_
871         */
872        protected List<DateTime> getForecastTrackStartDates(StormInfo stormInfo,
873                        Way way) throws Exception {
874
875                String columns = SqlUtil.comma(new String[] { getColYear(),
876                                COL_TYPHOON_MONTH, COL_TYPHOON_DAY, getColHour() });
877
878                List whereList = new ArrayList();
879                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(stormInfo
880                                .getStormId())));
881                whereList.add(SqlUtil.eq(COL_TYPHOON_FHOUR, ZEROHOUR));
882                whereList.add(SqlUtil.eq(COL_TYPHOON_WAY, SqlUtil.quote(way.getId())));
883
884                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
885                                SqlUtil.makeAnd(whereList));
886                query = query
887                                + " order by  "
888                                + SqlUtil.comma(new String[] { getColYear(), COL_TYPHOON_MONTH,
889                                                COL_TYPHOON_DAY, getColHour() });
890                // System.err.println (query);
891                Statement statement = evaluate(query);
892                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
893                ResultSet results;
894                List<DateTime> startDates = new ArrayList<DateTime>();
895                while ((results = iter.getNext()) != null) {
896                        int col = 1;
897                        int year = results.getInt(col++);
898                        int month = results.getInt(col++);
899                        int day = results.getInt(col++);
900                        int hour = results.getInt(col++);
901                        startDates.add(getDateTime(year, month, day, hour));
902                }
903                return startDates;
904        }
905
906        /**
907         * _more_
908         * 
909         * 
910         * @throws Exception
911         *             _more_
912         */
913        protected void getWayProbabilityRadius() throws Exception {
914
915                String columns = SqlUtil.comma(new String[] { COL_PROBILITY_WAYNAME,
916                                COL_PROBILITY_FHOUR, COL_PROBILITY_P10, COL_PROBILITY_P20,
917                                COL_PROBILITY_P30, COL_PROBILITY_P40, COL_PROBILITY_P50,
918                                COL_PROBILITY_P60, COL_PROBILITY_P70, COL_PROBILITY_P80,
919                                COL_PROBILITY_P90, COL_PROBILITY_P100, COL_DISTANCE_ERROR });
920
921                List whereList = new ArrayList();
922
923                String query = SqlUtil.makeSelect(columns, Misc
924                                .newList(TABLE_PROBILITY), SqlUtil.makeAnd(whereList));
925                Statement statement = evaluate(query);
926                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
927                ResultSet results;
928                wayfhourToRadius = new HashMap();
929                while ((results = iter.getNext()) != null) {
930                        float[] wp = new float[11];
931                        int col = 1;
932                        String wayName = results.getString(col++);
933                        int fhour = results.getInt(col++);
934                        wp[0] = results.getFloat(col++);
935                        wp[1] = results.getFloat(col++);
936                        wp[2] = results.getFloat(col++);
937                        wp[3] = results.getFloat(col++);
938                        wp[4] = results.getFloat(col++);
939                        wp[5] = results.getFloat(col++);
940                        wp[6] = results.getFloat(col++);
941                        wp[7] = results.getFloat(col++);
942                        wp[8] = results.getFloat(col++);
943                        wp[9] = results.getFloat(col++);
944                        wp[10] = results.getFloat(col++);
945                        putProbabilityRadius(new Way(wayName), fhour, wp);
946                }
947        }
948
949        /**
950         * _more_
951         * 
952         * @param stormInfo
953         *            _more_
954         * @param observationWay
955         *            _more_
956         * 
957         * @return _more_
958         * 
959         * @throws Exception
960         *             _more_
961         */
962        protected StormTrack getObservationTrack(StormInfo stormInfo,
963                        Way observationWay) throws Exception {
964                addWay(observationWay);
965                // first get the obs from one specific way
966                List<StormTrackPoint> obsTrackPoints = getObservationTrackPoints(
967                                stormInfo, observationWay);
968
969                if (obsTrackPoints.size() == 0) {
970                        return null;
971                }
972
973                return new StormTrack(stormInfo, addWay(Way.OBSERVATION),
974                                obsTrackPoints, obsParams);
975        }
976
977        /**
978         * _more_
979         * 
980         * @return _more_
981         */
982        public boolean getIsObservationWayChangeable() {
983                return true;
984        }
985
986        /**
987         * _more_
988         * 
989         * @return _more_
990         */
991        public Way getDefaultObservationWay() {
992                return DEFAULT_OBSERVATION_WAY;
993        }
994
995        /**
996         * _more_
997         * 
998         * 
999         * 
1000         * @param stormInfo
1001         *            _more_
1002         * @param wy
1003         *            _more_
1004         * 
1005         * @return _more_
1006         * @throws Exception
1007         *             _more_
1008         */
1009        protected List<StormTrackPoint> getObservationTrackPoints(
1010                        StormInfo stormInfo, Way wy) throws Exception {
1011                String columns = SqlUtil.comma(new String[] { getColYear(),
1012                                COL_TYPHOON_MONTH, COL_TYPHOON_DAY, getColHour(),
1013                                COL_TYPHOON_LATITUDE, COL_TYPHOON_LONGITUDE,
1014                                COL_TYPHOON_WINDSPEED, COL_TYPHOON_PRESSURE,
1015                                COL_TYPHOON_RADIUSMG, COL_TYPHOON_RADIUSWG,
1016                                COL_TYPHOON_MOVEDIR, COL_TYPHOON_MOVESPEED, COL_TYPHOON_WAY });
1017
1018                List whereList = new ArrayList();
1019
1020                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(stormInfo
1021                                .getStormId())));
1022                whereList.add(SqlUtil.eq(COL_TYPHOON_FHOUR, ZEROHOUR));
1023                whereList.add(SqlUtil.eq(COL_TYPHOON_WAY, SqlUtil.quote(wy.getId())));
1024
1025                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
1026                                SqlUtil.makeAnd(whereList));
1027                query = query
1028                                + " order by  "
1029                                + SqlUtil.comma(new String[] { getColYear(), COL_TYPHOON_MONTH,
1030                                                COL_TYPHOON_DAY, getColHour() });
1031                // System.err.println (query);
1032                Statement statement = evaluate(query);
1033                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
1034                ResultSet results;
1035
1036                List<StormTrackPoint> obsPts = new ArrayList();
1037                // Hashtable seenDate = new Hashtable();
1038                Real altReal = new Real(RealType.Altitude, 0);
1039
1040                while ((results = iter.getNext()) != null) {
1041                        List<Real> attrs = new ArrayList();
1042                        int col = 1;
1043                        int year = results.getInt(col++);
1044                        int month = results.getInt(col++);
1045                        int day = results.getInt(col++);
1046                        int hour = results.getInt(col++);
1047                        double latitude = getLatLonValue(results.getDouble(col++));
1048                        if ((latitude > 90) || (latitude < -90)) {
1049                                continue;
1050                        }
1051                        double longitude = getLatLonValue(results.getDouble(col++));
1052                        if ((longitude > 360) || (longitude < -180)) {
1053                                continue;
1054                        }
1055                        attrs.add(PARAM_MAXWINDSPEED.getReal(getValue(results
1056                                        .getDouble(col++), PARAM_MAXWINDSPEED.getName())));
1057                        attrs.add(PARAM_MINPRESSURE.getReal(getValue(results
1058                                        .getDouble(col++), PARAM_MINPRESSURE.getName())));
1059                        attrs.add(PARAM_RADIUSMODERATEGALE.getReal(getValue(results
1060                                        .getDouble(col++), PARAM_RADIUSMODERATEGALE.getName())));
1061                        attrs.add(PARAM_RADIUSWHOLEGALE.getReal(getValue(results
1062                                        .getDouble(col++), PARAM_RADIUSWHOLEGALE.getName())));
1063                        attrs.add(PARAM_MOVEDIRECTION.getReal(getValue(results
1064                                        .getDouble(col++), PARAM_MOVEDIRECTION.getName())));
1065                        attrs.add(PARAM_MOVESPEED.getReal(getValue(
1066                                        results.getDouble(col++), PARAM_MOVESPEED.getName())));
1067
1068                        EarthLocation elt = new EarthLocationLite(new Real(
1069                                        RealType.Latitude, latitude), new Real(RealType.Longitude,
1070                                        longitude), altReal);
1071
1072                        DateTime date = getDateTime(year, month, day, hour);
1073                        String key = "" + latitude + " " + longitude;
1074                        // if(seenDate.get(date)!=null) {
1075                        // if(!seenDate.get(date).equals(key)) {
1076                        // System.err.println ("seen: " + date + " " + seenDate.get(date) +
1077                        // " != " + key);
1078                        // }
1079                        // continue;
1080                        // }
1081                        // seenDate.put(date,date);
1082                        // seenDate.put(date,key);
1083                        StormTrackPoint stp = new StormTrackPoint(elt, date, 0, attrs);
1084                        obsPts.add(stp);
1085                }
1086
1087                return obsPts;
1088        }
1089
1090        /**
1091         * _more_
1092         * 
1093         * @param stormInfo
1094         *            _more_
1095         * @param wy
1096         *            _more_
1097         * @param before
1098         *            _more_
1099         * @param after
1100         *            _more_
1101         * @param pts
1102         *            _more_
1103         * 
1104         * @return _more_
1105         * 
1106         * @throws Exception
1107         *             _more_
1108         */
1109        protected List<StormTrackPoint> getObservationTrack(StormInfo stormInfo,
1110                        Way wy, DateTime before, DateTime after, List pts) throws Exception {
1111
1112                String columns = SqlUtil.comma(new String[] { getColYear(),
1113                                COL_TYPHOON_MONTH, COL_TYPHOON_DAY, getColHour(),
1114                                COL_TYPHOON_LATITUDE, COL_TYPHOON_LONGITUDE,
1115                                COL_TYPHOON_WINDSPEED, COL_TYPHOON_PRESSURE,
1116                                COL_TYPHOON_RADIUSMG, COL_TYPHOON_RADIUSWG,
1117                                COL_TYPHOON_MOVEDIR, COL_TYPHOON_MOVESPEED, COL_TYPHOON_WAY });
1118
1119                List whereList = new ArrayList();
1120
1121                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(stormInfo
1122                                .getStormId())));
1123                whereList.add(SqlUtil.eq(COL_TYPHOON_FHOUR, ZEROHOUR));
1124                whereList.add(SqlUtil.eq(COL_TYPHOON_WAY, SqlUtil.quote(wy.getId())));
1125
1126                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
1127                                SqlUtil.makeAnd(whereList));
1128                query = query
1129                                + " order by  "
1130                                + SqlUtil.comma(new String[] { getColYear(), COL_TYPHOON_MONTH,
1131                                                COL_TYPHOON_DAY, getColHour() });
1132                // System.err.println (query);
1133                Statement statement = evaluate(query);
1134                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
1135                ResultSet results;
1136
1137                List<StormTrackPoint> obsPts = new ArrayList();
1138                List<StormTrackPoint> obsPts1 = new ArrayList();
1139                List<StormTrackPoint> obsPts2 = new ArrayList();
1140                Real altReal = new Real(RealType.Altitude, 0);
1141
1142                while ((results = iter.getNext()) != null) {
1143                        List<Real> attrs = new ArrayList();
1144                        int col = 1;
1145                        int year = results.getInt(col++);
1146                        int month = results.getInt(col++);
1147                        int day = results.getInt(col++);
1148                        int hour = results.getInt(col++);
1149                        double latitude = getLatLonValue(results.getDouble(col++));
1150                        if ((latitude > 90) || (latitude < -90)) {
1151                                continue;
1152                        }
1153                        double longitude = getLatLonValue(results.getDouble(col++));
1154                        if ((longitude > 360) || (longitude < -180)) {
1155                                continue;
1156                        }
1157
1158                        attrs.add(PARAM_MAXWINDSPEED.getReal(getValue(results
1159                                        .getDouble(col++), PARAM_MAXWINDSPEED.getName())));
1160                        attrs.add(PARAM_MINPRESSURE.getReal(getValue(results
1161                                        .getDouble(col++), PARAM_MINPRESSURE.getName())));
1162                        attrs.add(PARAM_RADIUSMODERATEGALE.getReal(getValue(results
1163                                        .getDouble(col++), PARAM_RADIUSMODERATEGALE.getName())));
1164                        attrs.add(PARAM_RADIUSWHOLEGALE.getReal(getValue(results
1165                                        .getDouble(col++), PARAM_RADIUSWHOLEGALE.getName())));
1166                        attrs.add(PARAM_MOVEDIRECTION.getReal(getValue(results
1167                                        .getDouble(col++), PARAM_MOVEDIRECTION.getName())));
1168                        attrs.add(PARAM_MOVESPEED.getReal(getValue(
1169                                        results.getDouble(col++), PARAM_MOVESPEED.getName())));
1170
1171                        EarthLocation elt = new EarthLocationLite(new Real(
1172                                        RealType.Latitude, latitude), new Real(RealType.Longitude,
1173                                        longitude), altReal);
1174
1175                        DateTime date = getDateTime(year, month, day, hour);
1176
1177                        if (date.getValue() < before.getValue()) {
1178                                StormTrackPoint stp = new StormTrackPoint(elt, date, 0, attrs);
1179                                obsPts1.add(stp);
1180                        }
1181
1182                        if (date.getValue() > after.getValue()) {
1183                                StormTrackPoint stp = new StormTrackPoint(elt, date, 0, attrs);
1184                                obsPts2.add(stp);
1185                        }
1186
1187                }
1188
1189                if (obsPts1.size() > 0) {
1190                        obsPts.addAll(obsPts1);
1191                }
1192
1193                obsPts.addAll(pts);
1194
1195                if (obsPts2.size() > 0) {
1196                        obsPts.addAll(obsPts2);
1197                }
1198
1199                return obsPts;
1200
1201        }
1202
1203        /**
1204         * _more_
1205         * 
1206         * @param times
1207         *            _more_
1208         * 
1209         * @return _more_
1210         */
1211        protected DateTime getStartTime(List times) {
1212                int size = times.size();
1213                DateTime dt = (DateTime) times.get(0);
1214                int idx = 0;
1215                double value = dt.getValue();
1216                for (int i = 1; i < size; i++) {
1217                        dt = (DateTime) times.get(i);
1218                        double dtValue = dt.getValue();
1219                        if (dtValue < value) {
1220                                value = dtValue;
1221                                idx = i;
1222                        }
1223                }
1224                return (DateTime) times.get(idx);
1225        }
1226
1227        /**
1228         * _more_
1229         * 
1230         * 
1231         * 
1232         * @return _more_
1233         * @throws Exception
1234         *             _more_
1235         */
1236        private List<StormInfo> getAllStormInfos() throws Exception {
1237                String columns = SqlUtil.distinct(COL_TYPHOON_STORMID);
1238                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK));
1239                // System.err.println (query);
1240                // System.err.println(query);
1241                SqlUtil.Iterator iter = SqlUtil.getIterator(evaluate(query));
1242                ResultSet results;
1243                List<StormInfo> stormInfos = new ArrayList<StormInfo>();
1244                while ((results = iter.getNext()) != null) {
1245                        String id = results.getString(1);
1246                        DateTime startTime = getStormStartTime(id);
1247                        // System.err.println(id + " " + startTime);
1248                        StormInfo sinfo = new StormInfo(id, startTime);
1249                        stormInfos.add(sinfo);
1250                }
1251                return stormInfos;
1252        }
1253
1254        /**
1255         * _more_
1256         * 
1257         * @param id
1258         *            _more_
1259         * 
1260         * @return _more_
1261         * 
1262         * @throws Exception
1263         *             _more_
1264         */
1265        protected DateTime getStormStartTime(String id) throws Exception {
1266                String columns = SqlUtil.comma(new String[] { getColYear(),
1267                                COL_TYPHOON_MONTH, COL_TYPHOON_DAY, getColHour() });
1268
1269                List whereList = new ArrayList();
1270                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(id)));
1271                whereList.add(SqlUtil.eq(COL_TYPHOON_FHOUR, ZEROHOUR));
1272                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
1273                                SqlUtil.makeAnd(whereList));
1274                query = query + " order by  " + columns;
1275                // System.err.println (query);
1276                Statement statement = evaluate(query);
1277                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
1278                ResultSet results;
1279                while ((results = iter.getNext()) != null) {
1280                        int col = 1;
1281                        int year = results.getInt(col++);
1282                        int month = results.getInt(col++);
1283                        int day = results.getInt(col++);
1284                        int hour = results.getInt(col++);
1285                        statement.close();
1286                        // Just get the first one since we sorted the results with the order
1287                        // by
1288                        return getDateTime(year, month, day, hour);
1289                }
1290                return null;
1291        }
1292
1293        /**
1294         * _more_
1295         * 
1296         * 
1297         * 
1298         * @param stormInfo
1299         *            _more_
1300         * 
1301         * @return _more_
1302         * @throws Exception
1303         *             _more_
1304         */
1305        protected List<Way> getForecastWays(StormInfo stormInfo) throws Exception {
1306
1307                String columns = SqlUtil.distinct(COL_TYPHOON_WAY);
1308
1309                List whereList = new ArrayList();
1310                whereList.add(SqlUtil.eq(COL_TYPHOON_STORMID, SqlUtil.quote(stormInfo
1311                                .getStormId())));
1312                String query = SqlUtil.makeSelect(columns, Misc.newList(TABLE_TRACK),
1313                                SqlUtil.makeAnd(whereList));
1314                // System.err.println (query);
1315                Statement statement = evaluate(query);
1316                SqlUtil.Iterator iter = SqlUtil.getIterator(statement);
1317                ResultSet results;
1318
1319                List<Way> forecastWays = new ArrayList<Way>();
1320
1321                // TODO: How do we handle no data???
1322                while ((results = iter.getNext()) != null) {
1323                        Way way = new Way(results.getString(1));
1324                        addWay(way);
1325                        forecastWays.add(way);
1326                }
1327
1328                // System.err.println ("ways:" + forecastWays);
1329                return forecastWays;
1330
1331        }
1332
1333        /**
1334         * _more_
1335         * 
1336         * @param sql
1337         *            _more_
1338         * 
1339         * @return _more_
1340         * 
1341         * @throws SQLException
1342         *             _more_
1343         */
1344        private Statement evaluate(String sql) throws SQLException {
1345                Statement stmt = getConnection().createStatement();
1346                stmt.execute(sql);
1347                return stmt;
1348        }
1349
1350        /**
1351         * _more_
1352         * 
1353         * @return _more_
1354         */
1355        public Connection getConnection() {
1356                if (connection != null) {
1357                        return connection;
1358                }
1359                // String url = getFilePath();
1360                // Just hard code the jdbc url
1361                String url = dbUrl;
1362                // We don't need to do this for derby.
1363                /*
1364                 * if ((getUserName() == null) || (getUserName().trim().length() == 0))
1365                 * { if (url.indexOf("?") >= 0) { int idx = url.indexOf("?");
1366                 * List<String> args = (List<String>) StringUtil.split(url.substring(idx
1367                 * + 1), "&", true, true); url = url.substring(0, idx); for (String tok
1368                 * : args) { List<String> subtoks = (List<String>) StringUtil.split(tok,
1369                 * "=", true, true); if (subtoks.size() != 2) { continue; } String name
1370                 * = subtoks.get(0); String value = subtoks.get(1); if
1371                 * (name.equals("user")) { setUserName(value); } else if
1372                 * (name.equals("password")) { setPassword(value); } } } }
1373                 */
1374
1375                int cnt = 0;
1376                while (true) {
1377                        String userName = getUserName();
1378                        String password = getPassword();
1379                        if (userName == null) {
1380                                userName = "";
1381                        }
1382                        if (password == null) {
1383                                password = "";
1384                        }
1385                        // userName = "jeff";
1386                        // password = "mypassword";
1387                        try {
1388                                // System.err.println(url);
1389                                if (useDerby()) {
1390                                        connection = DriverManager.getConnection(url);
1391                                } else {
1392                                        if ((url.indexOf("user") > 0)
1393                                                        && (url.indexOf("password") > 0)) {
1394                                                connection = DriverManager.getConnection(url);
1395                                        } else {
1396                                                connection = DriverManager.getConnection(url, userName,
1397                                                                password);
1398                                        }
1399                                }
1400
1401                                return connection;
1402                        } catch (Exception sqe) {
1403                                // System.out.println(sqe);
1404                                String msg = sqe.toString();
1405                                if ((msg.indexOf("Access denied") >= 0)
1406                                                || (msg.indexOf("role \"" + userName
1407                                                                + "\" does not exist") >= 0)
1408                                                || (msg.indexOf("user name specified") >= 0)) {
1409                                        String label;
1410                                        if (cnt == 0) {
1411                                                label = "<html>The database requires a login.<br>Please enter a user name and password:</html>";
1412                                        } else {
1413                                                label = "<html>Incorrect username/password. Please try again.</html>";
1414                                        }
1415                                        if (!showPasswordDialog("Database Login", label)) {
1416                                                return null;
1417                                        }
1418                                        cnt++;
1419                                        continue;
1420                                }
1421                                throw new BadDataException("Unable to connect to database", sqe);
1422                        }
1423                }
1424        }
1425
1426        /**
1427         * _more_
1428         * 
1429         * @return _more_
1430         * 
1431         * @throws Exception
1432         *             _more_
1433         */
1434        private boolean initConnection() throws Exception {
1435                if (getConnection() == null) {
1436                        return false;
1437                }
1438
1439                try {
1440                        // Create the dummy database
1441                        Connection connection = getConnection();
1442                        Statement stmt = connection.createStatement();
1443                        // Drop the table - ignore any errors
1444                        // SqlUtil.loadSql("drop table " + TABLE_TRACK, stmt, false);
1445
1446                        if (useDerby()) {
1447                                // Load in the test data
1448                                try {
1449                                        stmt.execute("select count(*) from typhoon");
1450                                        System.err.println("Derby DB OK");
1451                                } catch (Exception exc) {
1452                                        System.err.println("exc;" + exc);
1453                                        System.err.println("Creating test database");
1454                                        String initSql = IOUtil.readContents(
1455                                                        "/ucar/unidata/data/storm/testdb.sql", getClass());
1456
1457                                        connection.setAutoCommit(false);
1458                                        SqlUtil.loadSql(initSql, stmt, false);
1459                                        connection.commit();
1460                                        connection.setAutoCommit(true);
1461                                }
1462                        }
1463                } catch (Exception exc) {
1464                        exc.printStackTrace();
1465                        return false;
1466                }
1467                return true;
1468        }
1469
1470        /**
1471         * _more_
1472         * 
1473         * @param args
1474         *            _more_
1475         * 
1476         * @throws Exception
1477         *             _more_
1478         */
1479        public static void main(String[] args) throws Exception {
1480                String sid = "0623";
1481                STIStormDataSource s = null;
1482                try {
1483                        s = new STIStormDataSource();
1484                } catch (Exception exc) {
1485                        System.err.println("err:" + exc);
1486                        exc.printStackTrace();
1487                }
1488                s.initAfter();
1489                List sInfoList = s.getStormInfos();
1490                StormInfo sInfo = (StormInfo) sInfoList.get(0);
1491                sInfo = s.getStormInfo(sid);
1492                String sd = sInfo.getStormId();
1493                StormTrackCollection cls = s.getTrackCollection(sInfo, null, null);
1494                StormTrack obsTrack = cls.getObsTrack();
1495                List trackPointList = obsTrack.getTrackPoints();
1496                List trackPointTime = obsTrack.getTrackTimes();
1497                List ways = cls.getWayList();
1498                Map mp = cls.getWayToStartDatesHashMap();
1499                Map mp1 = cls.getWayToTracksHashMap();
1500
1501                System.err.println("test:");
1502
1503        }
1504
1505        /**
1506         * Set the DbUrl property.
1507         * 
1508         * @param value
1509         *            The new value for DbUrl
1510         */
1511        public void setDbUrl(String value) {
1512                dbUrl = value;
1513        }
1514
1515        /**
1516         * Get the DbUrl property.
1517         * 
1518         * @return The DbUrl
1519         */
1520        public String getDbUrl() {
1521                return dbUrl;
1522        }
1523
1524}