001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2015
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.chooser;
030
031import java.awt.Component;
032import java.awt.Container;
033import java.awt.event.ActionEvent;
034import java.awt.event.ActionListener;
035import java.beans.PropertyChangeEvent;
036import java.beans.PropertyChangeListener;
037import java.io.File;
038import java.util.ArrayList;
039import java.util.Collections;
040import java.util.Vector;
041
042import javax.swing.JComboBox;
043import javax.swing.JFileChooser;
044import javax.swing.JLabel;
045import javax.swing.JPanel;
046import javax.swing.filechooser.FileFilter;
047
048import org.w3c.dom.Element;
049
050import ucar.unidata.idv.chooser.IdvChooserManager;
051import ucar.unidata.util.GuiUtils;
052import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
053
054public class HRITChooser extends FileChooser {
055
056        private static final long serialVersionUID = 1L;
057    
058    private HRITFilter hf = null;
059
060    private JLabel channelLabel = McVGuiUtils.makeLabelRight("Data Channel:");
061
062    /**
063     * Create the chooser with the given manager and xml
064     *
065     * @param mgr The manager
066     * @param root The xml
067     *
068     */
069    
070    public HRITChooser(IdvChooserManager mgr, Element root) {
071        super(mgr, root);
072    }
073    
074    /**
075     * Make the file chooser
076     *
077     * @param path   the initial path
078     *
079     * @return  the file chooser
080     */
081    
082    protected JFileChooser doMakeFileChooser(String path) {
083        return new HRITFileChooser(path);
084    }
085    
086    protected Vector<String> getAvailableHRITTypes(String path) {
087        if (path == null) path = ".";
088        
089        ArrayList<String> al = new ArrayList<String>();
090        Vector<String> v = new Vector<String>();
091        File f = new File(path);
092        File [] files = null;
093        if (f.isDirectory()) {
094                files = f.listFiles(
095                        new java.io.FileFilter() {
096                                public boolean accept(File f) {
097                            if ((f.getName().endsWith("__")) && (f.getName().matches(".*MSG[2-3].*"))) {
098                                return true;
099                            } else {
100                                return false;
101                            }
102                                }
103                        }
104                );
105        }
106        if (files != null) {
107                for (int i = 0; i < files.length; i++) {
108                String channelStr = files[i].getName().substring(26, 32);
109                if (channelStr.equals("______")) continue;
110                channelStr = channelStr.replace("___", "");
111                if (! al.contains(channelStr)) {
112                        al.add(channelStr);
113                }
114                }
115        }
116        Collections.sort(al);
117        for (int i = 0; i < al.size(); i++) {
118                v.add(al.get(i));
119        }
120        return v;
121    }
122    
123    public class ImageTypeChooser extends JComboBox implements ActionListener, PropertyChangeListener {
124        
125                private static final long serialVersionUID = 1L;
126                JFileChooser jfc = null;
127        
128        public ImageTypeChooser(JFileChooser fc, String path) {
129                jfc = fc;
130            Vector<String> availableTypes = getAvailableHRITTypes(path);
131            if (availableTypes.size() == 1 && availableTypes.get(0) == ".") {
132                availableTypes.removeAllElements();
133            }
134            reloadComboBox(availableTypes);
135            addActionListener(this);
136            McVGuiUtils.setComponentWidth(this, McVGuiUtils.Width.DOUBLE);
137        }
138        
139        public void actionPerformed(ActionEvent e) {
140            JComboBox cb = (JComboBox) e.getSource();
141            String newFilter = (String) cb.getSelectedItem();
142            HRITFilter hFilter = (HRITFilter) jfc.getFileFilter();
143            hFilter.setExtraFilter(newFilter);
144            jfc.rescanCurrentDirectory();
145        }
146        
147        public void reloadComboBox(Vector<String> v) {
148                removeAllItems();
149                if (v != null) {
150                        for (int i = 0; i < v.size(); i++) {
151                                addItem(v.get(i));
152                        }
153                }
154                if (v == null || v.size() == 0) {
155                        setEnabled(false);
156                        channelLabel.setEnabled(false);
157                }
158                else {
159                        setEnabled(true);
160                        channelLabel.setEnabled(true);
161                }
162        }
163        
164        public void propertyChange(PropertyChangeEvent e) {
165            String prop = e.getPropertyName();
166
167            // If the directory changed, reload the combo box with new image type choices.
168            if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals(prop)) {
169                Vector<String> availableTypes = getAvailableHRITTypes(jfc.getCurrentDirectory().getPath());
170                reloadComboBox(availableTypes);
171            }
172
173        }
174        
175    }
176    
177    /* HRITFilter */
178    public class HRITFilter extends FileFilter {
179        
180        String extraFilter = null;
181        
182        public HRITFilter(String extraFilter) {
183                super();
184                if (extraFilter != null) {
185                        this.extraFilter = extraFilter;
186                }
187        }
188        
189        // Accept all directories and all HRIT files.
190        public boolean accept(File f) {
191                
192            if (f.isDirectory()) {
193                return true;
194            }
195
196            // XXX TJJ - at present, we are ONLY allowing MSG2 and MSG3 segment data files
197            // through the filter which have already been Wavelet decompressed
198            // (i.e., they end with __ and not C_ )
199            String fileName = f.getName();
200            if ((fileName.endsWith("__")) && (fileName.matches(".*MSG[2-3].*")) && (fileName.length() >= 58)) {
201                if (extraFilter != null) {
202                        if (fileName.contains(extraFilter)) {
203                                return true;
204                        } else {
205                                return false;
206                        }
207                }
208            } else {
209                return false;
210            }
211            return false;
212
213        }
214
215        // The description of this filter
216        public String getDescription() {
217            return "HRIT Data";
218        }
219        
220        // change the additional filter string
221        public void setExtraFilter(String newFilter) {
222                if (newFilter != null) {
223                        extraFilter = newFilter;
224                        //seenPatterns.clear();
225                }
226        }
227        
228    }
229        
230    /**
231     * HRITFileChooser, an extension of JFileChooser
232     *
233     * @author Tommy Jasmin
234     */
235    
236    public class HRITFileChooser extends JFileChooser {
237
238        /**
239                 * default for serializable class
240                 */
241                private static final long serialVersionUID = 1L;
242
243                /**
244         * Create the file chooser
245         *
246         * @param path   the initial path
247         */
248                
249        public HRITFileChooser(String path) {
250            super(path);
251            setControlButtonsAreShown(false);
252            setMultiSelectionEnabled(false);
253            setAcceptAllFileFilterUsed(false);
254            processChildren(this);
255        }
256
257        private void processChildren(Container c) {
258                Component [] components = c.getComponents();
259                if (components != null) {
260                        // loop through all components, looking for the JLabel children of 
261                        // components we want to remove
262                        for (int i = 0; i < components.length; i++) {
263                                if (components[i] instanceof JLabel) {
264                                        String text = ((JLabel) components[i]).getText();
265                                        if (text.equals("File Name:")) {
266                                                hideChildren((Container) components[i].getParent());
267                                                continue;
268                                        }
269                                        if (text.equals("Files of Type:")) {
270                                                hideChildren((Container) components[i].getParent());
271                                                continue;
272                                        }
273                                }
274                                // now check this component for any children
275                                processChildren((Container) components[i]);
276                        }
277                }
278        }
279        
280        private void hideChildren(Container c) {
281                Component [] components = c.getComponents();
282                for (int i = 0; i < components.length; i++) {
283                        components[i].setVisible(false);
284                }
285                c.setVisible(false);
286        }
287
288        /**
289         * Approve the selection
290         */
291        
292        public void approveSelection() {
293            HRITChooser.this.doLoad();
294        }
295
296        /**
297         * Cancel the selection
298         */
299        
300        public void cancelSelection() {
301            closeChooser();
302        }
303
304        /**
305         * Set the selected files
306         *
307         * @param selectedFiles  the selected files
308         */
309        
310        public void setSelectedFiles(File[] selectedFiles) {
311                String channelStr = null;
312                String timeStr = null;
313                if (selectedFiles != null) {
314                        for (int i = 0; i < selectedFiles.length; i++) {
315                                if (! selectedFiles[i].isDirectory()) {
316                                        if (selectedFiles[i].getName().length() >= 58) {
317                                                channelStr = selectedFiles[i].getName().substring(26, 32);
318                                                timeStr = selectedFiles[i].getName().substring(46, 58);
319                                        }
320                                }
321                        }
322                }
323                File curDir = getCurrentDirectory();
324                File [] fileList = curDir.listFiles();
325                String tmpChannel = null;
326                String tmpTime = null;
327                ArrayList<File> matches = new ArrayList<File>();
328                for (int i = 0; i < fileList.length; i++) {
329                        if ((fileList[i].getName().endsWith("__")) && 
330                                (fileList[i].getName().matches(".*MSG[2-3].*")) && 
331                                (fileList[i].getName().length() >= 58)) {
332                                tmpChannel = fileList[i].getName().substring(26, 32);
333                                tmpTime = fileList[i].getName().substring(46, 58);
334                                if ((tmpChannel.equals(channelStr)) && (tmpTime.equals(timeStr))) {
335                                        matches.add(fileList[i]);
336                                }
337                        }
338                }
339                Collections.sort(matches);
340                
341                // make new file array from ArrayList matches
342                File [] fileSet = new File[matches.size()];
343                for (int i = 0; i < matches.size(); i++) {
344                        fileSet[i] = (File) matches.get(i);
345                }
346
347                super.setSelectedFiles(fileSet);
348            setHaveData( !((selectedFiles == null)
349                           || (selectedFiles.length == 0)));
350        }
351    }
352
353    /**
354     * Handle the selection of the set of files
355     *
356     * @param files The files the user chose
357     * @param directory The directory they chose them from
358     * @return True if the file was successful
359     * @throws Exception
360     */
361    
362    protected boolean selectFilesInner(File[] files, File directory)
363            throws Exception {
364        if ((files == null) || (files.length == 0)) {
365            userMessage("Please select a file");
366            return false;
367        }
368        
369        // only allow selection of files that make sense as a "set"
370        // for now, that means all part of single image for a single channel
371        String channelStr = files[0].getName().substring(26, 32);
372        String timeStr = files[0].getName().substring(46, 58);
373        int prvSegment = -1;
374        int curSegment = -1;
375        for (int i = 0; i < files.length; i++) {
376                try {
377                        curSegment = Integer.parseInt(files[i].getName().substring(40, 42));
378                } catch (NumberFormatException nfe) {
379                        userMessage("Problem determining image segment number for file: " + files[i].getName());
380                        return false;
381                }
382                if (!files[i].getName().substring(26, 32).equals(channelStr)) {
383                        userMessage("Selected data must be for a single channel and time");
384                        return false;
385                }
386                if (!files[i].getName().substring(46, 58).equals(timeStr)) {
387                        userMessage("Selected data must be for a single channel and time");
388                        return false;
389                }
390                if (prvSegment >= 0) {
391                        if (curSegment != (prvSegment + 1)) {
392                        userMessage("Selected data must be a contiguous set of image segment files");
393                        return false;
394                        }
395                }
396                prvSegment = curSegment;
397        }
398        
399        // XXX TJJ - until HRITAdapter can handle the fact that HRV data can 
400        // alter geographic coverage in mid-transmission, we deal with this by
401        // only allowing display of HRV segments one at a time.
402        
403        // commenting out for now - will deal with it in field selector window
404/*        if (files.length > 1) {
405                int hrvCount = 0;
406                for (int i = 0; i < files.length; i++) {
407                        if (files[i].getName().contains("HRV")) {
408                                hrvCount++;
409                        } 
410                        if (hrvCount > 1) {
411                                userMessage("At present, HRV data can only be displayed one file at a time");
412                                return false;
413                        }                       
414                }
415        }*/
416
417        return super.selectFilesInner(files, directory);
418    }
419    
420    /**
421     * Get the bottom panel for the chooser
422     * @return the bottom panel
423     */
424    
425    protected JPanel getBottomPanel() {
426        // If we don't have a fileChooser yet, this won't do any good
427        // This happens when Unidata's FileChooser is instantiated
428        // We instantiate ours right after that
429        if (fileChooser == null) {
430                return null;
431        }
432        
433        ImageTypeChooser itc = new ImageTypeChooser(fileChooser, path);
434        fileChooser.addPropertyChangeListener(itc);
435        JPanel bottomPanel = GuiUtils.left(itc);
436        bottomPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
437        
438        return McVGuiUtils.makeLabeledComponent(channelLabel, itc);
439    }
440    
441    /**
442     * Get the center panel for the chooser
443     * @return the center panel
444     */
445    
446    protected JPanel getCenterPanel() {
447        JPanel centerPanel = super.getCenterPanel();
448        
449        fileChooser.setAcceptAllFileFilterUsed(false);
450      
451        // see what HRIT data is available in this directory,
452        Vector<String> availableTypes = getAvailableHRITTypes(path);
453        String extraFilter = null;
454        if ((availableTypes != null) && (availableTypes.size() > 0)) {
455                extraFilter = (String) availableTypes.get(0);
456        }
457        
458        hf = new HRITFilter(extraFilter);
459        fileChooser.setFileFilter(hf);
460
461        return centerPanel;
462    }
463    
464}