001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
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 https://www.gnu.org/licenses/.
027 */
028
029package edu.wisc.ssec.mcidasv.chooser.adde;
030
031import static javax.swing.GroupLayout.DEFAULT_SIZE;
032import static javax.swing.GroupLayout.PREFERRED_SIZE;
033import static javax.swing.GroupLayout.Alignment.BASELINE;
034import static javax.swing.GroupLayout.Alignment.LEADING;
035import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
036
037import java.util.ArrayList;
038import java.util.Hashtable;
039import java.util.List;
040
041import javax.swing.GroupLayout;
042import javax.swing.JComponent;
043import javax.swing.JLabel;
044import javax.swing.JPanel;
045
046import org.w3c.dom.Element;
047
048import ucar.unidata.data.AddeUtil;
049import ucar.unidata.data.DataSelection;
050import ucar.unidata.data.profiler.AddeProfilerDataSource;
051import ucar.unidata.idv.chooser.IdvChooserManager;
052import ucar.unidata.metdata.NamedStationTable;
053import ucar.unidata.util.GuiUtils;
054import ucar.unidata.util.Misc;
055import ucar.unidata.util.TwoFacedObject;
056import ucar.unidata.view.station.StationLocationMap;
057import ucar.unidata.xml.XmlResourceCollection;
058
059import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
060
061/**
062 * Selection widget for specifing data sources of
063 * NOAA National Profiler Network data.
064 * For selecting Profiler data source; user selects ADDE server,
065 * profiler station(s),
066 * and choice of data interval such as hourly or 6 minute.
067 *
068 * Metadata about the station (lat, lon. elevation)
069 * and about the request is made available by "get" methods.
070 *
071 * @author Unidata IDV Development Team
072 * @version $Revision$
073 */
074public class AddeProfilerDataChooser extends AddePointDataChooser {
075    
076    /** collection of station tables */
077    private XmlResourceCollection stationResources;
078
079    /**
080     * ctor
081     *
082     * @param mgr The chooser manager
083     * @param root The chooser.xml node
084     */
085    public AddeProfilerDataChooser(IdvChooserManager mgr, Element root) {
086        super(mgr, root);
087                    
088        descriptorsAllowPrefix = "PROF";
089                
090    }
091    
092    /**
093     * Tell the AddeChooser our name
094     *
095     * @return  The name
096     */
097    public String getDataName() {
098        return "Profiler Data";
099    }
100
101    /**
102     * Get the descriptor widget label.
103     *
104     * @return  label for the descriptor  widget
105     */
106    public String getDescriptorLabel() { 
107        return "Profiler Type"; 
108    }
109        
110    /**
111     * Overwrite base class method to create the station map
112     * with the appropriate properties.
113     *
114     * @return The new station map
115     */
116    protected StationLocationMap createStationMap() {
117        return new StationLocationMap(true, (String) null, StationLocationMap.TEMPLATE_NAME) {
118            public void setDeclutter(boolean declutter) {
119                super.setDeclutter(declutter);
120                updateStatus();
121            }
122        };
123    }
124
125    /**
126     * Initialize  the  station map
127     *
128     * @param stationMap The station map to initialize
129     */
130    protected void initStationMap(StationLocationMap stationMap) {
131        super.initStationMap(stationMap);
132
133        // get station information from the xml file listed
134        if (stationResources == null) {
135            List resources =
136                Misc.newList(
137                    "/ucar/unidata/idv/resources/stations/profilerstns.xml");
138            stationResources = new XmlResourceCollection("", resources);
139        }
140
141        // create an object to hold the station info
142        NamedStationTable stationTable =
143            NamedStationTable.createStationTable(stationResources.getRoot(0));
144
145
146        List listOfTables =
147            NamedStationTable.createStationTables(stationResources);
148        if (listOfTables.size() > 0) {
149            NamedStationTable profStations =
150                (NamedStationTable) listOfTables.get(0);
151            // Take this out if we only want to init stations 
152            // when we connect to the server. 
153            //   each "value" is a full Station object, not the name string
154            stationMap.setStations(new ArrayList(profStations.values()));
155        } else {
156            //What to do if there are no stations
157        }
158    }
159
160    /**
161     * Get any extra key=value pairs that are appended to all requests.
162     *
163     * @param buff The buffer to append onto
164     */
165    protected void appendMiscKeyValues(StringBuffer buff) {
166        appendKeyValue(buff, PROP_POS, getDoRelativeTimes() ? "ALL" : "0");
167        super.appendMiscKeyValues(buff);
168    }
169
170    /**
171     * Override this to determine how to select sample
172     */
173    protected void appendTimesRequest(StringBuffer buf) {
174        appendKeyValue(buf, PROP_SELECT, "'IDA BLMM'");
175    }
176    
177    /**
178     * Do we have times selected. Either we are doing absolute
179     * times and there are some selected in the list. Or we
180     * are doing relative times and we have done a connect to the
181     * server
182     *
183     * @return Do we have times
184     */
185    public boolean timesOk() {
186        if (usingStations() && (stationMap.getStations().size() > 0)
187                && (getSelectedStations().size() == 0)) {
188            return false;
189        }
190        return super.timesOk();
191    }
192    
193    /**
194     * Get the selection event from the profiler data chooser
195     * and process it, creating a ADDE.PROFILER data source
196     *
197     */
198    public void doLoadInThread() {
199        showWaitCursor();
200        try {
201            List selectedStations = getSelectedStations();
202
203            // make properties Hashtable to hand some 
204            //  data selection metadata
205            // to the AddeProfilerDataSource where it helps process 
206            // the data from the server into data format this IDV
207            // needs for this request.
208
209            Hashtable profilersourceHT = new Hashtable();
210
211            profilersourceHT.put(AddeProfilerDataSource.PROFILER_INT,
212                    getRelBoxString());
213            profilersourceHT.put(AddeProfilerDataSource.PROFILER_DATAINT,
214                    getDescriptor());
215            profilersourceHT.put(AddeProfilerDataSource.PROFILER_SERVER,
216                    getServer());
217            profilersourceHT.put(AddeProfilerDataSource.PROFILER_TIMES,
218                    getDayTimeSelectString());
219            profilersourceHT.put(AddeUtil.NUM_RELATIVE_TIMES,
220                    getRelativeTimeIndices());
221            profilersourceHT.put(AddeUtil.RELATIVE_TIME_INCREMENT,
222                    new Float(getRelativeTimeIncrement()));
223            profilersourceHT.put(AddeUtil.MISC_KEYWORDS,
224                    getMiscKeywords());
225
226            profilersourceHT.put(DataSelection.PROP_CHOOSERTIMEMATCHING, getDoTimeDrivers());
227            //System.out.println("   pc time list "+getSelectedTimes());
228            //System.out.println
229            // ("   pc data display interval "+getSelectedDataInterval());
230            //System.out.println
231            // ("  pc data source interval  "+getDataSourceInterval());
232
233            // hard-coded "ADDE.PROFILER" is in idv/resources/datasource.xml,
234            // which tells IDV to use code 
235            // ucar.unidata.data.profiler.AddeProfilerDataSource
236            makeDataSource(selectedStations, "ADDE.PROFILER",
237                           profilersourceHT);
238            saveServerState();
239        } catch (Exception excp) {
240            logException("Unable to open Profiler dataset", excp);
241        }
242        showNormalCursor();
243        // uncheck the check box every time click the add source button
244        drivercbx.setSelected(false);
245        enableTimeWidgets();
246        setDoTimeDrivers(false);
247    }
248        
249    /**
250     * Get the extra time widget, but built in a different way.
251     * Designed to be put into a GroupLayout
252     */
253    protected JComponent getExtraTimeComponent() {
254        TwoFacedObject[] intervals = { 
255                new TwoFacedObject(AddeProfilerDataSource.PROFILER_6MIN, .2f),
256                new TwoFacedObject(AddeProfilerDataSource.PROFILER_12MIN, .1f),
257                new TwoFacedObject(AddeProfilerDataSource.PROFILER_30MIN, .5f),
258                new TwoFacedObject(AddeProfilerDataSource.PROFILER_1HR, 1f)
259        };
260
261        GuiUtils.setListData(relTimeIncBox, intervals);
262        if (relTimeIncBox.getItemCount()>=4) relTimeIncBox.setSelectedIndex(3);
263        
264        return McVGuiUtils.makeLabeledComponent(relTimeIncLabel, relTimeIncBox, McVGuiUtils.Position.LEFT);
265    }
266        
267    /**
268     * Make the UI for this selector.
269     *
270     * @return The gui
271     */
272    public JComponent doMakeContents() {      
273        JPanel myPanel = new JPanel();
274                        
275        JLabel stationLabel = McVGuiUtils.makeLabelRight("Stations:");
276        addServerComp(stationLabel);
277
278        JComponent stationPanel = getStationMap();
279        registerStatusComp("stations", stationPanel);
280        addServerComp(stationPanel);
281        
282        JLabel timesLabel = McVGuiUtils.makeLabelRight("Times:");
283        addDescComp(timesLabel);
284        
285        JPanel timesPanel = makeTimesPanel();
286        timesPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
287        addDescComp(timesPanel);
288        
289        enableWidgets();
290        updateStatus();
291
292        GroupLayout layout = new GroupLayout(myPanel);
293        myPanel.setLayout(layout);
294        layout.setHorizontalGroup(
295            layout.createParallelGroup(LEADING)
296            .addGroup(layout.createSequentialGroup()
297                .addGroup(layout.createParallelGroup(LEADING)
298                    .addGroup(layout.createSequentialGroup()
299                        .addComponent(descriptorLabel)
300                        .addGap(GAP_RELATED)
301                        .addComponent(descriptorComboBox))
302                    .addGroup(layout.createSequentialGroup()
303                        .addComponent(stationLabel)
304                        .addGap(GAP_RELATED)
305                        .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
306                    .addGroup(layout.createSequentialGroup()
307                        .addComponent(timesLabel)
308                        .addGap(GAP_RELATED)
309                        .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))))
310        );
311        layout.setVerticalGroup(
312            layout.createParallelGroup(LEADING)
313            .addGroup(layout.createSequentialGroup()
314                .addGroup(layout.createParallelGroup(BASELINE)
315                    .addComponent(descriptorLabel)
316                    .addComponent(descriptorComboBox))
317                .addPreferredGap(RELATED)
318                .addGroup(layout.createParallelGroup(LEADING)
319                    .addComponent(stationLabel)
320                    .addComponent(stationPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
321                .addPreferredGap(RELATED)
322                .addGroup(layout.createParallelGroup(LEADING)
323                    .addComponent(timesLabel)
324                    .addComponent(timesPanel, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
325                .addPreferredGap(RELATED))
326        );
327        
328        setInnerPanel(myPanel);
329        return super.doMakeContents(true);
330    }
331
332}
333