001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
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    
029    package edu.wisc.ssec.mcidasv.data.cyclone;
030    
031    import java.util.ArrayList;
032    import java.util.Calendar;
033    import java.util.Collection;
034    import java.util.Date;
035    import java.util.GregorianCalendar;
036    import java.util.HashMap;
037    import java.util.Hashtable;
038    import java.util.Iterator;
039    import java.util.List;
040    import java.util.Map;
041    
042    import ucar.unidata.data.DataSourceDescriptor;
043    import ucar.unidata.data.DataUtil;
044    import ucar.unidata.util.DateUtil;
045    import ucar.unidata.util.IOUtil;
046    import ucar.unidata.util.StringUtil;
047    import ucar.visad.Util;
048    import visad.CommonUnit;
049    import visad.DateTime;
050    import visad.Real;
051    import visad.RealType;
052    import visad.VisADException;
053    import visad.georef.EarthLocation;
054    import 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     */
060    public 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    }