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.util.ArrayList;
032import java.util.Calendar;
033import java.util.Collection;
034import java.util.Date;
035import java.util.GregorianCalendar;
036import java.util.HashMap;
037import java.util.Hashtable;
038import java.util.Iterator;
039import java.util.List;
040import java.util.Map;
041
042import ucar.unidata.data.DataSourceDescriptor;
043import ucar.unidata.data.DataUtil;
044import ucar.unidata.util.DateUtil;
045import ucar.unidata.util.IOUtil;
046import ucar.unidata.util.StringUtil;
047import ucar.visad.Util;
048import visad.CommonUnit;
049import visad.DateTime;
050import visad.Real;
051import visad.RealType;
052import visad.VisADException;
053import visad.georef.EarthLocation;
054import visad.georef.EarthLocationLite;
055
056/**
057 * Created by IntelliJ IDEA. User: yuanho Date: May 8, 2009 Time: 10:02:15 AM To
058 * change this template use File | Settings | File Templates.
059 */
060public class Diamond7StormDataSource extends StormDataSource {
061
062        /**
063         * _more_
064         * 
065         * @return _more_
066         */
067
068        public String getId() {
069                return "stiDiamond";
070        }
071
072        /** _more_ */
073        public static StormParam PARAM_MAXWINDSPEED;
074
075        /** _more_ */
076        public static StormParam PARAM_RADIUSMODERATEGALE;
077
078        /** _more_ */
079        public static StormParam PARAM_RADIUSWHOLEGALE;
080
081        /** _more_ */
082        public static StormParam PARAM_DISTANCE_ERROR;
083
084        /** _more_ */
085        public static StormParam PARAM_PROBABILITY100RADIUS;
086
087        /** _more_ */
088        public static StormParam PARAM_PROBABILITYRADIUS;
089
090        /** _more_ */
091        public static StormParam PARAM_MOVEDIRECTION;
092
093        /** _more_ */
094        public static StormParam PARAM_MOVESPEED;
095
096        /** _more_ */
097        private static float MISSING = 9999.0f;
098
099        /** _more_ */
100        private String fileName;
101
102        /** the stormInfo and track */
103        private List<StormInfo> stormInfos;
104
105        /** the stormInfo and track */
106        private List<StormTrack> stormTracks;
107
108        private HashMap<String, Way> stormWays;
109
110        /**
111         * constructor of sti storm data source
112         * 
113         * 
114         * 
115         * @param descriptor
116         *            _more_
117         * @param fileName
118         *            _more_
119         * @param properties
120         *            _more_
121         * @throws Exception
122         *             _more_
123         */
124
125        public Diamond7StormDataSource(DataSourceDescriptor descriptor,
126                        String fileName, Hashtable properties) throws Exception {
127                super(descriptor, fileName, "Diamond7 Storm Data", properties);
128                if ((fileName == null) || (fileName.trim().length() == 0)
129                                || fileName.trim().equalsIgnoreCase("default")) {
130                        System.err.println("No input file");
131                        ;
132                }
133
134                this.fileName = fileName;
135
136        }
137
138        /**
139         * _more_
140         * 
141         * @return _more_
142         */
143        public boolean isEditable() {
144                return true;
145        }
146
147        static {
148                try {
149                        // TODO: Make sure these are the right units
150                        PARAM_MINPRESSURE = new StormParam(makeRealType("minpressure",
151                                        "Min_Pressure", DataUtil.parseUnit("mb")));
152                        PARAM_MAXWINDSPEED = new StormParam(makeRealType("maxwindspeed",
153                                        "Max_Windspeed", Util.parseUnit("m/s")));
154                        PARAM_RADIUSMODERATEGALE = new StormParam(makeRealType(
155                                        "radiusmoderategale", "Radius_of_Beaufort_Scale7", DataUtil
156                                                        .parseUnit("km")));
157                        PARAM_RADIUSWHOLEGALE = new StormParam(makeRealType(
158                                        "radiuswholegale", "Radius_of_Beaufort_Scale10", DataUtil
159                                                        .parseUnit("km")));
160                        PARAM_MOVEDIRECTION = new StormParam(makeRealType("movedirection",
161                                        "Storm_Direction", CommonUnit.degree));
162                        PARAM_MOVESPEED = new StormParam(makeRealType("movespeed",
163                                        "Storm_Speed", Util.parseUnit("m/s")));
164
165                } catch (Exception exc) {
166                        System.err.println("Error creating storm params:" + exc);
167                        exc.printStackTrace();
168
169                }
170        }
171
172        /**
173         * _more_
174         * 
175         * @throws VisADException
176         *             _more_
177         */
178        protected void initParams() throws VisADException {
179                super.initParams();
180
181                obsParams = new StormParam[] { PARAM_MAXWINDSPEED, PARAM_MINPRESSURE,
182                                PARAM_RADIUSMODERATEGALE, PARAM_RADIUSWHOLEGALE,
183                                PARAM_MOVESPEED, PARAM_MOVEDIRECTION };
184
185                forecastParams = new StormParam[] { PARAM_MAXWINDSPEED,
186                                PARAM_MINPRESSURE, PARAM_RADIUSMODERATEGALE,
187                                PARAM_RADIUSWHOLEGALE, PARAM_MOVESPEED, PARAM_MOVEDIRECTION };
188        }
189
190        /**
191         * _more_
192         * 
193         * 
194         * @throws Exception
195         *             _more_
196         */
197        public Diamond7StormDataSource() throws Exception {
198        }
199
200        /**
201         * _more_
202         */
203        protected void initializeStormData() {
204
205                try {
206                        stormInfos = new ArrayList<StormInfo>();
207                        stormTracks = new ArrayList<StormTrack>();
208                        stormWays = new HashMap<String, Way>();
209                        String s = IOUtil.readContents(fileName);
210                        /*
211                         * 
212                         * diamond 7 0807 Tropical Cyclone Track Name 0807 japn 15 08 06 15
213                         * 8 0 123.7 18.1 18.0 996.0 NaN NaN NaN NaN 08 06 15 14 6 124.4
214                         * 18.8 19.0 995.0 NaN NaN NaN NaN year mon day time forecasttime
215                         * lon lat speed pressure wind-circle-radii radii2 movspd movdir
216                         */
217                        int lcn = 0;
218                        String sid = null;
219                        String sway = null;
220                        boolean nextTrack = false;
221                        Way trackWay = null;
222                        StormInfo sInfo = null;
223                        List<StormTrackPoint> pts = null;
224                        List<StormTrackPoint> obsPts = new ArrayList();
225                        StormTrack sTrack = null;
226                        List<String> lines = StringUtil.split(s, "\n", true, true);
227                        int currentIndex = 0;
228                        String headerLine1 = lines.get(currentIndex++);
229                        double minTime = Double.MAX_VALUE;
230                        DateTime minDate = null;
231
232                        while (currentIndex < lines.size()) {
233
234                                String headerLine2 = lines.get(currentIndex++);
235                                List<String> toks = StringUtil.split(headerLine2, " ", true,
236                                                true);
237                                sid = toks.get(1);
238                                sway = toks.get(2);
239                                int numberPts = Integer.parseInt(toks.get(3));
240                                trackWay = new Way(sway);
241                                stormWays.put(sway, trackWay);
242                                if (trackWay.isObservation())
243                                        hasObservation = true;
244                                if (sInfo == null) {
245                                        sInfo = new StormInfo(sid, new DateTime(new Date()));
246                                        stormInfos.add(sInfo);
247                                }
248
249                                pts = new ArrayList();
250                                /*  */
251                                int endPtsIndex = currentIndex + numberPts;
252
253                                // System.out.println("endPtsIndex "+ endPtsIndex);
254                                while (currentIndex < endPtsIndex) {
255
256                                        // System.out.println("currentIndex "+ currentIndex);
257                                        String line = lines.get(currentIndex++);
258                                        toks = StringUtil.split(line, " ", true, true);
259                                        String year = toks.get(0);
260                                        String mon = toks.get(1);
261                                        String day = toks.get(2);
262                                        String hr = toks.get(3);
263                                        String fhr = toks.get(4);
264                                        String lon = toks.get(5);
265                                        String lat = toks.get(6);
266                                        String maxwindsp = toks.get(7);
267                                        String minpress = toks.get(8);
268                                        String radiusmgale = toks.get(9);
269                                        String radiuswgale = toks.get(10);
270                                        String mspd = toks.get(11);
271                                        String mdir = toks.get(12);
272                                        int yy = Integer.parseInt(year);
273                                        if (yy < 20)
274                                                yy = 2000 + yy;
275                                        else if (yy > 50 && yy < 99)
276                                                yy = 1900 + yy;
277                                        DateTime dtt = getDateTime(yy, Integer.parseInt(mon),
278                                                        Integer.parseInt(day), Integer.parseInt(hr));
279                                        double latitude = Double.parseDouble(lat);
280                                        double longitude = Double.parseDouble(lon);
281                                        Real altReal = new Real(RealType.Altitude, 0);
282                                        int fhour = Integer.parseInt(fhr);
283
284                                        EarthLocation elt = new EarthLocationLite(new Real(
285                                                        RealType.Latitude, latitude), new Real(
286                                                        RealType.Longitude, longitude), altReal);
287                                        List<Real> attributes = new ArrayList<Real>();
288
289                                        double windspeed = getDouble(maxwindsp);
290                                        double pressure = getDouble(minpress);
291                                        attributes.add(PARAM_MINPRESSURE.getReal(pressure));
292                                        attributes.add(PARAM_MAXWINDSPEED.getReal(windspeed));
293                                        attributes.add(PARAM_RADIUSMODERATEGALE
294                                                        .getReal(getDouble(radiusmgale)));
295                                        attributes.add(PARAM_RADIUSWHOLEGALE
296                                                        .getReal(getDouble(radiuswgale)));
297                                        attributes
298                                                        .add(PARAM_MOVEDIRECTION.getReal(getDouble(mdir)));
299                                        attributes.add(PARAM_MOVESPEED.getReal(getDouble(mspd)));
300
301                                        StormTrackPoint stp = new StormTrackPoint(elt, dtt, fhour,
302                                                        attributes);
303
304                                        // System.out.println("fhour "+ fhour);
305                                        if (fhour == 0 && !trackWay.isObservation()) {
306                                                obsPts.add(stp);
307                                        }
308                                        if (fhour == 0 && pts.size() > 0
309                                                        && !trackWay.isObservation()) {
310                                                // System.out.println("fhours "+ pts.size());
311                                                DateTime trackStartTime = pts.get(0).getTime();
312                                                if (trackStartTime.getValue() < minTime) {
313                                                        minTime = trackStartTime.getValue();
314                                                        minDate = trackStartTime;
315                                                }
316                                                sTrack = new StormTrack(sInfo, trackWay, pts,
317                                                                forecastParams);
318                                                stormTracks.add(sTrack);
319                                                pts = new ArrayList();
320                                        }
321                                        pts.add(stp);
322                                }
323                                if (trackWay.isObservation()) {
324                                        DateTime trackStartTime = pts.get(0).getTime();
325                                        if (trackStartTime.getValue() < minTime) {
326                                                minTime = trackStartTime.getValue();
327                                                minDate = trackStartTime;
328                                        }
329                                        sTrack = new StormTrack(sInfo, trackWay, pts, obsParams);
330                                        stormTracks.add(sTrack);
331                                        pts = new ArrayList();
332                                }
333                                if (pts.size() > 0 && !trackWay.isObservation()) {
334                                        DateTime trackStartTime = pts.get(0).getTime();
335                                        if (trackStartTime.getValue() < minTime) {
336                                                minTime = trackStartTime.getValue();
337                                                minDate = trackStartTime;
338                                        }
339                                        sTrack = new StormTrack(sInfo, trackWay, pts,
340                                                        forecastParams);
341                                        stormTracks.add(sTrack);
342                                        pts = new ArrayList();
343                                }
344
345                        }
346                        /* last track */
347                        if (sInfo != null && minDate != null) {
348                                sInfo.setStartTime(minDate);
349                        }
350                        /* obs */
351                        if (!hasObservation && obsPts.size() > 0) {
352                                sTrack = new StormTrack(sInfo, DEFAULT_OBSERVATION_WAY, obsPts,
353                                                obsParams);
354                                stormTracks.add(sTrack);
355                                stormWays.put("Observation", DEFAULT_OBSERVATION_WAY);
356                        }
357
358                } catch (Exception exc) {
359                        logException("Error initializing ATCF data", exc);
360                } finally {
361                        decrOutstandingGetDataCalls();
362                }
363
364        }
365
366        /**
367         * _more_
368         * 
369         * @param dstring
370         *            _more_
371         * 
372         * @return _more_
373         */
374        public double getDouble(String dstring) {
375                if (dstring.equalsIgnoreCase("NaN") || dstring.equalsIgnoreCase("9999")) {
376                        return Double.NaN;
377                } else {
378                        return Double.parseDouble(dstring);
379                }
380        }
381
382        /**
383         * _more_
384         * 
385         * @return _more_
386         */
387        public List<StormInfo> getStormInfos() {
388                List<StormInfo> sInfos = new ArrayList();
389                sInfos.addAll(stormInfos);
390                return sInfos;
391        }
392
393        /**
394         * _more_
395         * 
396         * @param stormInfo
397         *            _more_
398         * @param waysToUse
399         *            _more_
400         * @param observationWay
401         *            _more_
402         * 
403         * @return _more_
404         * 
405         * @throws Exception
406         *             _more_
407         */
408
409        /** _more_ */
410        private static final Way DEFAULT_OBSERVATION_WAY = new Way("Observation");
411        private boolean hasObservation = false;
412
413        /**
414         * _more_
415         * 
416         * @param stormInfo
417         *            _more_
418         * @param waysToUse
419         *            _more_
420         * @param observationWay
421         *            _more_
422         * 
423         * @return _more_
424         * 
425         * @throws Exception
426         *             _more_
427         */
428        public StormTrackCollection getTrackCollectionInner(StormInfo stormInfo,
429                        Hashtable<String, Boolean> waysToUse, Way observationWay)
430                        throws Exception {
431
432                if (observationWay == null) {
433                        observationWay = DEFAULT_OBSERVATION_WAY;
434                }
435
436                // long t1 = System.currentTimeMillis();
437                StormTrackCollection trackCollection = new StormTrackCollection();
438                // initializeStormData();
439                List<Way> forecastWays = getForecastWays(stormInfo);
440
441                for (Way forecastWay : forecastWays) {
442                        if ((waysToUse != null) && (waysToUse.size() > 0)
443                                        && (waysToUse.get(forecastWay.getId()) == null)) {
444                                continue;
445                        }
446                        List forecastTracks = getForecastTracks(stormInfo, forecastWay);
447                        if (forecastTracks.size() > 0) {
448                                trackCollection.addTrackList(forecastTracks);
449                        }
450                }
451                StormTrack obsTrack = getObservationTrack(stormInfo, observationWay);
452                // (Way) forecastWays.get(0));
453                if (obsTrack != null) {
454                        List<StormTrack> tracks = trackCollection.getTracks();
455                        // for (StormTrack stk : tracks) {
456                        // addDistanceError(obsTrack, stk);
457                        // }
458                        // long t2 = System.currentTimeMillis();
459                        // System.err.println("time:" + (t2 - t1));
460                        trackCollection.addTrack(obsTrack);
461                }
462                return trackCollection;
463        }
464
465        /**
466         * _more_
467         * 
468         * 
469         * 
470         * @param stormInfo
471         *            _more_
472         * @param forecastWay
473         *            _more_
474         * 
475         * @return _more_
476         * @throws Exception
477         *             _more_
478         */
479        private List<StormTrack> getForecastTracks(StormInfo stormInfo,
480                        Way forecastWay) throws Exception {
481
482                List<StormTrack> tracks = new ArrayList<StormTrack>();
483                List<DateTime> startDates = getForecastTrackStartDates(stormInfo,
484                                forecastWay);
485
486                int nstarts = startDates.size();
487                for (int i = 0; i < nstarts; i++) {
488                        DateTime dt = (DateTime) startDates.get(i);
489                        StormTrack tk = getForecastTrack(stormInfo, dt, forecastWay);
490                        if (tk != null) {
491                                int pn = tk.getTrackPoints().size();
492                                // Why > 1???
493                                if (pn > 1) {
494                                        tracks.add(tk);
495                                }
496                        }
497                }
498                return tracks;
499
500        }
501
502        /**
503         * If d is a missing value return NaN. Else return d
504         * 
505         * @param d
506         *            is checked if not missing return same value
507         * @param name
508         *            _more_
509         * 
510         * @return _more_
511         */
512
513        public double getValue(double d, String name) {
514                if ((d == 9999) || (d == 999)) {
515                        return Double.NaN;
516                }
517
518                if (name.equalsIgnoreCase(PARAM_MAXWINDSPEED.getName())) {
519                        if ((d < 0) || (d > 60)) {
520                                return Double.NaN;
521                        }
522                } else if (name.equalsIgnoreCase(PARAM_MINPRESSURE.getName())) {
523                        if ((d < 800) || (d > 1050)) {
524                                return Double.NaN;
525                        }
526                } else if (name.equalsIgnoreCase(PARAM_RADIUSMODERATEGALE.getName())) {
527                        if ((d < 0) || (d > 900)) {
528                                return Double.NaN;
529                        }
530                } else if (name.equalsIgnoreCase(PARAM_RADIUSWHOLEGALE.getName())) {
531                        if ((d < 0) || (d > 500)) {
532                                return Double.NaN;
533                        }
534                } else if (name.equalsIgnoreCase(PARAM_MOVESPEED.getName())) {
535                        if ((d < 0) || (d > 55)) {
536                                return Double.NaN;
537                        }
538                } else if (name.equalsIgnoreCase(PARAM_MOVEDIRECTION.getName())) {
539                        if ((d < 0) || (d > 360)) {
540                                return Double.NaN;
541                        }
542                }
543
544                return d;
545        }
546
547        /**
548         * _more_
549         * 
550         * @param d
551         *            _more_
552         * 
553         * @return _more_
554         */
555        public double getLatLonValue(double d) {
556                if ((d == 9999) || (d == 999)) {
557                        return Double.NaN;
558                }
559                return d;
560        }
561
562        /**
563         * _more_
564         * 
565         * 
566         * 
567         * @param stormInfo
568         *            _more_
569         * @param sTime
570         *            _more_
571         * @param forecastWay
572         *            _more_
573         * 
574         * @return _more_
575         * @throws Exception
576         *             _more_
577         */
578        private StormTrack getForecastTrack(StormInfo stormInfo, DateTime sTime,
579                        Way forecastWay) throws Exception {
580
581                StormTrack track = null;
582
583                Iterator iter = stormTracks.iterator();
584                String sid = stormInfo.getStormId();
585                String sway = forecastWay.getId();
586                while (iter.hasNext()) {
587                        track = (StormTrack) iter.next();
588                        String away = track.getWay().getId();
589                        String id = track.getStormInfo().getStormId();
590                        DateTime dt = track.getStartTime();
591                        if (id.equalsIgnoreCase(sid) && (dt == sTime)
592                                        && sway.equalsIgnoreCase(away)) {
593                                return track;
594                        }
595
596                }
597                return null;
598        }
599
600        /**
601         * _more_
602         * 
603         * @param year
604         *            _more_
605         * @param month
606         *            _more_
607         * @param day
608         *            _more_
609         * @param hour
610         *            _more_
611         * 
612         * @return _more_
613         * 
614         * @throws Exception
615         *             _more_
616         */
617        private DateTime getDateTime(int year, int month, int day, int hour)
618                        throws Exception {
619                GregorianCalendar convertCal = new GregorianCalendar(
620                                DateUtil.TIMEZONE_GMT);
621                convertCal.clear();
622                convertCal.set(Calendar.YEAR, year);
623                // The MONTH is 0 based. The incoming month is 1 based
624                convertCal.set(Calendar.MONTH, month - 1);
625                convertCal.set(Calendar.DAY_OF_MONTH, day);
626                convertCal.set(Calendar.HOUR_OF_DAY, hour);
627                return new DateTime(convertCal.getTime());
628        }
629
630        /**
631         * _more_
632         * 
633         * 
634         * 
635         * @param stormInfo
636         *            _more_
637         * @param way
638         *            _more_
639         * 
640         * @return _more_
641         * @throws Exception
642         *             _more_
643         */
644        protected List<DateTime> getForecastTrackStartDates(StormInfo stormInfo,
645                        Way way) throws Exception {
646
647                Iterator iter = stormTracks.iterator();
648                List<DateTime> startDates = new ArrayList<DateTime>();
649                while (iter.hasNext()) {
650                        StormTrack track = (StormTrack) iter.next();
651                        if (!track.getWay().isObservation()) {
652                                DateTime dt = track.getStartTime();
653                                startDates.add(dt);
654                        }
655                }
656                return startDates;
657        }
658
659        /**
660         * _more_
661         * 
662         * @param stormInfo
663         *            _more_
664         * @param observationWay
665         *            _more_
666         * 
667         * @return _more_
668         * 
669         * @throws Exception
670         *             _more_
671         */
672        protected StormTrack getObservationTrack(StormInfo stormInfo,
673                        Way observationWay) throws Exception {
674                addWay(observationWay);
675                // first get the obs from one specific way
676                List<StormTrackPoint> obsTrackPoints = getObservationTrackPoints(
677                                stormInfo, observationWay);
678
679                if ((obsTrackPoints == null) || (obsTrackPoints.size() == 0)) {
680                        return null;
681                }
682
683                return new StormTrack(stormInfo, addWay(Way.OBSERVATION),
684                                obsTrackPoints, obsParams);
685        }
686
687        /**
688         * _more_
689         * 
690         * @return _more_
691         */
692        public boolean getIsObservationWayChangeable() {
693                return true;
694        }
695
696        /**
697         * _more_
698         * 
699         * 
700         * 
701         * @param stormInfo
702         *            _more_
703         * @param wy
704         *            _more_
705         * 
706         * @return _more_
707         * @throws Exception
708         *             _more_
709         */
710        protected List<StormTrackPoint> getObservationTrackPoints(
711                        StormInfo stormInfo, Way wy) throws Exception {
712
713                Iterator iter = stormTracks.iterator();
714                String sway = wy.getId();
715                String sid = stormInfo.getStormId();
716
717                while (iter.hasNext()) {
718                        StormTrack strack = (StormTrack) iter.next();
719                        String away = strack.getWay().getId();
720                        String aid = strack.getStormInfo().getStormId();
721                        if (away.equalsIgnoreCase(sway) && aid.equalsIgnoreCase(sid)) {
722                                return strack.getTrackPoints();
723                        }
724
725                }
726
727                return null;
728        }
729
730        /**
731         * _more_
732         * 
733         * @param stormInfo
734         *            _more_
735         * @param wy
736         *            _more_
737         * @param before
738         *            _more_
739         * @param after
740         *            _more_
741         * @param pts
742         *            _more_
743         * 
744         * @return _more_
745         * 
746         * @throws Exception
747         *             _more_
748         */
749        protected List<StormTrackPoint> getObservationTrack(StormInfo stormInfo,
750                        Way wy, DateTime before, DateTime after, List pts) throws Exception {
751
752                return null;
753        }
754
755        /**
756         * _more_
757         * 
758         * @param times
759         *            _more_
760         * 
761         * @return _more_
762         */
763        protected DateTime getStartTime(List times) {
764                int size = times.size();
765                DateTime dt = (DateTime) times.get(0);
766                int idx = 0;
767                double value = dt.getValue();
768                for (int i = 1; i < size; i++) {
769                        dt = (DateTime) times.get(i);
770                        double dtValue = dt.getValue();
771                        if (dtValue < value) {
772                                value = dtValue;
773                                idx = i;
774                        }
775                }
776                return (DateTime) times.get(idx);
777        }
778
779        /**
780         * _more_
781         * 
782         * @param sid
783         *            _more_
784         * 
785         * @return _more_
786         * 
787         * @throws Exception
788         *             _more_
789         */
790        protected DateTime getStormStartTime(String sid) throws Exception {
791
792                Iterator iter = stormTracks.iterator();
793
794                while (iter.hasNext()) {
795                        StormTrack strack = (StormTrack) iter.next();
796                        String aid = strack.getStormInfo().getStormId();
797                        if (aid.equalsIgnoreCase(sid)) {
798                                return strack.getStartTime();
799                        }
800                }
801                return null;
802        }
803
804        /**
805         * _more_
806         * 
807         * 
808         * 
809         * @param stormInfo
810         *            _more_
811         * 
812         * @return _more_
813         * @throws Exception
814         *             _more_
815         */
816        protected List<Way> getForecastWays(StormInfo stormInfo) throws Exception {
817
818                List<Way> ways = new ArrayList();
819
820                Collection wc = stormWays.values();
821                Iterator iter = wc.iterator();
822
823                while (iter.hasNext()) {
824                        Way way = (Way) iter.next();
825                        if (!way.isObservation())
826                                ways.add(way);
827                }
828
829                // System.err.println ("ways:" + forecastWays);
830                return ways;
831
832        }
833
834        /**
835         * _more_
836         * 
837         * @param args
838         *            _more_
839         * 
840         * @throws Exception
841         *             _more_
842         */
843        public static void main(String[] args) throws Exception {
844                String sid = "0623";
845                STIStormDataSource s = null;
846                try {
847                        s = new STIStormDataSource();
848                } catch (Exception exc) {
849                        System.err.println("err:" + exc);
850                        exc.printStackTrace();
851                }
852                s.initAfter();
853                List sInfoList = s.getStormInfos();
854                StormInfo sInfo = (StormInfo) sInfoList.get(0);
855                sInfo = s.getStormInfo(sid);
856                String sd = sInfo.getStormId();
857                StormTrackCollection cls = s.getTrackCollection(sInfo, null, null);
858                StormTrack obsTrack = cls.getObsTrack();
859                List trackPointList = obsTrack.getTrackPoints();
860                List trackPointTime = obsTrack.getTrackTimes();
861                List ways = cls.getWayList();
862                Map mp = cls.getWayToStartDatesHashMap();
863                Map mp1 = cls.getWayToTracksHashMap();
864
865                System.err.println("test:");
866
867        }
868
869}