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