001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.control.cyclone;
030
031import java.awt.Component;
032import java.awt.Container;
033import java.awt.Dimension;
034import java.awt.Point;
035import java.awt.Toolkit;
036import java.awt.event.ActionEvent;
037import java.awt.event.ActionListener;
038import java.awt.event.InputEvent;
039import java.rmi.RemoteException;
040import java.util.ArrayList;
041import java.util.List;
042import java.util.Vector;
043
044import javax.swing.JButton;
045import javax.swing.JComboBox;
046import javax.swing.JComponent;
047import javax.swing.JDialog;
048import javax.swing.JEditorPane;
049import javax.swing.JLabel;
050import javax.swing.JPanel;
051import javax.swing.JScrollPane;
052import javax.swing.JTextField;
053
054import ucar.unidata.data.DataChoice;
055import ucar.unidata.data.DataInstance;
056import ucar.unidata.data.DataSourceImpl;
057import ucar.unidata.data.DataUtil;
058import ucar.unidata.data.grid.GridUtil;
059import ucar.unidata.data.imagery.AddeImageDataSource;
060import ucar.unidata.data.imagery.AddeImageDescriptor;
061import ucar.unidata.data.imagery.ImageDataSource;
062import ucar.unidata.idv.DisplayInfo;
063import ucar.unidata.idv.control.DisplayControlImpl;
064import ucar.unidata.ui.LatLonWidget;
065import ucar.unidata.util.GuiUtils;
066import ucar.unidata.util.Misc;
067import ucar.unidata.util.ObjectListener;
068import ucar.unidata.view.geoloc.NavigatedDisplay;
069import ucar.visad.Util;
070import ucar.visad.display.Animation;
071import ucar.visad.display.PointProbe;
072import ucar.visad.quantities.AirTemperature;
073import visad.CommonUnit;
074import visad.DateTime;
075import visad.DisplayEvent;
076import visad.FieldImpl;
077import visad.FlatField;
078import visad.Real;
079import visad.RealTuple;
080import visad.RealTupleType;
081import visad.Set;
082import visad.VisADException;
083import visad.georef.EarthLocation;
084import visad.georef.LatLonPoint;
085import visad.util.DataUtility;
086import edu.wisc.ssec.mcidas.AreaDirectory;
087import edu.wisc.ssec.mcidasv.data.cyclone.StormAODT;
088import edu.wisc.ssec.mcidasv.data.cyclone.StormAODTInfo;
089import edu.wisc.ssec.mcidasv.data.cyclone.StormAODTUtil;
090
091/**
092 * Created by IntelliJ IDEA. User: yuanho Date: Mar 10, 2009 Time: 1:03:56 PM To
093 * change this template use File | Settings | File Templates.
094 */
095
096public class StormIntensityControl extends DisplayControlImpl {
097
098        /** _more_ */
099        private LatLonWidget latLonWidget;
100
101        /** _more_ */
102        private JEditorPane textComp;
103
104        /** _more_ */
105        private LatLonPoint probeLocation;
106
107        /** the probe */
108        private PointProbe probe;
109
110        /** _more_ */
111        private DataChoice choice;
112
113        /** _more_ */
114        private boolean running = false;
115
116        /** _more_ */
117        private boolean runOnClick = false;
118
119        /** _more_ */
120        private JButton aodtBtn;
121
122        /**
123         * _more_
124         */
125        public StormIntensityControl() {
126        }
127
128        /**
129         * _more_
130         * 
131         * @param choice
132         *            _more_
133         * 
134         * @return _more_
135         * 
136         * @throws RemoteException
137         *             _more_
138         * @throws VisADException
139         *             _more_
140         */
141        public boolean init(DataChoice choice) throws VisADException,
142                        RemoteException {
143                if (!super.init(choice)) {
144                        return false;
145                }
146                this.choice = choice;
147
148                // probe = new SelectorPoint ("",new
149                // RealTuple(RealTupleType.SpatialEarth3DTuple,
150                // new double[] {0,0,0}));
151
152                probe = new PointProbe(new RealTuple(RealTupleType.SpatialEarth3DTuple,
153                                new double[] { 0, 0, 0 }));
154
155                probe.setManipulable(false);
156                probe.setVisible(false);
157                probe.setAutoSize(true);
158
159                probe.setPointSize(getDisplayScale());
160                addDisplayable(probe, FLAG_COLOR);
161
162                setContents(doMakeContents());
163                updateProbeLocation();
164                return true;
165        }
166
167        /** _more_ */
168        private JComboBox domainBox;
169
170        /** _more_ */
171        private int domainIndex = 0;
172
173        /** _more_ */
174        private JComboBox oceanBox;
175
176        /** _more_ */
177        private int oceanIndex = 0;
178
179        /** _more_ */
180        private JComboBox sceneBox;
181
182        /** _more_ */
183        private int sceneIndex = 0;
184
185        /** _more_ */
186        private String[] ocean = { "Atlantic", "Pacific", "Indian" };
187
188        /** _more_ */
189        private String text;
190
191        /**
192         * _more_
193         * 
194         * @return _more_
195         */
196        public Container doMakeContents() {
197                latLonWidget = new LatLonWidget(GuiUtils.makeActionListener(this,
198                                "latLonWidgetChanged", null));
199                JPanel latlonPanel = GuiUtils.hbox(Misc.newList(latLonWidget));
200
201                domainBox = new JComboBox(new Vector(Misc.newList("Ocean", "Land")));
202                domainBox.setSelectedIndex(domainIndex);
203                domainBox.addActionListener(new ActionListener() {
204                        public void actionPerformed(ActionEvent ae) {
205                                domainIndex = domainBox.getSelectedIndex();
206                        }
207                });
208                domainBox.setToolTipText("Domain selection for Ocean or Land.");
209
210                oceanBox = new JComboBox(new Vector(Misc.newList("Atlantic", "Pacific",
211                                "Indian")));
212                oceanBox.setSelectedIndex(oceanIndex);
213                oceanBox.addActionListener(new ActionListener() {
214                        public void actionPerformed(ActionEvent ae) {
215                                oceanIndex = oceanBox.getSelectedIndex();
216                        }
217                });
218                oceanBox.setToolTipText("Ocean Selection Atlantic, Pacific, or Indian");
219
220                sceneBox = new JComboBox(new Vector(Misc.newList(" COMPUTED")));
221                sceneBox.setSelectedIndex(sceneIndex);
222                sceneBox.addActionListener(new ActionListener() {
223                        public void actionPerformed(ActionEvent ae) {
224                                sceneIndex = sceneBox.getSelectedIndex();
225                        }
226                });
227                sceneBox.setToolTipText("Only computed scene type available");
228
229                aodtBtn = new JButton("Run Analysis");
230                aodtBtn.addActionListener(new ActionListener() {
231                        public void actionPerformed(ActionEvent ae) {
232                                doAnalysis();
233                        }
234                });
235                JComponent btn = GuiUtils.hbox(aodtBtn, GuiUtils.makeCheckbox(
236                                "Run On Click", this, "runOnClick"));
237
238                textComp = new JEditorPane();
239
240                textComp.setEditable(false);
241                textComp.setContentType("text/html");
242                textComp.setPreferredSize(new Dimension(300, 180));
243                // GuiUtils.setFixedWidthFont(textComp);
244                textComp.setEditable(false);
245
246                JScrollPane textScroller = new JScrollPane(textComp);
247                textScroller
248                                .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
249                textScroller.setPreferredSize(new Dimension(300, 180));
250
251                JComponent textHolder = GuiUtils.topCenter(new JLabel("Result:"),
252                                textScroller);
253
254                GuiUtils.tmpInsets = GuiUtils.INSETS_5;
255                JComponent widgets = GuiUtils.formLayout(new Component[] {
256                                GuiUtils.rLabel("Location:"),
257                                GuiUtils.left(latlonPanel),
258                                GuiUtils.rLabel("Domain:"),
259                                GuiUtils.left(GuiUtils.hbox(new Component[] { domainBox,
260                                                new JLabel("Ocean Selection:"), oceanBox,
261                                                new JLabel("Scene Type:"), sceneBox }, 5)),
262                                GuiUtils.filler(), GuiUtils.left(btn) });
263                // JPanel htmlPanel = GuiUtils.hbox( htmlScroller);
264
265                // JPanel controls =
266                // GuiUtils.topCenterBottom(latlonPanel,widgets,textHolder);
267                JPanel controls = GuiUtils.topCenter(widgets, textHolder);
268
269                return controls;
270        }
271
272        /**
273         * _more_
274         */
275        public void latLonWidgetChanged() {
276                try {
277                        System.err.println("widget changed");
278                        String message = latLonWidget.isValidValues();
279                        if (message != null) {
280                                userMessage(message);
281                                return;
282                        }
283
284                        probeLocation = ucar.visad.Util.makeEarthLocation(
285                                        latLonWidget.getLat(), latLonWidget.getLon())
286                                        .getLatLonPoint();
287                } catch (Exception e) {
288                        logException("Handling LatLonWidget changed", e);
289                }
290
291        }
292
293        /**
294         * _more_
295         * 
296         * @return _more_
297         */
298        protected boolean shouldAddDisplayListener() {
299                return true;
300        }
301
302        /**
303         * _more_
304         * 
305         * @return _more_
306         */
307        protected boolean shouldAddControlListener() {
308                return true;
309        }
310
311        /**
312         * Should we handle display events
313         * 
314         * @return Ok to handle events
315         */
316        protected boolean canHandleEvents() {
317                if (!getHaveInitialized() || (getMakeWindow() && !getWindowVisible())) {
318                        return false;
319                }
320                return isGuiShown();
321        }
322
323        /**
324         * Listen for DisplayEvents
325         * 
326         * @param event
327         *            The event
328         */
329        public void handleDisplayChanged(DisplayEvent event) {
330                super.handleDisplayChanged(event);
331
332                if (!canHandleEvents()) {
333                        return;
334                }
335
336                int id = event.getId();
337                InputEvent inputEvent = event.getInputEvent();
338
339                try {
340                        if (id == DisplayEvent.MOUSE_PRESSED) {
341                                if (!isLeftButtonDown(event)) {
342                                        return;
343                                }
344                                probeLocation = toEarth(event).getLatLonPoint();
345                                updateProbeLocation();
346                                if (runOnClick) {
347                                        doAnalysis();
348                                }
349                        }
350                } catch (Exception e) {
351                        logException("Handling display event changed", e);
352                }
353
354        }
355
356        /**
357         * _more_
358         */
359        private void updateProbeLocation() {
360                try {
361                        if (probeLocation == null) {
362                                return;
363                        }
364                        double lon = probeLocation.getLongitude().getValue(
365                                        CommonUnit.degree);
366                        double lat = probeLocation.getLatitude()
367                                        .getValue(CommonUnit.degree);
368                        probe.setPosition(new RealTuple(RealTupleType.SpatialEarth3DTuple,
369                                        new double[] { lon, lat, 0 }));
370
371                        // probe.setPoint(new RealTuple(RealTupleType.SpatialEarth3DTuple,
372                        // new double[] {lon,
373                        // lat,0}));
374
375                        probe.setVisible(true);
376
377                        if (latLonWidget != null) {
378                                latLonWidget.setLat(getDisplayConventions()
379                                                .formatLatLon(
380                                                                probeLocation.getLatitude().getValue(
381                                                                                CommonUnit.degree)));
382
383                                latLonWidget.setLon(getDisplayConventions().formatLatLon(
384                                                probeLocation.getLongitude()
385                                                                .getValue(CommonUnit.degree)));
386
387                        }
388                        // Misc.run(this, "doAnalysis");
389
390                } catch (Exception e) {
391                        logException("Handling probe changed", e);
392                }
393        }
394
395        /**
396         * _more_
397         */
398        private void doAnalysis() {
399                if (running) {
400                        return;
401                }
402                running = true;
403                aodtBtn.setEnabled(false);
404                aodtBtn.setText("Running");
405
406                Misc.run(new Runnable() {
407                        public void run() {
408                                doAnalysisInner();
409                                running = false;
410                                aodtBtn.setEnabled(true);
411                        }
412                });
413
414        }
415
416        /**
417         * _more_
418         */
419        private void doAnalysisInner() {
420                FlatField ffield = null;
421                StormAODT sint = new StormAODT();
422                int sid = 0;
423                int channel = 0;
424
425                if (probeLocation == null) {
426                        return;
427                }
428                // Set timeset = null;
429                RealTuple timeTuple = null;
430                List sources = new ArrayList();
431                Real tt = null;
432                DateTime dat = null;
433                boolean isTemp = false;
434                choice.getDataSources(sources);
435                try {
436                        List infos = getDisplayInfos();
437                        DataInstance de = getDataInstance();
438                        DisplayInfo displayInfo = (DisplayInfo) infos.get(0);
439
440                        Animation anime = displayInfo.getViewManager().getAnimation();
441                        Set timeSet = anime.getSet();
442                        int pos = anime.getCurrent();
443                        ffield = DataUtil.getFlatField(de.getData());
444                        DataSourceImpl dsi = (DataSourceImpl) sources.get(0);
445
446                        if (dsi instanceof AddeImageDataSource) {
447                                ImageDataSource dds = (ImageDataSource) sources.get(0);
448                                List imageLists = dds.getImageList();
449
450                                AddeImageDescriptor aid = (AddeImageDescriptor) imageLists
451                                                .get(pos);
452                                AreaDirectory ad = aid.getDirectory();
453                                sid = ad.getSensorID();
454                                int[] bands = ad.getBands();
455                                channel = bands[0];
456
457                                isTemp = Util
458                                                .isCompatible(ffield, AirTemperature.getRealType());
459                        } else {
460                                channel = 4;
461                                sid = 70;
462                                String name = ffield.getSample(0).getType().prettyString();
463                                if (!name.contains("IR")) {
464                                        text = "Storm intensity analysis only running over Infrared field";
465                                        textComp.setText(text);
466                                        return;
467                                }
468                        }
469
470                        timeTuple = DataUtility.getSample(timeSet, pos);
471                        tt = (Real) timeTuple.getComponent(0);
472                        dat = new DateTime(tt);
473                } catch (VisADException e) {
474                        logException("Handling data", e);
475                        return;
476                } catch (RemoteException f) {
477                }
478
479                String shortName = choice.getName();
480
481                float cenlat = (float) probeLocation.getLatitude().getValue();
482                float cenlon = (float) probeLocation.getLongitude().getValue();
483                double curtime = dat.getValue();
484
485                String g_domain = ocean[oceanIndex]; // "ATL";
486                int cursat = 0;
487                int posm = 1;
488
489                if (domainIndex == 1) {
490                        text = "Storm intensity analysis not available over land";
491                        textComp.setText(text);
492                        return;
493                }
494
495                StormAODTInfo.IRData result = sint.aodtv72_drive(ffield, cenlat,
496                                cenlon, posm, curtime, cursat, g_domain, sid, channel, isTemp);
497                text = StormAODTUtil.aodtv72_textscreenoutput(result,
498                                getDisplayConventions().getLatLonFormat());
499                textComp.setText(text);
500        }
501
502        /**
503         * _more_
504         * 
505         * @param data
506         *            _more_
507         * 
508         * @return _more_
509         * 
510         * @throws RemoteException
511         *             _more_
512         * @throws VisADException
513         *             _more_
514         */
515        protected FlatField getFlatField(FieldImpl data) throws VisADException,
516                        RemoteException {
517                FlatField ff = null;
518                if (GridUtil.isSequence(data)) {
519                        ff = (FlatField) data.getSample(0);
520                } else {
521                        ff = (FlatField) data;
522                }
523                return ff;
524        }
525
526        /**
527         * Map the screen x/y of the event to an earth location
528         * 
529         * @param event
530         *            The event
531         * 
532         * @return The earth location
533         * 
534         * @throws java.rmi.RemoteException
535         *             When bad things happen
536         * @throws visad.VisADException
537         *             When bad things happen
538         * 
539         * @throws RemoteException
540         *             _more_
541         * @throws VisADException
542         *             _more_
543         */
544        public EarthLocation toEarth(DisplayEvent event) throws VisADException,
545                        RemoteException {
546                NavigatedDisplay d = getNavigatedDisplay();
547                return (d == null) ? null : d.getEarthLocation(toBox(event));
548        }
549
550        /**
551         * _more_
552         * 
553         * @param el
554         *            _more_
555         */
556        public void addAODT(EarthLocation el) {
557                final JDialog dialog = GuiUtils.createDialog("RUN AODT", true);
558                String question = "Please select storm center";
559                String label = "latitude: ";
560                String label1 = "longitude: ";
561                final JTextField field = new JTextField("", 10);
562                final JTextField field1 = new JTextField("", 10);
563
564                ObjectListener listener = new ObjectListener(new Boolean(false)) {
565                        public void actionPerformed(ActionEvent ae) {
566                                String cmd = ae.getActionCommand();
567                                if ((ae.getSource() == field) || cmd.equals(GuiUtils.CMD_OK)) {
568                                        theObject = new Boolean(true);
569                                } else {
570                                        theObject = new Boolean(false);
571                                }
572                                dialog.setVisible(false);
573                        }
574                };
575                ObjectListener listener1 = new ObjectListener(new Boolean(false)) {
576                        public void actionPerformed(ActionEvent ae) {
577                                String cmd = ae.getActionCommand();
578                                if ((ae.getSource() == field1) || cmd.equals(GuiUtils.CMD_OK)) {
579                                        theObject = new Boolean(true);
580                                } else {
581                                        theObject = new Boolean(false);
582                                }
583                                dialog.setVisible(false);
584                        }
585                };
586                field.addActionListener(listener);
587                field.addActionListener(listener1);
588                List comps = new ArrayList();
589
590                comps.add(GuiUtils.left(GuiUtils.inset(new JLabel(question), 4)));
591
592                JPanel topb = GuiUtils.doLayout(new Component[] {
593                                GuiUtils.rLabel(label),
594                                GuiUtils.hbox(field, GuiUtils.filler()),
595                                GuiUtils.rLabel(label1),
596                                GuiUtils.hbox(field1, GuiUtils.filler()) }, 4,
597                                GuiUtils.WT_NYNY, GuiUtils.WT_N);
598
599                comps.add(topb);
600
601                JComponent contents = GuiUtils.inset(GuiUtils.centerBottom(GuiUtils
602                                .vbox(comps), GuiUtils.makeOkCancelButtons(listener1)), 4);
603
604                GuiUtils.packDialog(dialog, contents);
605                Dimension ss = Toolkit.getDefaultToolkit().getScreenSize();
606
607                Point ctr = new Point(ss.width / 2 - 100, ss.height / 2 - 100);
608                dialog.setLocation(ctr);
609                dialog.setVisible(true);
610
611        }
612
613        /**
614         * Set the ProbeLocation property.
615         * 
616         * @param value
617         *            The new value for ProbeLocation
618         */
619        public void setProbeLocation(LatLonPoint value) {
620                probeLocation = value;
621        }
622
623        /**
624         * Get the ProbeLocation property.
625         * 
626         * @return The ProbeLocation
627         */
628        public LatLonPoint getProbeLocation() {
629                return probeLocation;
630        }
631
632        /**
633         * Set the RunOnClick property.
634         * 
635         * @param value
636         *            The new value for RunOnClick
637         */
638        public void setRunOnClick(boolean value) {
639                this.runOnClick = value;
640        }
641
642        /**
643         * Get the RunOnClick property.
644         * 
645         * @return The RunOnClick
646         */
647        public boolean getRunOnClick() {
648                return this.runOnClick;
649        }
650
651}