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