001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2016
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.data.hrit;
030
031import java.awt.BorderLayout;
032import java.awt.FlowLayout;
033import java.io.File;
034import java.io.IOException;
035import java.rmi.RemoteException;
036import java.util.ArrayList;
037import java.util.Hashtable;
038import java.util.List;
039
040import javax.swing.JComboBox;
041import javax.swing.JComponent;
042import javax.swing.JPanel;
043
044import edu.wisc.ssec.mcidas.Calibrator;
045
046import visad.Data;
047import visad.VisADException;
048import visad.data.hrit.HRITAdapter;
049
050import ucar.unidata.data.DataCategory;
051import ucar.unidata.data.DataChoice;
052import ucar.unidata.data.DataSelection;
053import ucar.unidata.data.DataSelectionComponent;
054import ucar.unidata.data.DataSourceDescriptor;
055import ucar.unidata.data.DataSourceImpl;
056import ucar.unidata.data.DirectDataChoice;
057import ucar.unidata.util.Misc;
058import ucar.unidata.util.WrapperException;
059
060public class HRITDataSource extends DataSourceImpl  {
061
062    /** List of sources files */
063    protected List sources;
064
065    public static String request;
066
067    /** List of sources files */
068    protected List adapters;
069    
070    private List categories;
071
072    /** for unpersistence */
073    protected String oldSourceFromBundles;
074    
075    private static final String DATA_DESCRIPTION = "HRIT Data";
076    
077    private static int counter = 1;
078
079    /** children choices */
080    private List myDataChoices = new ArrayList();
081
082    /**
083     * Default constructor
084     */
085    public HRITDataSource() {}
086
087    /**
088     * Construct a new HRIT data source.
089     * @param  descriptor  descriptor for this {@code DataSource}
090     * @param  fileName  name of the HRIT segment file to read
091     * @param  properties  hashtable of properties
092     *
093     * @throws VisADException problem creating data
094     */
095    public HRITDataSource(DataSourceDescriptor descriptor,
096                                 String fileName, Hashtable properties)
097            throws VisADException {
098        this(descriptor, Misc.newList(fileName), properties);
099    }
100    
101    /**
102     * Construct a new HRIT data source.
103     * @param  descriptor  descriptor for this {@code DataSource}
104     * @param  newSources  List of filenames
105     * @param  properties  hashtable of properties
106     *
107     * @throws VisADException problem creating data
108     */
109    public HRITDataSource(DataSourceDescriptor descriptor,
110                                 List newSources, Hashtable properties)
111            throws VisADException {
112        
113        this(descriptor, newSources, DATA_DESCRIPTION, properties);
114        boolean looksOk = false;
115        String dataCategoryStr = "HRIT Data";
116        if ((newSources != null) && (newSources.size() >= 1)) {
117                String fileNameFullPath = (String) newSources.get(0);
118                if ((fileNameFullPath != null) && (fileNameFullPath.length() >= 58)) {
119                        if ((fileNameFullPath.contains("MSG2")) && (fileNameFullPath.endsWith("-__"))) {
120                                String channelStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 13, fileNameFullPath.lastIndexOf("MSG2") + 19);
121                                String timeStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 33, fileNameFullPath.lastIndexOf("MSG2") + 45);
122                                dataCategoryStr = "MSG2 " + channelStr + " " + timeStr;
123                                looksOk = true;
124                        }
125                }
126        }
127        if (looksOk) {
128                DataCategory.createCategory(dataCategoryStr);
129                categories = DataCategory.parseCategories(dataCategoryStr + ";IMAGE");
130        } else {
131                throw new VisADException("Not a decompressed MSG HRIT file");
132        }
133    }    
134
135        /**
136     * Create a HRITDataSource
137     *
138     * @param descriptor The datasource descriptor
139     * @param newSources List of files or urls
140     * @param description The long name
141     * @param properties properties
142     *
143     * @throws VisADException  couldn't create the data
144     */
145    public HRITDataSource(DataSourceDescriptor descriptor, List newSources,
146                           String description, Hashtable properties) 
147            throws VisADException {
148
149        super(descriptor, "HRIT" + counter, "HRIT" + counter, properties);
150        counter++;
151        sources = newSources;
152    }
153
154
155    /**
156     * Can this data source save its data to local disk
157     *
158     * @return can save to local disk
159     */
160    public boolean canSaveDataToLocalDisk() {
161        return !isFileBased() && (getProperty(PROP_SERVICE_HTTP) != null);
162    }
163
164
165    /**
166     * Are we getting data from a file or from server
167     * 
168     * @return is the data from files
169     */
170    protected boolean isFileBased() {
171        if (sources.size() == 0) {
172            return false;
173        }
174        return (new File(sources.get(0).toString())).exists();
175    }
176
177    /**
178     * This is called when the CacheManager detects the need ot clear memory.
179     * It is intended to be overwritten by derived classes that are holding cached
180     * data that is not in the normal putCache facilities provided by this class
181     * since that data is actually managed by the CacheManager
182     */
183    public void clearCachedData() {
184        super.clearCachedData();
185    }
186    
187    /**
188     * Make and insert the {@link DataChoice DataChoices} for this {@code DataSource}.
189     */
190    public void doMakeDataChoices() {
191        DataChoice choice = null;
192        
193        for (int i = 0; i < sources.size(); i++) {
194                String fileNameFullPath = (String) sources.get(i);
195                if (fileNameFullPath.contains("MSG2")) {
196                        String channelStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 13, fileNameFullPath.lastIndexOf("MSG2") + 19);
197                        String timeStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 33, fileNameFullPath.lastIndexOf("MSG2") + 45);
198                        String segStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 27, fileNameFullPath.lastIndexOf("MSG2") + 29);
199                        try {
200                                choice = doMakeDataChoice(0, "MSG2 " + channelStr + " " + timeStr + " SEGMENT " + segStr);
201                        } 
202                        catch (Exception e) {
203                                e.printStackTrace();
204                                System.out.println("doMakeDataChoice failed");
205                        }
206
207                        if (choice != null) {
208                                addDataChoice(choice);
209                        }
210                }
211        }
212
213    }
214    
215    private DataChoice doMakeDataChoice(int idx, String var) throws Exception {
216        String name = var;
217        Hashtable ht = null;
218        DirectDataChoice ddc = new DirectDataChoice(this, idx, name, name, categories, ht);
219        return ddc;
220    }
221    
222    /**
223     * Create, if needed, and return the list of adapters.
224     * Will return null if there are no valid adapters.
225     *
226     * @return List of adapters or null
227     */
228    protected List getAdapters() {
229        if ((adapters == null) || (adapters.size() == 0)) {
230            try {
231                makeAdapters(sources);
232            } catch (Exception exc) {
233                setInError(true);
234                throw new WrapperException(exc);
235            }
236        }
237        if (adapters.size() == 0) {
238            adapters = null;
239        }
240        return adapters;
241    }
242
243    /**
244     * Make the adapters for the given list of files
245     *
246     * @param files Data files
247     *
248     * @throws Exception When bad things happen
249     */
250    private void makeAdapters(List files) throws Exception {
251        adapters = new ArrayList();
252    }
253
254
255    /**
256     * Create the list of times associated with this DataSource.
257     * @return list of times.
258     */
259    protected List doMakeDateTimes() {
260        List    times      = new ArrayList();
261        return times;
262    }
263
264    /**
265     * Get the data for the given DataChoice and selection criteria.
266     * @param dataChoice         DataChoice for selection
267     * @param category           DataCategory for the DataChoice (not used)
268     * @param dataparams         Resolution criteria.
269     * @param requestProperties  extra request properties
270     * @return  the Data object for the request
271     *
272     * @throws RemoteException couldn't create a remote data object
273     * @throws VisADException  couldn't create the data
274     */
275    protected Data getDataInner(DataChoice dataChoice, DataCategory category,
276                                DataSelection dataparams,
277                                Hashtable requestProperties)
278            throws VisADException, RemoteException {
279
280        // for now, hardcoded array of band center wave numbers, such that'
281        // the array index is the band number
282        String[] bandCWN = { 
283                        "N/A", "006", "008", "016", "039", "062", "073",
284                        "087", "097", "108", "120", "134", "___"
285        };
286        
287        // XXX TJJ need to determine this from data type and wavelength
288        int bandNum = 1;
289        // default to BRIT calibration, will check if user picked something else
290        int calType = Calibrator.CAL_BRIT;
291        
292        String newRes = (String) dataparams.getProperty("magnification");
293        int magFactor = 1;
294        if (newRes != null) {
295                try {
296                        magFactor = Integer.parseInt(newRes);
297                } catch (NumberFormatException nfe) {
298                        nfe.printStackTrace();
299                }
300        }
301
302        // pull out source index 
303        String idxStr = dataChoice.getName().substring(dataChoice.getName().length() - 2, dataChoice.getName().length());
304        
305        Data data = null;
306        
307        String [] files = new String[1];
308        // initialize central wave number string
309        String cwnStr = "006";
310        for (int i = 0; i < sources.size(); i++) {
311                String tmpStr = (String) sources.get(i);
312                cwnStr = tmpStr.substring(tmpStr.lastIndexOf("MSG2") + 16, tmpStr.lastIndexOf("MSG2") + 19);
313                String segStr = tmpStr.substring(tmpStr.lastIndexOf("MSG2") + 27, tmpStr.lastIndexOf("MSG2") + 29);
314                if (segStr.equals(idxStr)) {
315                        files[0] = (String) sources.get(i);
316                }
317        }
318        
319        // match up central wave number with band number index
320        for (int i = 0; i < bandCWN.length; i++) {
321                if (bandCWN[i].equals(cwnStr)) {
322                        bandNum = i;
323                        break;
324                }
325        }
326        
327        String newCal = (String) dataparams.getProperty("calibration");
328        // do checks to only allow valid calibrations here
329        if (newCal != null) {
330                if ((bandNum >= 4) && (bandNum <= 11)) {
331                        if (newCal.equals("RAD")) {
332                                calType = Calibrator.CAL_RAD;
333                        }
334                        if (newCal.equals("TEMP")) {
335                                calType = Calibrator.CAL_TEMP;
336                        }
337                        if (newCal.equals("BRIT")) {
338                                calType = Calibrator.CAL_BRIT;
339                        }
340                } else {
341                        if (newCal.equals("RAD")) {
342                                calType = Calibrator.CAL_RAD;
343                        }
344                        if (newCal.equals("ALB")) {
345                                calType = Calibrator.CAL_ALB;
346                        }
347                        if (newCal.equals("BRIT")) {
348                                calType = Calibrator.CAL_BRIT;
349                        }                       
350                }
351        }
352
353        HRITAdapter ha;
354                try {
355                        ha = new HRITAdapter(files, magFactor, calType, bandNum);
356                        data = ha.getData();
357                } catch (IOException e) {
358                        e.printStackTrace();
359                }
360
361                return data;
362    }
363
364    protected void initDataSelectionComponents(
365                List<DataSelectionComponent> components,
366                final DataChoice dataChoice) {
367
368        try {
369                components.add(new ResolutionSelection(dataChoice));
370        } 
371        catch (Exception e) {
372                e.printStackTrace();
373        }
374    }
375
376
377    class ResolutionSelection extends DataSelectionComponent {
378
379        DataChoice dataChoice;
380        JPanel display;
381        JComboBox jcbMag = null;
382        JComboBox jcbCal = null;
383
384        ResolutionSelection(DataChoice dataChoice) throws Exception {
385                super("Magnification and Calibration");
386                this.dataChoice = dataChoice;
387                List names = dataChoice.getCurrentNames();
388                display = new JPanel(new FlowLayout());
389                String[] resStrings = { "1", "2", "4", "8", "16" };
390                jcbMag = new JComboBox(resStrings);
391                display.add(jcbMag);
392                String[] irCalStrings  = { "BRIT", "RAD", "RAW", "TEMP" };
393                String[] visCalStrings = { "BRIT", "RAD", "RAW", "ALB" };
394                // XXX TJJ - we need a standard mechanism to make this determination
395                // this is a temporary cheap hack: grab the last file name added and 
396                // do a hardcoded string match.
397                String sampleFileName = names.get(names.size() - 1).toString();
398                // those below are considered "visible" bands, yes even IR_016!
399                if ((sampleFileName.contains("VIS")) ||
400                        (sampleFileName.contains("HRV")) ||
401                        (sampleFileName.contains("IR_016"))
402                                ) {
403                        jcbCal = new JComboBox(visCalStrings);
404                } else {
405                        jcbCal = new JComboBox(irCalStrings);
406                }
407                display.add(jcbCal);
408        }
409
410        protected JComponent doMakeContents() {
411                try {
412                        JPanel panel = new JPanel(new BorderLayout());
413                        panel.add("Center", display);
414                        return panel;
415                }
416                catch (Exception e) {
417                        System.out.println(e);
418                }
419                return null;
420        }
421
422        public void applyToDataSelection(DataSelection dataSelection) {
423                try {
424                        dataSelection.putProperty("magnification", jcbMag.getSelectedItem());
425                        dataSelection.putProperty("calibration", jcbCal.getSelectedItem());
426                } catch (Exception e) {
427                        e.printStackTrace();
428                }
429        }
430    }
431}