001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
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    
029    package edu.wisc.ssec.mcidasv.data.hrit;
030    
031    import java.awt.BorderLayout;
032    import java.awt.FlowLayout;
033    import java.io.File;
034    import java.io.IOException;
035    import java.rmi.RemoteException;
036    import java.util.ArrayList;
037    import java.util.Hashtable;
038    import java.util.List;
039    
040    import javax.swing.JComboBox;
041    import javax.swing.JComponent;
042    import javax.swing.JPanel;
043    
044    import edu.wisc.ssec.mcidas.Calibrator;
045    
046    import visad.Data;
047    import visad.VisADException;
048    import visad.data.hrit.HRITAdapter;
049    
050    import ucar.unidata.data.DataCategory;
051    import ucar.unidata.data.DataChoice;
052    import ucar.unidata.data.DataSelection;
053    import ucar.unidata.data.DataSelectionComponent;
054    import ucar.unidata.data.DataSourceDescriptor;
055    import ucar.unidata.data.DataSourceImpl;
056    import ucar.unidata.data.DirectDataChoice;
057    import ucar.unidata.util.Misc;
058    import ucar.unidata.util.WrapperException;
059    
060    public 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</code>
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</code>
104         * @param  sources   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 <code>DataChoice</code>-s for this
189         * <code>DataSource</code>.
190         */
191        public void doMakeDataChoices() {
192            DataChoice choice = null;
193            
194            for (int i = 0; i < sources.size(); i++) {
195                    String fileNameFullPath = (String) sources.get(i);
196                    if (fileNameFullPath.contains("MSG2")) {
197                            String channelStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 13, fileNameFullPath.lastIndexOf("MSG2") + 19);
198                            String timeStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 33, fileNameFullPath.lastIndexOf("MSG2") + 45);
199                            String segStr = fileNameFullPath.substring(fileNameFullPath.lastIndexOf("MSG2") + 27, fileNameFullPath.lastIndexOf("MSG2") + 29);
200                            try {
201                                    choice = doMakeDataChoice(0, "MSG2 " + channelStr + " " + timeStr + " SEGMENT " + segStr);
202                            } 
203                            catch (Exception e) {
204                                    e.printStackTrace();
205                                    System.out.println("doMakeDataChoice failed");
206                            }
207    
208                            if (choice != null) {
209                                    addDataChoice(choice);
210                            }
211                    }
212            }
213    
214        }
215        
216        private DataChoice doMakeDataChoice(int idx, String var) throws Exception {
217            String name = var;
218            Hashtable ht = null;
219            DirectDataChoice ddc = new DirectDataChoice(this, idx, name, name, categories, ht);
220            return ddc;
221        }
222        
223        /**
224         * Create, if needed, and return the list of adapters.
225         * Will return null if there are no valid adapters.
226         *
227         * @return List of adapters or null
228         */
229        protected List getAdapters() {
230            if ((adapters == null) || (adapters.size() == 0)) {
231                try {
232                    makeAdapters(sources);
233                } catch (Exception exc) {
234                    setInError(true);
235                    throw new WrapperException(exc);
236                }
237            }
238            if (adapters.size() == 0) {
239                adapters = null;
240            }
241            return adapters;
242        }
243    
244        /**
245         * Make the adapters for the given list of files
246         *
247         * @param files Data files
248         *
249         * @throws Exception When bad things happen
250         */
251        private void makeAdapters(List files) throws Exception {
252            adapters = new ArrayList();
253        }
254    
255    
256        /**
257         * Create the list of times associated with this DataSource.
258         * @return list of times.
259         */
260        protected List doMakeDateTimes() {
261            List    times      = new ArrayList();
262            return times;
263        }
264    
265        /**
266         * Get the data for the given DataChoice and selection criteria.
267         * @param dataChoice         DataChoice for selection
268         * @param category           DataCategory for the DataChoice (not used)
269         * @param resolution         resolution criteria
270         * @param requestProperties  extra request properties
271         * @return  the Data object for the request
272         *
273         * @throws RemoteException couldn't create a remote data object
274         * @throws VisADException  couldn't create the data
275         */
276        protected Data getDataInner(DataChoice dataChoice, DataCategory category,
277                                    DataSelection dataparams,
278                                    Hashtable requestProperties)
279                throws VisADException, RemoteException {
280    
281            // for now, hardcoded array of band center wave numbers, such that'
282            // the array index is the band number
283            String[] bandCWN = { 
284                            "N/A", "006", "008", "016", "039", "062", "073",
285                            "087", "097", "108", "120", "134", "___"
286            };
287            
288            // XXX TJJ need to determine this from data type and wavelength
289            int bandNum = 1;
290            // default to BRIT calibration, will check if user picked something else
291            int calType = Calibrator.CAL_BRIT;
292            
293            String newRes = (String) dataparams.getProperty("magnification");
294            int magFactor = 1;
295            if (newRes != null) {
296                    try {
297                            magFactor = Integer.parseInt(newRes);
298                    } catch (NumberFormatException nfe) {
299                            nfe.printStackTrace();
300                    }
301            }
302    
303            // pull out source index 
304            String idxStr = dataChoice.getName().substring(dataChoice.getName().length() - 2, dataChoice.getName().length());
305            
306            Data data = null;
307            
308            String [] files = new String[1];
309            // initialize central wave number string
310            String cwnStr = "006";
311            for (int i = 0; i < sources.size(); i++) {
312                    String tmpStr = (String) sources.get(i);
313                    cwnStr = tmpStr.substring(tmpStr.lastIndexOf("MSG2") + 16, tmpStr.lastIndexOf("MSG2") + 19);
314                    String segStr = tmpStr.substring(tmpStr.lastIndexOf("MSG2") + 27, tmpStr.lastIndexOf("MSG2") + 29);
315                    if (segStr.equals(idxStr)) {
316                            files[0] = (String) sources.get(i);
317                    }
318            }
319            
320            // match up central wave number with band number index
321            for (int i = 0; i < bandCWN.length; i++) {
322                    if (bandCWN[i].equals(cwnStr)) {
323                            bandNum = i;
324                            break;
325                    }
326            }
327            
328            String newCal = (String) dataparams.getProperty("calibration");
329            // do checks to only allow valid calibrations here
330            if (newCal != null) {
331                    if ((bandNum >= 4) && (bandNum <= 11)) {
332                            if (newCal.equals("RAD")) {
333                                    calType = Calibrator.CAL_RAD;
334                            }
335                            if (newCal.equals("TEMP")) {
336                                    calType = Calibrator.CAL_TEMP;
337                            }
338                            if (newCal.equals("BRIT")) {
339                                    calType = Calibrator.CAL_BRIT;
340                            }
341                    } else {
342                            if (newCal.equals("RAD")) {
343                                    calType = Calibrator.CAL_RAD;
344                            }
345                            if (newCal.equals("ALB")) {
346                                    calType = Calibrator.CAL_ALB;
347                            }
348                            if (newCal.equals("BRIT")) {
349                                    calType = Calibrator.CAL_BRIT;
350                            }                       
351                    }
352            }
353    
354            HRITAdapter ha;
355                    try {
356                            ha = new HRITAdapter(files, magFactor, calType, bandNum);
357                            data = ha.getData();
358                    } catch (IOException e) {
359                            e.printStackTrace();
360                    }
361    
362                    return data;
363        }
364    
365        protected void initDataSelectionComponents(
366                    List<DataSelectionComponent> components,
367                    final DataChoice dataChoice) {
368    
369            try {
370                    components.add(new ResolutionSelection(dataChoice));
371            } 
372            catch (Exception e) {
373                    e.printStackTrace();
374            }
375        }
376    
377    
378        class ResolutionSelection extends DataSelectionComponent {
379    
380            DataChoice dataChoice;
381            JPanel display;
382            JComboBox jcbMag = null;
383            JComboBox jcbCal = null;
384    
385            ResolutionSelection(DataChoice dataChoice) throws Exception {
386                    super("Magnification and Calibration");
387                    this.dataChoice = dataChoice;
388                    List names = dataChoice.getCurrentNames();
389                    display = new JPanel(new FlowLayout());
390                    String[] resStrings = { "1", "2", "4", "8", "16" };
391                    jcbMag = new JComboBox(resStrings);
392                    display.add(jcbMag);
393                    String[] irCalStrings  = { "BRIT", "RAD", "RAW", "TEMP" };
394                    String[] visCalStrings = { "BRIT", "RAD", "RAW", "ALB" };
395                    // XXX TJJ - we need a standard mechanism to make this determination
396                    // this is a temporary cheap hack: grab the last file name added and 
397                    // do a hardcoded string match.
398                    String sampleFileName = names.get(names.size() - 1).toString();
399                    // those below are considered "visible" bands, yes even IR_016!
400                    if ((sampleFileName.contains("VIS")) ||
401                            (sampleFileName.contains("HRV")) ||
402                            (sampleFileName.contains("IR_016"))
403                                    ) {
404                            jcbCal = new JComboBox(visCalStrings);
405                    } else {
406                            jcbCal = new JComboBox(irCalStrings);
407                    }
408                    display.add(jcbCal);
409            }
410    
411            protected JComponent doMakeContents() {
412                    try {
413                            JPanel panel = new JPanel(new BorderLayout());
414                            panel.add("Center", display);
415                            return panel;
416                    }
417                    catch (Exception e) {
418                            System.out.println(e);
419                    }
420                    return null;
421            }
422    
423            public void applyToDataSelection(DataSelection dataSelection) {
424                    try {
425                            dataSelection.putProperty("magnification", jcbMag.getSelectedItem());
426                            dataSelection.putProperty("calibration", jcbCal.getSelectedItem());
427                    } catch (Exception e) {
428                            e.printStackTrace();
429                    }
430            }
431        }
432    }