001    /*
002     * $Id: AddeImageParameterDataSource.java,v 1.30 2012/04/26 17:11:50 tomw 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.adde;
032    
033    import java.awt.Component;
034    import java.awt.Container;
035    import java.awt.Dimension;
036    import java.awt.event.ActionEvent;
037    import java.awt.event.ActionListener;
038    import java.io.File;
039    import java.io.RandomAccessFile;
040    import java.rmi.RemoteException;
041    import java.text.SimpleDateFormat;
042    import java.util.ArrayList;
043    import java.util.Arrays;
044    import java.util.Comparator;
045    import java.util.Enumeration;
046    import java.util.Hashtable;
047    import java.util.Iterator;
048    import java.util.List;
049    import java.util.StringTokenizer;
050    import java.util.TimeZone;
051    import java.util.TreeMap;
052    
053    import javax.swing.BoxLayout;
054    import javax.swing.JCheckBox;
055    import javax.swing.JComponent;
056    import javax.swing.JLabel;
057    import javax.swing.JPanel;
058    import javax.swing.JScrollPane;
059    import javax.swing.JTabbedPane;
060    
061    import org.slf4j.Logger;
062    import org.slf4j.LoggerFactory;
063    
064    import edu.wisc.ssec.mcidas.AREAnav;
065    import edu.wisc.ssec.mcidas.AreaDirectory;
066    import edu.wisc.ssec.mcidas.AreaDirectoryList;
067    import edu.wisc.ssec.mcidas.AreaFile;
068    import edu.wisc.ssec.mcidas.adde.AddeImageURL;
069    import edu.wisc.ssec.mcidas.adde.AddeTextReader;
070    
071    import visad.Data;
072    import visad.DateTime;
073    import visad.FlatField;
074    import visad.FunctionType;
075    import visad.MathType;
076    import visad.RealType;
077    import visad.Set;
078    import visad.VisADException;
079    import visad.data.DataRange;
080    import visad.data.mcidas.AREACoordinateSystem;
081    import visad.data.mcidas.AreaAdapter;
082    import visad.georef.MapProjection;
083    import visad.meteorology.ImageSequence;
084    import visad.meteorology.ImageSequenceImpl;
085    import visad.meteorology.ImageSequenceManager;
086    import visad.meteorology.SingleBandedImage;
087    import visad.util.ThreadManager;
088    
089    import ucar.nc2.iosp.mcidas.McIDASAreaProjection;
090    import ucar.unidata.data.BadDataException;
091    import ucar.unidata.data.CompositeDataChoice;
092    import ucar.unidata.data.DataCategory;
093    import ucar.unidata.data.DataChoice;
094    import ucar.unidata.data.DataSelection;
095    import ucar.unidata.data.DataSelectionComponent;
096    import ucar.unidata.data.DataSourceDescriptor;
097    import ucar.unidata.data.DirectDataChoice;
098    import ucar.unidata.data.GeoLocationInfo;
099    import ucar.unidata.data.GeoSelection;
100    import ucar.unidata.data.imagery.AddeImageDataSource;
101    import ucar.unidata.data.imagery.AddeImageDescriptor;
102    import ucar.unidata.data.imagery.AddeImageInfo;
103    import ucar.unidata.data.imagery.BandInfo;
104    import ucar.unidata.data.imagery.ImageDataset;
105    import ucar.unidata.geoloc.LatLonPoint;
106    import ucar.unidata.geoloc.ProjectionImpl;
107    import ucar.unidata.idv.DisplayControl;
108    import ucar.unidata.util.GuiUtils;
109    import ucar.unidata.util.IOUtil;
110    import ucar.unidata.util.LogUtil;
111    import ucar.unidata.util.PollingInfo;
112    import ucar.unidata.util.StringUtil;
113    import ucar.unidata.util.ThreeDSize;
114    import ucar.unidata.util.TwoFacedObject;
115    import ucar.visad.Util;
116    import ucar.visad.data.AreaImageFlatField;
117    
118    import edu.wisc.ssec.mcidasv.data.GeoLatLonSelection;
119    import edu.wisc.ssec.mcidasv.data.GeoPreviewSelection;
120    
121    /**
122     * Abstract DataSource class for images files.
123     */
124    public class AddeImageParameterDataSource extends AddeImageDataSource {
125    
126        private static final Logger logger = LoggerFactory.getLogger(AddeImageParameterDataSource.class);
127    
128        /**
129         * Public keys for server, group, dataset, user, project.
130         */
131        public final static String SIZE_KEY = "size";
132        public final static String PLACE_KEY = "place";
133        public final static String LATLON_KEY = "latlon";
134        public final static String LINELE_KEY = "linele";
135        public final static String MAG_KEY = "mag";
136        public final static String BAND_KEY = "band";
137        public final static String BANDINFO_KEY = "bandinfo";
138        public final static String UNIT_KEY = "unit";
139        public final static String PREVIEW_KEY = "preview";
140        public final static String SPAC_KEY = "spac";
141        public final static String NAV_KEY = "nav";
142        public final static String AUX_KEY = "aux";
143        public final static String DOC_KEY = "doc";
144        public final static String SPACING_BRIT = "1";
145        public final static String SPACING_NON_BRIT = "4";
146    
147        /** The first projection we find */
148        protected ProjectionImpl sampleProjection;
149        public MapProjection sampleMapProjection;
150    
151        /** list of twod categories */
152        private List twoDCategories;
153    
154        /** list of 2D time series categories */
155        private List twoDTimeSeriesCategories;
156    
157        /** list of twod categories */
158        private List bandCategories;
159    
160        /** list of 2D time series categories */
161        private List bandTimeSeriesCategories;
162    
163        /* ADDE request string */
164        private String source;
165        private String baseSource;
166    
167        /* properties for this data source */
168        private Hashtable sourceProps;
169        private Hashtable selectionProps;
170    
171        private int lineResolution;
172        private int elementResolution;
173        private float lRes;
174        private float eRes;
175        private int lineMag = 1;
176        private int elementMag = 1;
177    
178        private GeoSelection lastGeoSelection;
179        private DataChoice lastChoice = null;
180        private Boolean showPreview = Boolean.FALSE;
181        private FlatField previewImage = null;
182        private MapProjection previewProjection;
183        private Hashtable initProps;
184    
185        private AreaDirectory previewDir = null;
186        private AREAnav previewNav = null;
187        private boolean haveDataSelectionComponents = false;
188    
189        private GeoPreviewSelection previewSel;
190        private GeoLatLonSelection laLoSel;
191    
192        private String choiceName;
193    
194        private String saveCoordType;
195        private String savePlace;
196        private double saveLat;
197        private double saveLon;
198        private int saveNumLine;
199        private int saveNumEle;
200        private int saveLineMag;
201        private int saveEleMag;
202        private Boolean saveShowPreview;
203    
204        private String displaySource;
205    
206        protected List<DataChoice> stashedChoices = null;
207        private List iml = new ArrayList();
208        private List saveImageList = new ArrayList();
209    
210        private int previewLineRes = 1;
211        private int previewEleRes = 1;
212    
213        /** Whether or not this DataSource was loaded from a bundle. */
214        private boolean fromBundle = false;
215        
216        /** Are any of the data choices based upon remote files? */
217        private boolean hasRemoteChoices = false;
218    
219        public AddeImageParameterDataSource() {} 
220    
221        /**
222         * Creates a {@code AddeImageParameterDataSource} with a single ADDE URL.
223         * <b>Note:</b> the URLs should point at {@literal "image"} data.
224         * 
225         * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source.
226         * @param image ADDE URL
227         * @param properties The properties for this data source.
228         * 
229         * @throws VisADException
230         */
231        public AddeImageParameterDataSource(DataSourceDescriptor descriptor, String image,
232                                   Hashtable properties)
233                throws VisADException {
234            super(descriptor, new String[] { image }, properties);
235            logger.trace("desc={}, image={}, properties={}", new Object[] { descriptor, image, properties });
236        }
237    
238        /**
239         * Create a new AddeImageParameterDataSource with an array of ADDE URL strings.
240         * <b>Note:</b> the URLs should point at {@literal "image"} data.
241         * 
242         * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source.
243         * @param images Array of ADDE URLs.
244         * @param properties Properties for this data source.
245         * 
246         * @throws VisADException
247         */
248        public AddeImageParameterDataSource(DataSourceDescriptor descriptor, String[] images,
249                               Hashtable properties) throws VisADException {
250            super(descriptor, images, properties);
251            logger.trace("desc={}, images={}, properties={}", new Object[] { descriptor, images, properties });
252        }
253    
254        /**
255         * Creates a new {@code AddeImageParameterDataSource} with an 
256         * {@link java.util.List List} of ADDE URL strings.
257         * <b>Note:</b> the URLs should point at {@literal "image"} data.
258         * 
259         * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source.
260         * @param images {@code List} of ADDE URL strings.
261         * @param properties Properties for this data source.
262         * 
263         * @throws VisADException
264         */
265        public AddeImageParameterDataSource(DataSourceDescriptor descriptor, List images,
266                               Hashtable properties) throws VisADException {
267            super(descriptor, images, properties);
268            logger.trace("desc={}, images={}, properties={}", new Object[] { descriptor, images, properties });
269        }
270    
271        /**
272         * Create a new AddeImageParameterDataSource with the given dataset.
273         * 
274         * @param descriptor {@link ucar.unidata.data.DataSourceDescriptor DataSourceDescriptor} for this data source.
275         * @param ids Dataset.
276         * @param properties Properties for this data source.
277         * 
278         * @throws VisADException
279         */
280        public AddeImageParameterDataSource(DataSourceDescriptor descriptor, ImageDataset ids,
281                               Hashtable properties) throws VisADException {
282            super(descriptor, ids, properties);
283            logger.trace("desc={}, ids={}, properties={}", new Object[] { descriptor, ids, properties });
284            this.sourceProps = properties;
285            if (properties.containsKey((Object)PREVIEW_KEY)) {
286                this.showPreview = (Boolean)(properties.get((Object)PREVIEW_KEY));
287                saveShowPreview = showPreview;
288            } else {
289                if (saveShowPreview != null) {
290                    showPreview = saveShowPreview;
291                }
292            }
293            
294            List descs = ids.getImageDescriptors();
295            AddeImageDescriptor aid = (AddeImageDescriptor)descs.get(0);
296            this.source = aid.getSource();
297            if (this.source.contains("localhost")) {
298                AreaDirectory areaDirectory = aid.getDirectory();
299                if (!sourceProps.containsKey((Object)UNIT_KEY)) {
300                    if (!sourceProps.containsKey((Object)BAND_KEY)) {
301                        String calType = areaDirectory.getCalibrationType();
302                        if (!calType.equals("RAW")) {
303                            sourceProps.put(UNIT_KEY, calType);
304                            int[] bandNums = areaDirectory.getBands();
305                            String bandString = new Integer(bandNums[0]).toString();
306                            sourceProps.put(BAND_KEY, bandString);
307                        }
308                    }
309                }
310            }
311            setMag();
312            getAreaDirectory(properties);
313        }
314    
315        @Override protected void propertiesChanged() {
316            logger.trace("fired");
317            super.propertiesChanged();
318        }
319    
320        @Override protected boolean initDataFromPollingInfo() {
321            boolean result = super.initDataFromPollingInfo();
322            logger.trace("result={}", result);
323            return result;
324        }
325    
326        @Override protected boolean isPolling() {
327            boolean result = super.isPolling();
328            logger.trace("isPolling={}", result);
329            return result;
330        }
331    
332        @Override public void setPollingInfo(PollingInfo value) {
333            logger.trace("value={}", value);
334            super.setPollingInfo(value);
335        }
336    
337        @Override protected boolean hasPollingInfo() {
338            boolean result = super.hasPollingInfo();
339            logger.trace("hasPollingInfo={}", result);
340            return result;
341        }
342    
343        @Override public PollingInfo getPollingInfo() {
344            PollingInfo result = super.getPollingInfo();
345            logger.trace("getPollingInfo={}", result);
346            return result;
347        }
348    
349        @Override public void initAfterUnpersistence() {
350            logger.trace("unbundled!");
351            super.initAfterUnpersistence();
352    
353            if (this.sourceProps.containsKey(PREVIEW_KEY)) {
354                this.showPreview = (Boolean)this.sourceProps.get(PREVIEW_KEY);
355                if (this.showPreview == null) {
356                    this.showPreview = Boolean.FALSE;
357                }
358                this.saveShowPreview = this.showPreview;
359            }
360            
361            this.fromBundle = true;
362            List<AddeImageDescriptor> descriptors = (List<AddeImageDescriptor>)getImageList();
363            this.source = descriptors.get(0).getSource(); // TODO: why not use the source from
364                                                          // each AddeImageDescriptor?
365            for (AddeImageDescriptor descriptor : descriptors) {
366                if (!isFromFile(descriptor)) {
367                    this.hasRemoteChoices = true;
368                    break;
369                }
370            }
371        }
372    
373        @Override public boolean canSaveDataToLocalDisk() {
374            return true;
375        }
376    
377        private Hashtable<DataChoice, DataSelection> choiceToSel = new Hashtable<DataChoice, DataSelection>();
378    
379        public DataSelection getSelForChoice(final DataChoice choice) {
380            return choiceToSel.get(choice);
381        }
382        public boolean hasSelForChoice(final DataChoice choice) {
383            return choiceToSel.containsKey(choice);
384        }
385        public void putSelForChoice(final DataChoice choice, final DataSelection sel) {
386            choiceToSel.put(choice, sel);
387        }
388    
389        /**
390         * Save files to local disk
391         *
392         * @param prefix destination dir and file prefix
393         * @param loadId For JobManager
394         * @param changeLinks Change internal file references
395         *
396         * @return Files copied
397         *
398         * @throws Exception On badness
399         */
400        @Override protected List saveDataToLocalDisk(String prefix, Object loadId, boolean changeLinks) throws Exception {
401            logger.trace("prefix={} loadId={} changeLinks={}", new Object[] { prefix, loadId, changeLinks });
402            final List<JCheckBox> checkboxes = new ArrayList<JCheckBox>();
403            List categories = new ArrayList();
404            Hashtable catMap = new Hashtable();
405            Hashtable currentDataChoices = new Hashtable();
406    
407            List displays = getIdv().getDisplayControls();
408            for (int i = 0; i < displays.size(); i++) {
409                List dataChoices = ((DisplayControl)displays.get(i)).getDataChoices();
410                if (dataChoices == null) {
411                    continue;
412                }
413                List finalOnes = new ArrayList();
414                for (int j = 0; j < dataChoices.size(); j++) {
415                    ((DataChoice)dataChoices.get(j)).getFinalDataChoices(finalOnes);
416                }
417                for (int dcIdx = 0; dcIdx < finalOnes.size(); dcIdx++) {
418                    DataChoice dc = (DataChoice)finalOnes.get(dcIdx);
419                    if (!(dc instanceof DirectDataChoice)) {
420                        continue;
421                    }
422                    DirectDataChoice ddc = (DirectDataChoice) dc;
423                    if (ddc.getDataSource() != this) {
424                        continue;
425                    }
426                    currentDataChoices.put(ddc.getName(), "");
427                }
428            }
429    
430            for (int i = 0; i < dataChoices.size(); i++) {
431                DataChoice dataChoice = (DataChoice) dataChoices.get(i);
432                if (!(dataChoice instanceof DirectDataChoice)) {
433                    continue;
434                }
435    
436                // skip over datachoices that the user has not already loaded.
437                // (but fill the "slot" with null (it's a hack to signify that 
438                // the "download" loop should skip over the data choice associated 
439                // with this slot)
440                if (!currentDataChoices.containsKey(dataChoice.getName())) {
441                    checkboxes.add(null); // 
442                    continue;
443                }
444    
445                String label = dataChoice.getDescription();
446                if (label.length() > 30) {
447                    label = label.substring(0, 29) + "...";
448                }
449                JCheckBox cbx =
450                    new JCheckBox(label, 
451                                  currentDataChoices.get(dataChoice.getName())
452                                  != null);
453                ThreeDSize size = (ThreeDSize)dataChoice.getProperty(SIZE_KEY);
454                cbx.setToolTipText(dataChoice.getName());
455                checkboxes.add(cbx);
456                DataCategory dc = dataChoice.getDisplayCategory();
457                List comps = (List)catMap.get(dc);
458                if (comps == null) {
459                    comps = new ArrayList();
460                    catMap.put(dc, comps);
461                    categories.add(dc);
462                }
463                comps.add(cbx);
464                comps.add(GuiUtils.filler());
465                if (size != null) {
466                    JLabel sizeLabel = GuiUtils.rLabel(size.getSize() + "  ");
467                    sizeLabel.setToolTipText(size.getLabel());
468                    comps.add(sizeLabel);
469                } else {
470                    comps.add(new JLabel(""));
471                }
472            }
473            final JCheckBox allCbx = new JCheckBox("Select All");
474            allCbx.addActionListener(new ActionListener() {
475                public void actionPerformed(ActionEvent ae) {
476                    for (JCheckBox cbx : checkboxes) {
477                        if (cbx != null) {
478                            cbx.setSelected(allCbx.isSelected());
479                        }
480                    }
481                }
482            });
483            List catComps = new ArrayList();
484            JTabbedPane tab = new JTabbedPane(JTabbedPane.LEFT);
485    
486            for (int i = 0; i < categories.size(); i++) {
487                List comps = (List)catMap.get(categories.get(i));
488                JPanel innerPanel = GuiUtils.doLayout(comps, 3, GuiUtils.WT_NYN, GuiUtils.WT_N);
489                JScrollPane sp = new JScrollPane(GuiUtils.top(innerPanel));
490                sp.setPreferredSize(new Dimension(500, 400));
491                JPanel top = GuiUtils.right(GuiUtils.rLabel("  "));
492                JComponent inner = GuiUtils.inset(GuiUtils.topCenter(top, sp), 5);
493                tab.addTab(categories.get(i).toString(), inner);
494            }
495    
496            JComponent contents = tab;
497            contents = GuiUtils.topCenter(
498                GuiUtils.inset(
499                    GuiUtils.leftRight(
500                        new JLabel("Select the fields to download"),
501                        allCbx), 5), contents);
502            JLabel label = new JLabel(getNameForDataSource(this, 50, true));
503            contents = GuiUtils.topCenter(label, contents);
504            contents = GuiUtils.inset(contents, 5);
505            if (!GuiUtils.showOkCancelDialog(null, "", contents, null)) {
506                return null;
507            }
508    
509            // iterate through user's selection to build list of things to download
510            List<String> realUrls = new ArrayList<String>();
511            List<AddeImageDescriptor> descriptorsToSave = new ArrayList<AddeImageDescriptor>();
512            List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object)null);
513            List<BandInfo> savedBands = new ArrayList<BandInfo>();
514            for (int i = 0; i < dataChoices.size(); i++) {
515                DataChoice dataChoice = (DataChoice)dataChoices.get(i);
516                if (!(dataChoice instanceof DirectDataChoice)) {
517                    continue;
518                }
519                JCheckBox cbx = (JCheckBox)checkboxes.get(i);
520                if (cbx == null || !cbx.isSelected()) {
521                    continue;
522                }
523    
524                if (dataChoice.getDataSelection() == null) {
525                    dataChoice.setDataSelection(getSelForChoice(dataChoice));
526                }
527                logger.trace("selected choice={} id={}", dataChoice.getName(), dataChoice.getId());
528                List<AddeImageDescriptor> descriptors = getDescriptors(dataChoice, dataChoice.getDataSelection());
529                logger.trace("descriptors={}", descriptors);
530                
531                BandInfo bandInfo;
532                Object dataChoiceId = dataChoice.getId();
533                if (dataChoiceId instanceof BandInfo) {
534                    bandInfo = (BandInfo)dataChoiceId;
535                } else {
536                    bandInfo = bandInfos.get(0);
537                }
538                String preferredUnit = bandInfo.getPreferredUnit();
539                List<TwoFacedObject> filteredCalUnits = new ArrayList<TwoFacedObject>();
540                for (TwoFacedObject tfo : (List<TwoFacedObject>)bandInfo.getCalibrationUnits()) {
541                    if (preferredUnit.equals(tfo.getId())) {
542                        filteredCalUnits.add(tfo);
543                    }
544                }
545                bandInfo.setCalibrationUnits(filteredCalUnits);
546                savedBands.add(bandInfo);
547    
548                DataSelection selection = dataChoice.getDataSelection();
549                if (selection == null) {
550                    if (getSelForChoice(dataChoice) != null) {
551                        selection = getSelForChoice(dataChoice);
552                    } else {
553                        selection = getDataSelection();
554                    }
555                }
556    
557                Hashtable selectionProperties = selection.getProperties();
558    //            Hashtable selectionProperties;
559    //            if (selection != null) {
560    //                selectionProperties = selection.getProperties();
561    //            } else {
562    //                DataSelection sel = this.getDataSelection();
563    //                selectionProperties = new Hashtable();
564    //            }
565                logger.trace("bandinfo.getUnit={} selection props={}", bandInfo.getPreferredUnit(), selectionProperties);
566                for (AddeImageDescriptor descriptor : descriptors) {
567    //                AddeImageInfo aii = (AddeImageInfo)descriptor.getImageInfo().clone();
568                    String src = descriptor.getSource();
569                    logger.trace("src before={}", src);
570                    src = replaceKey(src, AddeImageURL.KEY_UNIT, bandInfo.getPreferredUnit());
571                    if (selectionProperties.containsKey(AddeImageURL.KEY_PLACE)) {
572                        src = replaceKey(src, AddeImageURL.KEY_PLACE, selectionProperties.get(AddeImageURL.KEY_PLACE));
573                    }
574                    if (selectionProperties.containsKey(AddeImageURL.KEY_LATLON)) {
575                        src = replaceKey(src, AddeImageURL.KEY_LINEELE, AddeImageURL.KEY_LATLON, selectionProperties.get(AddeImageURL.KEY_LATLON));
576                    }
577                    if (selectionProperties.containsKey(AddeImageURL.KEY_LINEELE)) {
578                        src = removeKey(src, AddeImageURL.KEY_LATLON);
579                        src = replaceKey(src, AddeImageURL.KEY_LINEELE, selectionProperties.get(AddeImageURL.KEY_LINEELE));
580                    }
581                    if (selectionProperties.containsKey(AddeImageURL.KEY_MAG)) {
582                        src = replaceKey(src, AddeImageURL.KEY_MAG, selectionProperties.get(AddeImageURL.KEY_MAG));
583                    }
584                    if (selectionProperties.containsKey(AddeImageURL.KEY_SIZE)) {
585                        src = replaceKey(src, AddeImageURL.KEY_SIZE, selectionProperties.get(AddeImageURL.KEY_SIZE));
586                    }
587                    logger.trace("src after={}", src);
588                    descriptor.setSource(src);
589                    descriptorsToSave.add(descriptor);
590                }
591    //          descriptorsToSave.addAll(descriptors);
592            }
593            if (!savedBands.isEmpty()) {
594                setProperty(PROP_BANDINFO, savedBands);
595            }
596            if (descriptorsToSave.isEmpty()) {
597                return null;
598            }
599    
600            //Start the load, showing the dialog
601            List<String> suffixes = new ArrayList<String>();
602            SimpleDateFormat sdf = new SimpleDateFormat("_" + DATAPATH_DATE_FORMAT);
603            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
604            for (int i = 0; i < descriptorsToSave.size(); i++) {
605                AddeImageDescriptor descriptor = descriptorsToSave.get(i);
606                AddeImageInfo aii = descriptor.getImageInfo();
607                DateTime dttm = (DateTime)timeMap.get(descriptor.getSource());
608                if (dttm != null) {
609                    suffixes.add(sdf.format(ucar.visad.Util.makeDate(dttm)) + ".area");
610                } else if (aii != null) {
611                    String suffix = "_Band"+aii.getBand()+"_Unit"+aii.getUnit()+"_Pos"+i+".area";
612                    suffixes.add(suffix);
613                    logger.trace("test suffix={}", suffix);
614                } else {
615                    suffixes.add(i + ".area");
616                }
617                realUrls.add(descriptor.getSource());
618            }
619            logger.trace("urls={}", realUrls);
620            logger.trace("prefix={}", prefix);
621            logger.trace("suffixes={}", suffixes);
622            logger.trace("loadId={}", loadId);
623            List newFiles = IOUtil.writeTo(realUrls, prefix, suffixes, loadId);
624            logger.trace("files={}", newFiles);
625            if (newFiles == null) {
626                logger.trace("failed while in writeTo?");
627                return null;
628            } else {
629                logger.trace("finished writeTo!");
630            }
631            if (changeLinks) {
632                imageList = newFiles;
633            }
634    
635            // write 0 as the first word
636            for (int i = 0; i < newFiles.size(); i++) {
637                try {
638                    RandomAccessFile to = new RandomAccessFile((String)newFiles.get(i), "rw");
639                    to.seek(0);
640                    to.writeInt(0);
641                    to.close();
642                } catch (Exception e) {
643                    logger.error("unable to set first word to zero", e);
644                }
645            }
646    
647    
648    //        if (geoSubset != null) {
649    //            geoSubset.clearStride();
650    //            geoSubset.setBoundingBox(null);
651    //            if (geoSelectionPanel != null) {
652    //                geoSelectionPanel.initWith(doMakeGeoSelectionPanel());
653    //            }
654    //        }
655    
656    //        List newFiles = Misc.newList(path);
657    //        if (changeLinks) {
658    //            //Get rid of the resolver URL
659    //            getProperties().remove(PROP_RESOLVERURL);
660    //            setNewFiles(newFiles);
661    //        }
662    //        
663            logger.trace("returning={}", newFiles);
664            return newFiles;
665        }
666    
667        @Override protected String getDataPrefix() {
668            String tmp = StringUtil.replace(getName(), ' ', "");
669            tmp = StringUtil.replace(tmp, '/', "");
670            tmp = StringUtil.replace(tmp, "(AllBands)", "");
671            tmp = IOUtil.cleanFileName(tmp);
672            logger.trace("data prefix={}", tmp);
673            return tmp;
674        }
675        
676        /**
677         * A utility method that helps us deal with legacy bundles that used to
678         * have String file names as the id of a data choice.
679         *
680         * @param object     May be an AddeImageDescriptor (for new bundles) or a
681         *                   String that is converted to an image descriptor.
682         * @return The image descriptor.
683         */
684        @Override public AddeImageDescriptor getDescriptor(Object object) {
685    //        logger.trace("--------------------");
686            if (object == null) {
687    //            logger.trace("null obj");
688                return null;
689            }
690            if (object instanceof DataChoice) {
691                object = ((DataChoice)object).getId();
692                logger.trace("datachoice getId={}", object);
693            }
694            if (object instanceof ImageDataInfo) {
695                int index = ((ImageDataInfo) object).getIndex();
696                if (index < myDataChoices.size()) {
697                    DataChoice dc = (DataChoice)myDataChoices.get(index);
698                    Object tmpObject = dc.getId();
699                    if (tmpObject instanceof ImageDataInfo) {
700    //                    logger.trace("returning imagedatainfo");
701                        return ((ImageDataInfo)tmpObject).getAid();
702                    }
703                }
704    //            logger.trace("invalid idx for imagedatainfo? (idx={} vs size={})", index, myDataChoices.size());
705                return null;
706                //            return ((ImageDataInfo) object).getAid();
707            }
708    
709            if (object instanceof AddeImageDescriptor) {
710    //            logger.trace("already addeimagedesc! desc={}", object);
711                return (AddeImageDescriptor)object;
712            }
713            AddeImageDescriptor tmp = new AddeImageDescriptor(object.toString());
714    //        logger.trace("return descriptor={}", tmp);
715    //        logger.trace("--------------------");
716            return tmp;
717        }
718    
719        /**
720         *  Overwrite base class  method to return the name of this class.
721         *
722         *  @return The name.
723         */
724        public String getImageDataSourceName() {
725            return "Adde Image Data Source (Parameter)";
726        }
727    
728        private void setMag() {
729            Object magKey = (Object)"mag";
730            if (sourceProps.containsKey(magKey)) {
731                String magVal = (String)(sourceProps.get(magKey));
732                String[] magVals = magVal.split(" ");
733                this.lineMag = new Integer(magVals[0]).intValue();
734                this.elementMag = new Integer(magVals[1]).intValue();
735            }
736        }
737    
738        private void getAreaDirectory(Hashtable properties) {
739            String addeCmdBuff = source;
740            if (addeCmdBuff.contains("BAND=")) {
741                String bandStr = getKey(addeCmdBuff, "BAND");
742                if (bandStr.length() == 0) {
743                    addeCmdBuff = replaceKey(addeCmdBuff, "BAND", "1");
744                }
745            }
746            if (addeCmdBuff.contains("MAG=")) {
747                String[] segs = addeCmdBuff.split("MAG=");
748                String seg0 = segs[0];
749                String seg1 = segs[1];
750                int indx = seg1.indexOf("&");
751                seg1 = seg1.substring(indx);
752                String magString = lineMag + " " + elementMag;
753                addeCmdBuff = seg0 + "MAG=" + magString + seg1;
754            }
755            addeCmdBuff = addeCmdBuff.replace("imagedata", "imagedir");
756            AreaDirectoryList dirList = null;
757            try {
758                dirList = new AreaDirectoryList(addeCmdBuff);
759            } catch (Exception e) {
760                try {
761                    List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object)null);
762                    BandInfo bi = bandInfos.get(0);
763                    String bandStr = new Integer(bi.getBandNumber()).toString();
764                    addeCmdBuff = replaceKey(addeCmdBuff, "BAND", bandStr);
765                    dirList = new AreaDirectoryList(addeCmdBuff);
766                } catch (Exception eOpen) {
767                    setInError(true);
768                    logger.error("problem opening AREA file", eOpen);
769                }
770            }
771    
772            try {
773                List areaDirs = dirList.getDirs();
774                AreaDirectory ad = (AreaDirectory)areaDirs.get(0);
775                float[] res = getLineEleResolution(ad);
776                float resol = res[0];
777                if (this.lineMag < 0)
778                    resol *= Math.abs(this.lineMag);
779                this.lineResolution = ad.getValue(11);
780                this.lRes = resol;
781                resol = res[1];
782                if (this.elementMag < 0)
783                    resol *= Math.abs(this.elementMag);
784                this.elementResolution = ad.getValue(12);
785                this.eRes = resol;
786            } catch (Exception e) {
787                setInError(true);
788                logger.error("getting area directory", e);
789            }
790            baseSource = addeCmdBuff;
791        }
792    
793        protected void initDataSelectionComponents(
794                       List<DataSelectionComponent> components, final DataChoice dataChoice) {
795    
796            if (fromBundle && !hasRemoteChoices) {
797                components.add(new BundlePreviewSelection("Region (Disabled)"));
798                components.add(new BundlePreviewSelection("Advanced (Disabled)"));
799                return;
800            }
801    
802            getDataContext().getIdv().showWaitCursor();
803            
804            boolean hasImagePreview = true;
805            if (this.showPreview == null) {
806                this.showPreview = true;
807            }
808            boolean basically = false;
809            if (this.lastChoice != null) {
810                basically = dataChoice.basicallyEquals(this.lastChoice);
811            }
812            logger.trace("dataChoice={}", dataChoice);
813            // check for comps and whether or not dataChoice is hooping right back into line
814            if (this.haveDataSelectionComponents && dataChoice.equals(this.lastChoice)) {
815                try {
816                    // did the datachoice ever actually get data?
817                    if (dataChoice.getDataSelection() == null) {
818                        if (!basically) {
819                            this.laLoSel = new GeoLatLonSelection(this, 
820                                             dataChoice, this.initProps, this.previewProjection,
821                                             previewDir, previewNav);
822                        }
823                        this.lineMag = this.laLoSel.getLineMag();
824                        this.elementMag = this.laLoSel.getElementMag();
825                        
826                        /* DAVEP: Force preview on. "No preview" means blank image */
827    //                    this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 
828    //                                     this.laLoSel, this.previewProjection,
829    //                                     this.lineMag, this.elementMag, this.showPreview);
830                        this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 
831                                this.laLoSel, this.previewProjection,
832                                this.lineMag, this.elementMag, true);
833                    }
834                    components.add(this.previewSel);
835                    components.add(this.laLoSel);
836                } catch (Exception e) {
837                    logger.error("error while repeating addition of selection components", e);
838                    getDataContext().getIdv().showNormalCursor();
839                }
840            } else {
841                try {
842                    hasImagePreview = makePreviewImage(dataChoice);
843                    if (basically) {
844                        getSaveComponents();
845                    }
846                } catch (Exception e) {
847                    JLabel label = new JLabel("Can't make preview image");
848                    JPanel contents = GuiUtils.top(GuiUtils.inset(label, label.getText().length() + 12));
849                    GuiUtils.showOkDialog(null, "No Preview Image", contents, null);
850                    getDataContext().getIdv().showNormalCursor();
851                    logger.error("problem creating preview image", e);
852                    return;
853                }
854                this.lastChoice = dataChoice;
855                if (hasImagePreview) {
856                    try {
857                        String magStr = getKey(baseSource, MAG_KEY);
858                        String saveMagStr = magStr;
859                        String[] vals = StringUtil.split(magStr, " ", 2);
860                        Integer iVal = new Integer(vals[0]);
861                        int lMag = iVal.intValue() * -1;
862                        if (lMag == -1) {
863                            lMag = 1;
864                        }
865                        iVal = new Integer(vals[1]);
866                        int eMag = iVal.intValue() * -1;
867                        if (eMag == -1) {
868                            eMag = 1;
869                        }
870                        magStr = lMag + " " + eMag;
871                        replaceKey(MAG_KEY, magStr);
872    //                    String saveStr = baseSource;
873    //                    if (!showPreview) {
874    //                        replaceKey(SIZE_KEY, "2 2");
875    //                    }
876                        AreaAdapter aa = null;
877                        AREACoordinateSystem acs = null;
878                        try {
879                            
880                            if (showPreview) {
881                                    aa = new AreaAdapter(baseSource, false);
882                                    this.previewImage = (FlatField)aa.getImage();
883                            }
884                            else {
885                                    this.previewImage = Util.makeField(0, 1, 1, 0, 1, 1, 0, "TEMP");
886                            }
887                            
888                            AreaFile af = new AreaFile(baseSource);
889                            previewNav = af.getNavigation();
890                            AreaDirectory ad = af.getAreaDirectory();
891                            this.lineResolution = ad.getValue(11);
892                            this.elementResolution = ad.getValue(12);
893                            acs = new AREACoordinateSystem(af);
894                        } catch (Exception e) {
895                            String excp = e.toString();
896                            int indx = excp.lastIndexOf(":");
897                            String errorText = excp.substring(indx+1);
898                            JLabel label = new JLabel(errorText);
899                            JPanel contents = GuiUtils.top(GuiUtils.inset(label, label.getText().length() + 12));
900                            GuiUtils.showOkDialog(null, "Can't Make Geographical Selection Tabs", contents, null);
901                            getDataContext().getIdv().showNormalCursor();
902                            logger.error("problem creating preview image", e);
903                            return;
904                        }
905                        this.initProps = new Hashtable();
906                        Enumeration propEnum = sourceProps.keys();
907                        for (int i = 0; propEnum.hasMoreElements(); i++) {
908                            String key = propEnum.nextElement().toString();
909                            Object val = sourceProps.get(key);
910                            key = key.toUpperCase();
911                            if (val instanceof String) {
912                                String str = (String)val;
913                                val = (Object)(str.toUpperCase());
914                            }
915                            this.initProps.put(key,val);
916                        }
917                        replaceKey(MAG_KEY, saveMagStr);
918                        magStr = getKey(baseSource, MAG_KEY);
919                        vals = StringUtil.split(magStr, " ", 2);
920                        iVal = new Integer(vals[0]);
921                        lMag = iVal.intValue();
922                        iVal = new Integer(vals[1]);
923                        eMag = iVal.intValue();
924    
925                        this.initProps.put("LRES", String.valueOf((this.lRes)));
926                        this.initProps.put("ERES", String.valueOf((this.eRes)));
927                        this.initProps.put("PLRES", String.valueOf((this.previewLineRes)));
928                        this.initProps.put("PERES", String.valueOf((this.previewEleRes)));
929                        this.previewProjection = (MapProjection)acs;
930    
931                        String coordType = "";
932                        double coords[] = { 0.0, 0.0 };
933                        
934                        logger.trace("basically={} laLoSel==null?={}", basically, (this.laLoSel==null));
935                        if (!basically) {
936                            if (this.laLoSel != null) {
937                                coordType = this.laLoSel.getCoordinateType();
938                                if (coordType.equals(this.laLoSel.getLatLonType())) {
939                                    coords[0] = this.laLoSel.getLatitude();
940                                    coords[1] = this.laLoSel.getLongitude();
941                                } else {
942                                    coords[0] = (double)this.laLoSel.getLine();
943                                    coords[1] = (double)this.laLoSel.getElement();
944                                }
945    
946                                // turns out that laLoSel is reused for datachoices
947                                // from the same source. if you don't update laLoSel's
948                                // dataChoice, it'll apply whatever data selection
949                                // you set up... to the first data choice that you
950                                // loaded! (and causing an NPE when attempting to
951                                // bundle the dataselection for the newly-selected
952                                // datachoice.
953                                this.previewSel.setDataChoice(dataChoice);
954                                this.laLoSel.setDataChoice(dataChoice);
955                                this.laLoSel.setPreviewLineRes(this.previewLineRes);
956                                this.laLoSel.setPreviewEleRes(this.previewEleRes);
957                                this.laLoSel.update(previewDir, this.previewProjection, previewNav,
958                                               coordType, coords);
959                                
960                            } else {
961                                this.laLoSel = new GeoLatLonSelection(this, 
962                                              dataChoice, this.initProps, this.previewProjection,
963                                              previewDir, previewNav);
964                                this.lineMag = this.laLoSel.getLineMag();
965                                this.elementMag = this.laLoSel.getElementMag();
966                            }
967                        } else {
968                            if (this.laLoSel != null) {
969                                this.previewSel.setDataChoice(dataChoice);
970                                this.laLoSel.setDataChoice(dataChoice);
971                            }
972                        }
973                        /* DAVEP: Force preview on. "No preview" means blank image */
974    //                    this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 
975    //                                     this.laLoSel, this.previewProjection,
976    //                                     this.lineMag, this.elementMag, this.showPreview);
977                        this.previewSel = new GeoPreviewSelection(this, dataChoice, this.previewImage, 
978                                this.laLoSel, this.previewProjection,
979                                this.lineMag, this.elementMag, true);
980                        
981                    } catch (Exception e) {
982                        logger.error("problem making selection components", e);
983                        getDataContext().getIdv().showNormalCursor();
984                    }
985                    this.haveDataSelectionComponents = true;
986                    replaceKey(MAG_KEY, (Object)(this.lineMag + " " + this.elementMag));
987                    components.add(this.previewSel);
988                    components.add(this.laLoSel);
989                }
990            }
991            if (this.previewSel != null) {
992                this.previewSel.initBox();
993            }
994            getDataContext().getIdv().showNormalCursor();
995        }
996    
997        /**
998         * A hook to allow this data source to add data selection components
999         * to the IDV field selector
1000         *
1001         * @param dataChoice the data choice
1002         *
1003         * @return list of components
1004         */
1005    //    @Override public List<DataSelectionComponent> getDataSelectionComponents(DataChoice dataChoice) {
1006    ////        List<DataSelectionComponent> dataSelectionComponents = new ArrayList<DataSelectionComponent>();
1007    ////        initDataSelectionComponents(dataSelectionComponents, dataChoice);
1008    ////        return dataSelectionComponents;
1009    //        return new ArrayList<DataSelectionComponent>();
1010    //    }
1011        
1012        private boolean makePreviewImage(DataChoice dataChoice) {
1013    
1014            getDataContext().getIdv().showWaitCursor();
1015    
1016            boolean msgFlag = false;
1017            showPreview = saveShowPreview;
1018            List<BandInfo> bandInfos = (List<BandInfo>) getProperty(PROP_BANDINFO, (Object) null);
1019            BandInfo bi = null;
1020            String saveBand = getKey(source, BAND_KEY);
1021            int bandIdx = 0;
1022            List<TwoFacedObject> calList = null;
1023            try {
1024                Object dcObj = dataChoice.getId();
1025                if (dcObj instanceof BandInfo) {
1026                    bi = (BandInfo) dcObj;
1027                    Integer bandInt = new Integer(bandInfos.indexOf(dcObj)+1);
1028                    saveBand = bandInt.toString();
1029                } else {
1030                    msgFlag = true;
1031                    bi = bandInfos.get(bandIdx);
1032                    this.showPreview = false;
1033                }
1034                // pull out the list of cal units, we'll need for type check later...
1035                calList = bi.getCalibrationUnits();
1036                source = replaceKey(source, BAND_KEY, (Object) (bi.getBandNumber()));
1037                // if we're replacing the band, replace cal type with preferred  
1038                // type for that band
1039                source = replaceKey(source, UNIT_KEY, (Object) bi.getPreferredUnit());
1040            } catch (Exception excp) {
1041                handlePreviewImageError(1, excp);
1042            }
1043            String name = dataChoice.getName();
1044            int idx = name.lastIndexOf("_");
1045            String unit = name.substring(idx + 1);
1046    
1047            // if this is not a valid cal unit (e.g. could be set to a plugin formula name)
1048            // set it to something valid
1049            boolean validCal = false;
1050            for (TwoFacedObject tfo : calList) {
1051                if (unit.equals((String) tfo.getId())) {
1052                    validCal = true;
1053                    break;
1054                }
1055            }
1056            if (!validCal) {
1057                unit = bi.getPreferredUnit();
1058            }
1059    
1060            if (getKey(source, UNIT_KEY).length() == 0) {
1061                source = replaceKey(source, UNIT_KEY, (Object)(unit));
1062            }
1063    
1064            AddeImageDescriptor aid = null;
1065            while (aid == null) {
1066                try {
1067                    aid = new AddeImageDescriptor(this.source);
1068                } catch (Exception excp) {
1069                    msgFlag = true;
1070                    if (bandIdx > bandInfos.size()) {
1071                        return false;
1072                    }
1073                    bi = bandInfos.get(bandIdx);
1074                    source = replaceKey(source, BAND_KEY, (Object)(bi.getBandNumber()));
1075                    ++bandIdx;
1076                }
1077            }
1078            previewDir = getPreviewDirectory(aid);
1079            int eMag = 1;
1080            int lMag = 1;
1081            int eSize = 1;
1082            int lSize = 1;
1083            try {
1084                int plMag = 1;
1085                int peMag = 1;
1086                Object magKey = (Object)"mag";
1087                if (sourceProps.containsKey(magKey)) {
1088                    String magVal = (String)(sourceProps.get(magKey));
1089                    String[] magVals = magVal.split(" ");
1090                    peMag = new Integer(magVals[0]).intValue();
1091                    plMag = new Integer(magVals[1]).intValue();
1092                }
1093                double feSize = (double)previewDir.getElements();
1094                double flSize = (double)previewDir.getLines();
1095                double feMag = (double)peMag;
1096                double flMag = (double)plMag;
1097                if (feSize > flSize) {
1098                    feMag = feSize/525.0;
1099                    flMag = feMag * (double)plMag/(double)peMag;
1100                } else {
1101                    flMag = flSize/500.0;
1102                    feMag = flMag * (double)peMag/(double)plMag;
1103                }
1104                eMag = (int)Math.ceil(feMag);
1105                lMag = (int)Math.ceil(flMag);
1106            } catch(Exception excp) {
1107               handlePreviewImageError(3, excp);
1108            }
1109            if (eMag < 1) eMag = 1;
1110            if (lMag < 1) lMag = 1;
1111    
1112            eSize = 525;
1113            lSize = 500;
1114            if ((baseSource == null) || msgFlag) {
1115                baseSource = source;
1116            }
1117            this.previewLineRes = lMag;
1118            this.previewEleRes = eMag;
1119            String uLStr = "0 0 F";
1120            try {
1121                int startLine = previewDir.getValue(5);
1122                int startEle = previewDir.getValue(6);
1123                uLStr = startLine + " " + startEle + " I";
1124            } catch (Exception e) {
1125            }
1126            String src = aid.getSource();
1127            
1128            src = removeKey(src, LATLON_KEY);
1129            src = replaceKey(src, LINELE_KEY, (Object)uLStr);
1130            src = replaceKey(src, PLACE_KEY, (Object)("ULEFT"));
1131            src = replaceKey(src, SIZE_KEY, (Object)(lSize + " " + eSize));
1132            src = replaceKey(src, MAG_KEY, (Object)(lMag + " " + eMag));
1133            src = replaceKey(src, BAND_KEY, (Object)(bi.getBandNumber()));
1134            src = replaceKey(src, UNIT_KEY, (Object)(unit));
1135            
1136            try {
1137                aid = new AddeImageDescriptor(src);
1138            } catch (Exception excp) {
1139                handlePreviewImageError(4, excp);
1140                src = replaceKey(src, BAND_KEY, (Object)saveBand);
1141                aid = new AddeImageDescriptor(src);
1142                src = replaceKey(src, BAND_KEY, (Object)(bi.getBandNumber()));
1143            }
1144            if (msgFlag && (!"ALL".equals(saveBand))) {
1145                src = replaceKey(src, BAND_KEY, (Object)saveBand);
1146            }
1147            baseSource = src;
1148    
1149            getDataContext().getIdv().showNormalCursor();
1150    
1151            return true;
1152        }
1153    
1154        /**
1155         * Show the given error to the user. 
1156         *
1157         * @param excp The exception
1158         */
1159        protected void handlePreviewImageError(int flag, Exception excp) {
1160            getDataContext().getIdv().showNormalCursor();
1161            LogUtil.userErrorMessage("Error in makePreviewImage  e=" + flag + " " + excp);
1162        }
1163    
1164        private String removeKey(String src, String key) {
1165            String returnString = src;
1166            key = key.toUpperCase() + '=';
1167            if (returnString.contains(key)) {
1168                String[] segs = returnString.split(key);
1169                String seg0 = segs[0];
1170                String seg1 = segs[1];
1171                int indx = seg1.indexOf("&");
1172                if (indx >= 0) {
1173                    seg1 = seg1.substring(indx+1);
1174                }
1175                returnString = seg0 + seg1;
1176            }
1177            return returnString;
1178        }
1179    
1180        private String replaceKey(String src, String key, Object val) {
1181            String returnString = src;
1182            // make sure we got valid key/val pair
1183            if ((key == null) || (val == null)) {
1184                return returnString;
1185            }
1186            key = key.toUpperCase() + '=';
1187            if (returnString.contains(key)) {
1188                String[] segs = returnString.split(key);
1189                String seg0 = segs[0];
1190                String seg1 = segs[1];
1191                int indx = seg1.indexOf("&");
1192                if (indx < 0) {
1193                    seg1 = "";
1194                } else if (indx > 0) {
1195                    seg1 = seg1.substring(indx);
1196                }
1197                returnString = seg0 + key + val + seg1;
1198            } else {
1199                returnString = returnString + '&' + key + val;
1200            }
1201            // if key is for cal units, and it was changed to BRIT,
1202            // must change the spacing key too 
1203            if ((key.equals(UNIT_KEY + "=")) && ("BRIT".equals(val))) {
1204                returnString = replaceKey(returnString, SPAC_KEY, SPAC_KEY, SPACING_BRIT);
1205            } else {
1206                returnString = replaceKey(returnString, SPAC_KEY, SPAC_KEY, SPACING_NON_BRIT); 
1207            }
1208            return returnString;
1209        }
1210    
1211        private String replaceKey(String src, String oldKey, String newKey, Object val) {
1212            String returnString = src;
1213            oldKey = oldKey.toUpperCase() + '=';
1214            newKey = newKey.toUpperCase() + '=';
1215            if (returnString.contains(oldKey)) {
1216                String[] segs = returnString.split(oldKey);
1217                String seg0 = segs[0];
1218                String seg1 = segs[1];
1219                int indx = seg1.indexOf("&");
1220                if (indx < 0) {
1221                    seg1 = "";
1222                } else if (indx > 0) {
1223                    seg1 = seg1.substring(indx);
1224                }
1225                returnString = seg0 + newKey + val + seg1;
1226            }
1227            else {
1228                returnString = returnString + '&' + newKey + val;
1229            }
1230            return returnString;
1231        }
1232    
1233        private void replaceKey(String key, Object val) {
1234            baseSource = replaceKey(baseSource, key, val);
1235        }
1236    
1237        private String getKey(String src, String key) {
1238            String returnString = "";
1239            key = key.toUpperCase() + '=';
1240            if (src.contains(key)) {
1241                String[] segs = src.split(key);
1242                segs = segs[1].split("&");
1243                returnString = segs[0];
1244            }
1245            return returnString;
1246        }
1247    
1248    
1249        /**
1250         * Create the set of {@link ucar.unidata.data.DataChoice} that represent
1251         * the data held by this data source.  We create one top-level
1252         * {@link ucar.unidata.data.CompositeDataChoice} that represents
1253         * all of the image time steps. We create a set of children
1254         * {@link ucar.unidata.data.DirectDataChoice}, one for each time step.
1255         */
1256        public void doMakeDataChoices() {
1257            super.doMakeDataChoices();
1258            List<BandInfo> bandInfos = (List<BandInfo>)getProperty(PROP_BANDINFO, (Object)null);
1259            String name = "";
1260            if (this.choiceName != null) {
1261                name = this.choiceName;
1262            }
1263            if (name.length() != 0) {
1264                logger.trace("already have a name={}", name);
1265                return;
1266            }
1267            if (!sourceProps.containsKey(UNIT_KEY)) {
1268                logger.trace("sourceProps has no unit key={}", sourceProps);
1269                return;
1270            }
1271            BandInfo bi = null;
1272            if (sourceProps.containsKey(BAND_KEY)) {
1273                int bandProp = new Integer((String)(sourceProps.get(BAND_KEY))).intValue();
1274                int bandIndex = BandInfo.findIndexByNumber(bandProp, bandInfos);
1275                bi = (BandInfo)bandInfos.get(bandIndex);
1276                if (sourceProps.containsKey(UNIT_KEY)) {
1277                    bi.setPreferredUnit((String)(sourceProps.get(UNIT_KEY)));
1278                } else {
1279                    bi.setPreferredUnit("");
1280                }
1281                name = makeBandParam(bi);
1282            }
1283            else if (sourceProps.containsKey(BANDINFO_KEY)) {
1284                ArrayList al = (ArrayList)sourceProps.get(BANDINFO_KEY);
1285                bi = (BandInfo)al.get(0);
1286                name = makeBandParam(bi);
1287            }
1288            if (stashedChoices != null) {
1289                int numChoices = stashedChoices.size();
1290                for (int i = 0; i < numChoices; i++) {
1291                   DataChoice choice = (DataChoice)stashedChoices.get(i);
1292                   if (name.equals(choice.getName())) {
1293                       setProperty(PROP_DATACHOICENAME, choice.getName());
1294                   }
1295                }
1296            }
1297        }
1298    
1299        /**
1300         * Overridden so that McIDAS-V can <i>attempt</i> to return the correct
1301         * {@code DataSelection} for the current {@code DataChoice}.
1302         */
1303        @Override public DataSelection getDataSelection() {
1304            DataSelection tmp;
1305            if (this.laLoSel == null || this.choiceToSel == null || !this.choiceToSel.containsKey(this.laLoSel.getDataChoice())) {
1306                logger.trace("* idvland getDataSelection");
1307                tmp = super.getDataSelection();
1308            } else {
1309                logger.trace("* mcv getSelForChoice");
1310                tmp = this.getSelForChoice(this.laLoSel.getDataChoice());
1311            }
1312            logger.trace("return selection props={} geo={}", tmp.getProperties(), tmp.getGeoSelection());
1313            return tmp;
1314        }
1315    
1316        /**
1317         * Overridden so that McIDAS-V can associate this data source's current 
1318         * {@code DataChoice} with the given {@code DataSelection}.
1319         */
1320        @Override public void setDataSelection(DataSelection s) {
1321            super.setDataSelection(s);
1322            if (this.laLoSel != null) {
1323                this.putSelForChoice(this.laLoSel.getDataChoice(), s);
1324            }
1325            logger.trace("setting selection props={} geo={}", s.getProperties(), s.getGeoSelection());
1326        }
1327        
1328    //    @Override public int canShowParameter(String name) {
1329    //        int result = super.canShowParameter(name);
1330    //        switch (result) {
1331    //            case 0: //show=yes
1332    //                logger.trace("can show param={}", name);
1333    //                break;
1334    //            case 1: // show=hide
1335    //                logger.trace("hide param={}", name);
1336    //                break;
1337    //            case 2: // show=no
1338    //                logger.trace("no show param={}", name);
1339    //                break;
1340    //            default:
1341    //                logger.trace("trouble for param={}", name);
1342    //                break;
1343    //        }
1344    //        return result;
1345    //
1346    //    }
1347        
1348        /**
1349         * Insert the new DataChoice into the dataChoice list.
1350         *
1351         * @param choice   new choice to add
1352         */
1353        protected void addDataChoice(DataChoice choice) {
1354            logger.trace("choice={}", choice);
1355            super.addDataChoice(choice);
1356            if (stashedChoices == null) {
1357                stashedChoices = new ArrayList();
1358            }
1359            stashedChoices.add(choice);
1360        }
1361    
1362    
1363        /**
1364         * Initialize the {@link ucar.unidata.data.DataCategory} objects that
1365         * this data source uses. 
1366         */
1367        private void makeCategories() {
1368            twoDTimeSeriesCategories =
1369                DataCategory.parseCategories("IMAGE-2D-TIME;", false);
1370            twoDCategories = DataCategory.parseCategories("IMAGE-2D;", false);
1371            bandCategories = DataCategory.parseCategories("IMAGE-BAND;", false);
1372            bandTimeSeriesCategories =
1373                DataCategory.parseCategories("IMAGE-BAND-TIME;", false);
1374    
1375        }
1376    
1377        /**
1378         * Checks to see if a given {@code AddeImageDescriptor} is based upon a 
1379         * local (or remote) file.
1380         * 
1381         * <p>The check is pretty simple: is {@code descriptor.getSource()} a valid
1382         * path?
1383         * 
1384         * @param descriptor {@code AddeImageDescriptor} of questionable origins. Shouldn't be {@code null}.
1385         * 
1386         * @return {@code true} if {@code descriptor}'s source is a valid path.
1387         */
1388        public static boolean isFromFile(final AddeImageDescriptor descriptor) {
1389            return new File(descriptor.getSource()).exists();
1390        }
1391    
1392        /**
1393         * Create the actual data represented by the given
1394         * {@link ucar.unidata.data.DataChoice}.
1395         *
1396         * @param dataChoice        Either the
1397         *                          {@link ucar.unidata.data.CompositeDataChoice}
1398         *                          representing all time steps or a
1399         *                          {@link ucar.unidata.data.DirectDataChoice}
1400         *                          representing a single time step.
1401         * @param category          Not really used.
1402         * @param dataSelection     Defines any time subsets.
1403         * @param requestProperties extra request properties
1404         *
1405         * @return The image or image sequence data.
1406         *
1407         * @throws RemoteException    Java RMI problem
1408         * @throws VisADException     VisAD problem
1409         */
1410        protected Data getDataInner(DataChoice dataChoice, DataCategory category,
1411                                    DataSelection dataSelection,
1412                                    Hashtable requestProperties)
1413                throws VisADException, RemoteException {
1414            Data img = null;
1415            iml = new ArrayList();
1416    
1417            if (dataSelection == null) {
1418                return null;
1419            }
1420            setDataSelection(dataSelection);
1421    
1422            GeoSelection geoSelection = dataSelection.getGeoSelection(true);
1423            if (geoSelection == null) {
1424                return null;
1425            }
1426    
1427            boolean validState = geoSelection.getHasValidState();
1428            if (!validState) {
1429                return null;
1430            }
1431    
1432            if (this.lastGeoSelection == null) {
1433                this.lastGeoSelection = geoSelection;
1434            }
1435    
1436            this.selectionProps = dataSelection.getProperties();
1437            Enumeration propEnum = this.selectionProps.keys();
1438            for (int i = 0; propEnum.hasMoreElements(); i++) {
1439                String key = propEnum.nextElement().toString();
1440                if (key.compareToIgnoreCase(LATLON_KEY) == 0) {
1441                    String val = (String)this.selectionProps.get(key);
1442                    if (val.contains("NaN")) {
1443                        return img;
1444                    }
1445                }
1446                if (key.compareToIgnoreCase(LINELE_KEY) == 0) {
1447                    String val = (String)this.selectionProps.get(key);
1448                    if (val.contains("NaN")) {
1449                        return img;
1450                    }
1451                }
1452            }
1453    
1454            if (this.selectionProps.containsKey("MAG")) {
1455                String str = (String)this.selectionProps.get("MAG");
1456                String[] strs = StringUtil.split(str, " ", 2);
1457                this.lineMag = new Integer(strs[0]).intValue();
1458                this.elementMag = new Integer(strs[1]).intValue();
1459            }
1460            this.choiceName = dataChoice.getName();
1461            if (this.choiceName != null) {
1462                setProperty(PROP_DATACHOICENAME, this.choiceName);
1463            }
1464            try {
1465                img = super.getDataInner(dataChoice, category, dataSelection, requestProperties);
1466            } catch (Exception e) {
1467                String displaySrc = getDisplaySource();
1468                if (displaySrc != null) {
1469                    AddeImageDescriptor aid = new AddeImageDescriptor(displaySrc);
1470                    dataChoice.setId((Object)aid);
1471                    img = super.getDataInner(dataChoice, category, dataSelection, requestProperties);
1472                }
1473            }
1474            return img;
1475        }
1476    
1477        /**
1478         * Check if the DataChoice has a BandInfo for it's Id
1479         *
1480         * @param dataChoice  choice to check
1481         *
1482         * @return true if the choice ID is a BandInfo
1483         */
1484        private boolean hasBandInfo(DataChoice dataChoice) {
1485            Object id = dataChoice.getId();
1486            return id instanceof BandInfo;
1487        }
1488    
1489        /** _more_ */
1490        AreaDirectory[][] currentDirs;
1491    
1492        /**
1493         * Create the  image sequence defined by the given dataChoice.
1494         *
1495         * @param dataChoice     The choice.
1496         * @param subset     any time subsets.
1497         * @return The image sequence.
1498         *
1499         * @throws RemoteException    Java RMI problem
1500         * @throws VisADException     VisAD problem
1501         */
1502        protected ImageSequence makeImageSequence(DataChoice dataChoice,
1503                DataSelection subset)
1504                throws VisADException, RemoteException {
1505    
1506    //        if (dataChoice.getDataSelection() == null) {
1507    //            dataChoice.setDataSelection(subset);
1508    //        }
1509            Hashtable subsetProperties = subset.getProperties();
1510            Enumeration propEnum = subsetProperties.keys();
1511            int numLines = 0;
1512            int numEles = 0;
1513            for (int i=0; propEnum.hasMoreElements(); i++) {
1514                String key = propEnum.nextElement().toString();
1515                if (key.compareToIgnoreCase(SIZE_KEY) == 0) {
1516                    String sizeStr = (String)(subsetProperties.get(key));
1517                    String[] vals = StringUtil.split(sizeStr, " ", 2);
1518                    Integer iVal = new Integer(vals[0]);
1519                    numLines = iVal.intValue();
1520                    iVal = new Integer(vals[1]);
1521                    numEles = iVal.intValue();
1522                    break;
1523                }
1524            }
1525    
1526            if (sampleMapProjection == null) {
1527                String addeCmdBuff = baseSource;
1528                AreaFile af = null;
1529                try {
1530                    af = new AreaFile(addeCmdBuff);
1531                } catch (Exception eOpen) {
1532                    logger.error("could not open area file: {}", eOpen);
1533                    setInError(true);
1534                    throw new BadDataException("Opening area file: " + eOpen.getMessage());
1535                }
1536                try {
1537                    McIDASAreaProjection map = new McIDASAreaProjection(af);
1538                    AREACoordinateSystem acs = new AREACoordinateSystem(af);
1539                    sampleMapProjection = (MapProjection)acs;
1540                    sampleProjection = map;
1541                } catch (Exception e) {
1542                    logger.error("making area projection: {}", e);
1543                    setInError(true);
1544                    throw new BadDataException("Making area projection: " + e.getMessage());
1545                }
1546            }
1547            AREACoordinateSystem macs = (AREACoordinateSystem)sampleMapProjection;
1548            int[] dirBlk = macs.getDirBlock();
1549            if (numLines == 0) {
1550                double elelin[][] = new double[2][2];
1551                double latlon[][] = new double[2][2];
1552                GeoSelection gs = subset.getGeoSelection();
1553                GeoLocationInfo gli = gs.getBoundingBox();
1554                if ((gli == null) && (lastGeoSelection != null)) {
1555                    subset.setGeoSelection(lastGeoSelection);
1556                    gs = lastGeoSelection;
1557                    gli = gs.getBoundingBox();
1558                }
1559                LatLonPoint llp = gli.getUpperLeft();
1560                latlon[0][0] = llp.getLatitude();
1561                latlon[1][0] = llp.getLongitude();
1562                llp = gli.getLowerRight();
1563                latlon[0][1] = llp.getLatitude();
1564                latlon[1][1] = llp.getLongitude();
1565                elelin = macs.fromReference(latlon);
1566                numLines = (int)(Math.abs(elelin[1][0] - elelin[1][1]))*dirBlk[11];
1567                numEles = (int)(Math.abs(elelin[0][1] - elelin[0][0]))*dirBlk[12];
1568            }
1569    
1570            try {
1571                List descriptorsToUse = new ArrayList();
1572                if (hasBandInfo(dataChoice)) {
1573                    descriptorsToUse = getDescriptors(dataChoice, subset);
1574                } else {
1575                    List choices = (dataChoice instanceof CompositeDataChoice)
1576                                   ? getChoicesFromSubset(
1577                                       (CompositeDataChoice) dataChoice, subset)
1578                                   : Arrays.asList(new DataChoice[] {
1579                                       dataChoice });
1580                    for (Iterator iter = choices.iterator(); iter.hasNext(); ) {
1581                        DataChoice          subChoice = (DataChoice) iter.next();
1582                        AddeImageDescriptor aid =
1583                            getDescriptor(subChoice.getId());
1584                        if (aid == null) {
1585                            continue;
1586                        }
1587                        DateTime dttm = aid.getImageTime();
1588                        if ((subset != null) && (dttm != null)) {
1589                            List times = getTimesFromDataSelection(subset,
1590                                             dataChoice);
1591                            if ((times != null) && (times.indexOf(dttm) == -1)) {
1592                                continue;
1593                            }
1594                        }
1595                        descriptorsToUse.add(aid);
1596                    }
1597                }
1598    
1599                if (descriptorsToUse.size() == 0) {
1600                    return null;
1601                }
1602                AddeImageInfo biggestPosition = null;
1603                int           pos             = 0;
1604                boolean       anyRelative     = false;
1605                // Find the descriptor with the largets position
1606                for (Iterator iter =
1607                        descriptorsToUse.iterator(); iter.hasNext(); ) {
1608                    AddeImageDescriptor aid = (AddeImageDescriptor) iter.next();
1609                    if (aid.getIsRelative()) {
1610                        anyRelative = true;
1611                    }
1612                    AddeImageInfo       aii = aid.getImageInfo();
1613    
1614                    //Are we dealing with area files here?
1615                    if (aii == null) {
1616                        break;
1617                    }
1618    
1619                    //Check if this is absolute time
1620                    if ((aii.getStartDate() != null)
1621                            || (aii.getEndDate() != null)) {
1622                        biggestPosition = null;
1623                        break;
1624                    }
1625                    if ((biggestPosition == null)
1626                        || (Math.abs(aii.getDatasetPosition()) > pos)) {
1627                        pos             = Math.abs(aii.getDatasetPosition());
1628                        biggestPosition = aii;
1629                    }
1630                }
1631    
1632                if (getCacheDataToDisk() && anyRelative
1633                    && (biggestPosition != null)) {
1634                    biggestPosition.setRequestType(AddeImageInfo.REQ_IMAGEDIR);
1635                    AreaDirectoryList adl =
1636                        new AreaDirectoryList(biggestPosition.getURLString());
1637                    biggestPosition.setRequestType(AddeImageInfo.REQ_IMAGEDATA);
1638                    currentDirs = adl.getSortedDirs();
1639                } else {
1640                    currentDirs = null;
1641                }
1642    
1643                ThreadManager threadManager =
1644                    new ThreadManager("image data reading");
1645                final ImageSequenceManager sequenceManager =
1646                    new ImageSequenceManager();
1647                int           cnt      = 1;
1648                DataChoice    parent   = dataChoice.getParent();
1649                final List<SingleBandedImage> images =
1650                    new ArrayList<SingleBandedImage>();
1651                MathType rangeType = null;
1652                for (Iterator iter =
1653                        descriptorsToUse.iterator(); iter.hasNext(); ) {
1654                    final AddeImageDescriptor aid =
1655                        (AddeImageDescriptor) iter.next();
1656                    if (currentDirs != null) {
1657                        int idx =
1658                            Math.abs(aid.getImageInfo().getDatasetPosition());
1659                        if (idx >= currentDirs.length) {
1660                            continue;
1661                        }
1662                    }
1663    
1664                    String label = "";
1665                    if (parent != null) {
1666                        label = label + parent.toString() + ' ';
1667                    } else {
1668                        DataCategory displayCategory =
1669                            dataChoice.getDisplayCategory();
1670                        if (displayCategory != null) {
1671                            label = label + displayCategory + ' ';
1672                        }
1673                    }
1674                    label = label + dataChoice.toString();
1675                    final String readLabel = "Time: " + (cnt++) + '/'
1676                        + descriptorsToUse.size() + ' '
1677                        + label;
1678    
1679                    String src = aid.getSource();
1680                    if (!isFromFile(aid)) {
1681                        try {
1682                            src = replaceKey(src, LINELE_KEY, (Object)("1 1"));
1683                            String sizeString = "10 10";
1684                            src = replaceKey(src, SIZE_KEY, (Object)(sizeString));
1685                            String name = dataChoice.getName();
1686                            int idx = name.lastIndexOf('_');
1687                            String unit = name.substring(idx+1);
1688                            if (getKey(src, UNIT_KEY).length() == 0) {
1689                                src = replaceKey(src, UNIT_KEY, (Object)(unit));
1690                            }
1691                            int lSize = numLines;
1692                            int eSize = numEles;
1693                            sizeString = lSize + " " + eSize;
1694                            src = replaceKey(src, SIZE_KEY, (Object)(sizeString));
1695                            src = replaceKey(src, MAG_KEY, (Object)(this.lineMag + " " + this.elementMag));
1696                            aid.setSource(src);
1697                        } catch (Exception exc) {
1698                            super.makeImageSequence(dataChoice, subset);
1699                        }
1700                    }
1701    
1702                    SingleBandedImage image = makeImage(aid, rangeType, true,
1703                                                        readLabel, subset);
1704                    if (image != null) {
1705                        if(rangeType==null) {
1706                            rangeType = ((FunctionType) image.getType()).getRange();
1707                        }
1708                        synchronized (images) {
1709                            images.add(image);
1710                        }
1711                    }
1712                }
1713    
1714                TreeMap imageMap = new TreeMap();
1715                for (SingleBandedImage image : images) {
1716                    imageMap.put(image.getStartTime(), image);
1717                }
1718                List<SingleBandedImage> sortedImages =
1719                    (List<SingleBandedImage>) new ArrayList(imageMap.values());
1720                if ((sortedImages.size() > 0)
1721                        && (sortedImages.get(0) instanceof AreaImageFlatField)) {
1722                    DataRange[] sampleRanges = null;
1723                    Set domainSet = null;
1724                    for (SingleBandedImage sbi : sortedImages) {
1725                        AreaImageFlatField aiff = (AreaImageFlatField) sbi;
1726                        sampleRanges = aiff.getRanges(true);
1727                        if (domainSet == null) {
1728                            domainSet = aiff.getDomainSet();
1729                        }
1730                        if ((sampleRanges != null) && (sampleRanges.length > 0)) {
1731                            for (int rangeIdx = 0; rangeIdx < sampleRanges.length;
1732                                    rangeIdx++) {
1733                                DataRange r = sampleRanges[rangeIdx];
1734                                if (Double.isInfinite(r.getMin())
1735                                    || Double.isInfinite(r.getMax())) {
1736                                    sampleRanges = null;
1737                                    break;
1738                                }
1739                            }
1740                        }
1741                        if (sampleRanges != null) {
1742                            break;
1743                        }
1744                    }
1745    
1746                    if (sampleRanges != null) {
1747                        for (SingleBandedImage sbi : sortedImages) {
1748                            AreaImageFlatField aiff = (AreaImageFlatField) sbi;
1749                            aiff.setSampleRanges(sampleRanges);
1750                            aiff.setDomainIfNeeded(domainSet);
1751                        }
1752                    }
1753                }
1754    
1755                SingleBandedImage[] imageArray =
1756                    (SingleBandedImage[]) sortedImages.toArray(
1757                        new SingleBandedImage[sortedImages.size()]);
1758                FunctionType imageFunction =
1759                    (FunctionType) imageArray[0].getType();
1760                FunctionType ftype = new FunctionType(RealType.Time,
1761                                         imageFunction);
1762                return new ImageSequenceImpl(ftype, imageArray);
1763            } catch (Exception exc) {
1764                throw new ucar.unidata.util.WrapperException(exc);
1765            }
1766    
1767        }
1768    
1769        /**
1770         * Create the single image defined by the given {@link ucar.unidata.data.imagery.AddeImageDescriptor AddeImageDescriptor}.
1771         *
1772         * @param aid Holds image directory and location of the desired image.
1773         * @param rangeType {@literal "rangeType"} to use (if non-{@code null}).
1774         * @param fromSequence _more_
1775         * @param readLabel 
1776         * @param subset geographical subsetting info
1777         *
1778         * @return The data.
1779         *
1780         * @throws RemoteException Java RMI problem
1781         * @throws VisADException VisAD problem
1782         */
1783        private SingleBandedImage makeImage(AddeImageDescriptor aid,
1784                                            MathType rangeType,
1785                                            boolean fromSequence, 
1786                                            String readLabel, DataSelection subset)
1787                throws VisADException, RemoteException {
1788            
1789            if (aid == null) {
1790                return null;
1791            }
1792    
1793            logger.trace("incoming src={} readLabel={}", aid.getSource(), readLabel);
1794            String src = aid.getSource();
1795    
1796            Hashtable props = subset.getProperties();
1797            // it only makes sense to set the following properties for things
1798            // coming from an ADDE server
1799            if (!isFromFile(aid)) {
1800                if (props.containsKey("PLACE")) {
1801                    src = replaceKey(src, "PLACE", props.get("PLACE"));
1802                }
1803                if (props.containsKey("LATLON")) { 
1804                    src = replaceKey(src, "LINELE", "LATLON", props.get("LATLON"));
1805                }
1806                if (props.containsKey("LINELE")) {
1807                    src = removeKey(src, "LATLON");
1808                    src = replaceKey(src, "LINELE", props.get("LINELE"));
1809                }
1810                if (props.containsKey("MAG")) {
1811                    src = replaceKey(src, "MAG", props.get("MAG"));
1812                }
1813            }
1814            aid.setSource(src);
1815    
1816            SingleBandedImage result;
1817            result = (SingleBandedImage)getCache(src);
1818            if (result != null) {
1819                setDisplaySource(src, props);
1820                return result;
1821            }
1822    
1823            //For now handle non adde urls here
1824            try {
1825                AddeImageInfo aii = aid.getImageInfo();
1826                AreaDirectory areaDir = null;
1827                try {
1828                    if (aii != null) {
1829                        logger.trace("imageinfo={}", aii.toString());
1830                        if (currentDirs != null) {
1831                            int pos = Math.abs(aii.getDatasetPosition());
1832                            int band = 0;
1833                            String bandString = aii.getBand();
1834                            if ((bandString != null) && !aii.ALL.equals(bandString)) {
1835                                band = new Integer(bandString).intValue();
1836                            }
1837                            // TODO: even though the band is non-zero we might only 
1838                            // get back one band
1839                            band = 0;
1840                            areaDir = currentDirs[currentDirs.length - pos - 1][band];
1841                        } else {
1842                            // If its absolute time then just use the AD from the descriptor
1843                            if ((aii.getStartDate() != null) || (aii.getEndDate() != null)) {
1844                                areaDir = aid.getDirectory();
1845                            } else {
1846                            }
1847                        }
1848                    } else {
1849                        logger.trace("uh oh");
1850                    }
1851                } catch (Exception exc) {
1852                    LogUtil.printMessage("error looking up area dir");
1853                    logger.error("error looking up area dir", exc);
1854                    return null;
1855                }
1856    
1857                if (areaDir == null) {
1858                    areaDir = aid.getDirectory();
1859                }
1860    
1861                if (!getCacheDataToDisk()) {
1862                    areaDir = null;
1863                }
1864    
1865                if (!fromSequence || (aid.getIsRelative() && (currentDirs == null))) {
1866                    areaDir = null;
1867                }
1868    
1869                if (areaDir != null) {
1870                    if (isFromFile(aid)) {
1871                      int hash = ((aii != null)
1872                                  ? aii.getURLString().hashCode()
1873                                  : areaDir.hashCode());
1874                      if (rangeType == null) {
1875                          result = AreaImageFlatField.createImmediate(aid, readLabel);
1876                      } else {
1877                          //Else, pass in the already created range type
1878                          result  = AreaImageFlatField.create(aid, areaDir, rangeType, readLabel);
1879                      }
1880                    }
1881    
1882                } else {
1883                    src = aid.getSource();
1884                    try {
1885                        savePlace = this.laLoSel.getPlace();
1886                        saveLat = this.laLoSel.getLatitude();
1887                        saveLon = this.laLoSel.getLongitude();
1888                        saveNumLine = this.laLoSel.getNumLines();
1889                        saveNumEle = this.laLoSel.getNumEles();
1890                        saveLineMag = this.laLoSel.getLineMag();
1891                        saveEleMag = this.laLoSel.getElementMag();
1892                    } catch (Exception e) {
1893                        logger.error("error reading from laLoSel", e);
1894    //                    savePlace = getSavePlace();
1895    //                    this.laLoSel.setPlace(savePlace);
1896    //                    saveLat = getSaveLat();
1897    //                    this.laLoSel.setLatitude(saveLat);
1898    //                    saveLon = getSaveLon();
1899    //                    this.laLoSel.setLongitude(saveLon);
1900    //                    saveNumLine = getSaveNumLine();
1901    //                    this.laLoSel.setNumLines(saveNumLine);
1902    //                    saveNumEle = getSaveNumEle();
1903    //                    this.laLoSel.setNumEles(saveNumEle);
1904    //                    saveLineMag = getSaveLineMag();
1905    //                    this.laLoSel.setLineMag(saveLineMag);
1906    //                    saveEleMag = getSaveEleMag();
1907    //                    this.laLoSel.setElementMag(saveEleMag);
1908                        this.laLoSel.setPlace(savePlace);
1909                        this.laLoSel.setLatitude(saveLat);
1910                        this.laLoSel.setLongitude(saveLon);
1911                        this.laLoSel.setNumLines(saveNumLine);
1912                        this.laLoSel.setNumEles(saveNumEle);
1913                        this.laLoSel.setLineMag(saveLineMag);
1914                        this.laLoSel.setElementMag(saveEleMag);
1915                    }
1916    
1917                    src = replaceKey(src, PLACE_KEY, savePlace);
1918                    src = removeKey(src, LINELE_KEY);
1919                    if (getKey(src, LATLON_KEY).length() != 0) {
1920                        String latStr = Double.toString(saveLat);
1921                        if (latStr.length() > 8) {
1922                            latStr = latStr.substring(0,7);
1923                        }
1924                        String lonStr = Double.toString(saveLon);
1925                        if (lonStr.length() > 9) {
1926                            lonStr = lonStr.substring(0,8);
1927                        }
1928                        src = replaceKey(src, LATLON_KEY, latStr + ' ' + lonStr);
1929                    }
1930                    src = replaceKey(src, SIZE_KEY, saveNumLine + ' ' + saveNumEle);
1931                    src = replaceKey(src, MAG_KEY, saveLineMag + ' ' + saveEleMag);
1932                }
1933    
1934                logger.trace("Getting a new aa: ", src);
1935                AreaAdapter aa = new AreaAdapter(src, false);
1936                areaDir = previewDir;
1937                result = aa.getImage();
1938    
1939                putCache(src, result);
1940                aid.setSource(src);
1941                iml.add(aid);
1942                setImageList(iml);
1943                setDisplaySource(src, props);
1944                return result;
1945    
1946            } catch (java.io.IOException ioe) {
1947                throw new VisADException("Creating AreaAdapter - " + ioe);
1948            }
1949        }
1950        
1951        /**
1952         * Make a parmeter name for the BandInfo
1953         *
1954         * @param bi    the BandInfo in question
1955         *
1956         * @return  a name for the parameter
1957         */
1958        private static String makeBandParam(BandInfo bi) {
1959            return new StringBuilder()
1960                .append(bi.getSensor())
1961                .append("_Band")
1962                .append(bi.getBandNumber())
1963                .append('_')
1964                .append(bi.getPreferredUnit()).toString();
1965        }
1966        
1967        private static String makeBandParam(AddeImageDescriptor descriptor) {
1968            AreaDirectory areaDir = descriptor.getDirectory();
1969            if (areaDir == null) {
1970                throw new NullPointerException("No AREA directory!");
1971            }
1972            return new StringBuilder()
1973                .append(areaDir.getSensorID())
1974                .append("_Band")
1975                .append(areaDir.getBands()[0])
1976                .append('_')
1977                .append(areaDir.getCalibrationType()).toString();
1978        }
1979    
1980        /**
1981         * Get the object that we use to display relative time. Relative time is defined
1982         * using an integer index, 0...n. We don't want to show the actual integer.
1983         * Rather we want to show "Third most recent", "Fourth most recent", etc.
1984         *
1985         * @param aid The image descriptor
1986         * @return The object that represents the relative time index of the aid
1987         */
1988        private Object getRelativeTimeObject(AddeImageDescriptor aid) {
1989            return new TwoFacedObject(aid.toString(),
1990                                      new Integer(aid.getRelativeIndex()));
1991        }
1992    
1993        /**
1994         * Sort the list of data choices on their time
1995         *
1996         * @param choices The data choices
1997         *
1998         * @return The data choices sorted
1999         */
2000        private List sortChoices(List choices) {
2001            Object[]   choicesArray = choices.toArray();
2002            Comparator comp         = new Comparator() {
2003                public int compare(Object o1, Object o2) {
2004                    AddeImageDescriptor aid1 = getDescriptor(o1);
2005                    AddeImageDescriptor aid2 = getDescriptor(o2);
2006                    if ((aid1 == null) || (aid2 == null)) {
2007                        return -1;
2008                    }
2009                    if (aid1.getIsRelative()) {
2010                        if (aid1.getRelativeIndex() < aid2.getRelativeIndex()) {
2011                            return 0;
2012                        } else if (aid1.getRelativeIndex()
2013                                   == aid2.getRelativeIndex()) {
2014                            return 1;
2015                        }
2016                        return -1;
2017                    }
2018                    return aid1.getImageTime().compareTo(aid2.getImageTime());
2019                }
2020            };
2021            Arrays.sort(choicesArray, comp);
2022            return new ArrayList(Arrays.asList(choicesArray));
2023    
2024        }
2025    
2026        /**
2027         * Get a list of descriptors from the choice and subset
2028         *
2029         * @param dataChoice  Data choice
2030         * @param subset  subsetting info
2031         *
2032         * @return  list of descriptors matching the selection
2033         */
2034        public List getDescriptors(DataChoice dataChoice, DataSelection subset) {
2035    //        logger.trace("choice={} subset props={} geo={}", new Object[] { dataChoice, subset.getProperties(), subset.getGeoSelection() });
2036            int linRes = this.lineResolution;
2037            int eleRes = this.elementResolution;
2038            int newLinRes = linRes;
2039            int newEleRes = eleRes;
2040            List times = getTimesFromDataSelection(subset, dataChoice);
2041    //        if (dataChoice.getDataSelection() == null) {
2042    //            logger.trace("setting datasel!");
2043    //            dataChoice.setDataSelection(subset);
2044    //        }
2045            if ((times == null) || times.isEmpty()) {
2046                times = imageTimes;
2047            }
2048            List descriptors = new ArrayList();
2049            Object choiceId = dataChoice.getId();
2050    //        if (choiceId instanceof BandInfo) {
2051    //            
2052    //        }
2053            int choiceBandNum = ((BandInfo)dataChoice.getId()).getBandNumber();
2054            int choiceSensorId = ((BandInfo)dataChoice.getId()).getSensor();
2055            String choicePrefUnit = ((BandInfo)dataChoice.getId()).getPreferredUnit();
2056            for (Iterator iter = times.iterator(); iter.hasNext(); ) {
2057                Object time  = iter.next();
2058                AddeImageDescriptor found = null;
2059                AddeImageDescriptor foundTimeMatch = null;
2060                if (saveImageList.isEmpty()) {
2061                    saveImageList = getImageList();
2062                }
2063                for (Iterator iter2 = saveImageList.iterator(); iter2.hasNext(); ) {
2064                    AddeImageDescriptor aid = getDescriptor(iter2.next());
2065                    if (aid != null) {
2066                        if (aid.getIsRelative()) {
2067                            Object id;
2068                            if (time instanceof TwoFacedObject) {
2069                                id = ((TwoFacedObject)time).getId();
2070                            } else {
2071                                id = time;
2072                            }
2073                            if ((id instanceof Integer) && ((Integer)id).intValue() == aid.getRelativeIndex()) {
2074                                found = aid;
2075                                break;
2076                            }
2077                        } else {
2078                            int aidBand = aid.getDirectory().getBands()[0];
2079                            int aidSensorId = aid.getDirectory().getSensorID();
2080                            String calType = aid.getDirectory().getCalibrationType();
2081                            if (foundTimeMatch == null && aid.getImageTime().equals(time)) {
2082                                logger.trace("found time match {}", time);
2083                                foundTimeMatch = aid;
2084                            }
2085                            if (aid.getImageTime().equals(time) && choiceBandNum == aidBand && choiceSensorId == aidSensorId && choicePrefUnit.equals(calType)) {
2086                                // the problem is here!
2087                                logger.trace("found aid={} src={}", makeBandParam(aid), aid.getSource());
2088                                logger.trace("target info: param={}", dataChoice.getName());
2089                                found = aid;
2090                                break;
2091                            }
2092                        }
2093                    }
2094                }
2095    
2096                if (found == null && foundTimeMatch != null) {
2097                    logger.trace("good enough!?");
2098                    found = foundTimeMatch;
2099                }
2100                
2101                if (found != null) {
2102                    try {
2103                        AddeImageDescriptor desc = new AddeImageDescriptor(found);
2104                        //Sometimes we might have a null imageinfo
2105                        if(desc.getImageInfo()!=null) {
2106                            AddeImageInfo aii =
2107                                (AddeImageInfo) desc.getImageInfo().clone();
2108                            BandInfo bi = (BandInfo) dataChoice.getId();
2109                            List<BandInfo> bandInfos =
2110                                (List<BandInfo>) getProperty(PROP_BANDINFO, (Object) null);
2111                            boolean hasBand = true;
2112                            //If this data source has been changed after we have create a display 
2113                            //then the possibility exists that the bandinfo contained by the incoming
2114                            //data choice might not be valid. If it isn't then default to the first 
2115                            //one in the list
2116                            if(bandInfos != null) {
2117                                hasBand = bandInfos.contains(bi);
2118                                if(!hasBand) {
2119                                }
2120                                if(!hasBand && bandInfos.size() > 0) {
2121                                    bi = bandInfos.get(0);
2122                                } else {
2123                                    //Not sure what to do here.
2124                                }
2125                            }
2126                            aii.setBand("" + bi.getBandNumber());
2127                            aii.setPlaceValue("ULEFT");
2128    
2129                            try {
2130                                AddeImageDescriptor newAid = new AddeImageDescriptor(aii.getURLString());
2131                                AreaDirectory newAd = newAid.getDirectory();
2132                                newLinRes = newAd.getValue(11);
2133                                newEleRes = newAd.getValue(12);
2134                            } catch (Exception e) {
2135                                logger.error("resetting resolution", e);
2136                            }
2137    
2138                            double[][] projCoords = new double[2][2];
2139                            try {
2140                                AreaDirectory ad = desc.getDirectory();
2141                                double lin = (double)ad.getValue(5);
2142                                double ele = (double)ad.getValue(6);
2143                                aii.setLocateKey("LINELE");
2144                                aii.setLocateValue((int)lin + " " + (int)ele);
2145                                projCoords[0][0] = lin;
2146                                projCoords[1][0] = ele;
2147                                lin += (double)ad.getValue(8);
2148                                ele += (double)ad.getValue(9);
2149                                projCoords[0][1] = lin;
2150                                projCoords[1][1] = ele;
2151                            } catch (Exception e) {
2152                                logger.error("problem with adjusting projCoords?", e);
2153                                return descriptors;
2154                            }
2155                            int lins = Math.abs((int)(projCoords[1][1] - projCoords[1][0]));
2156                            int eles = Math.abs((int)(projCoords[0][1] - projCoords[0][0]));
2157                            lins = lins*linRes/newLinRes;
2158                            if (this.lineMag > 0) {
2159                                lins *= this.lineMag;
2160                            } else {
2161                                lins /= -this.lineMag;
2162                            }
2163    
2164                            eles = eles*eleRes/newEleRes;
2165    
2166                            if (elementMag > 0) {
2167                                eles *= elementMag;
2168                            } else {
2169                                eles /= -elementMag;
2170                            }
2171    
2172                            aii.setLines(lins);
2173                            aii.setElements(eles);
2174                            desc.setImageInfo(aii);
2175                            desc.setSource(aii.getURLString());
2176                        }
2177                        descriptors.add(desc);
2178                    } catch (CloneNotSupportedException cnse) {}
2179                }
2180            }
2181            return descriptors;
2182        }
2183    
2184        /**
2185         * Get the subset of the composite based on the selection
2186         *
2187         * @param choice  composite choice
2188         * @param subset  time selection
2189         *
2190         * @return subset list
2191         */
2192        private List getChoicesFromSubset(CompositeDataChoice choice,
2193                                          DataSelection subset) {
2194            List choices = choice.getDataChoices();
2195            if (subset == null) {
2196                return choices;
2197            }
2198            List times = subset.getTimes();
2199            if (times == null) {
2200                return choices;
2201            }
2202            times = TwoFacedObject.getIdList(times);
2203            List   subChoices = new ArrayList();
2204            Object firstTime  = times.get(0);
2205            if (firstTime instanceof Integer) {
2206                for (Iterator iter = times.iterator(); iter.hasNext(); ) {
2207                    subChoices.add(
2208                        choices.get(((Integer) iter.next()).intValue()));
2209                }
2210            } else {  // TODO: what if they are DateTimes?
2211                subChoices.addAll(choices);
2212            }
2213            return subChoices;
2214        }
2215    
2216        private AreaDirectory getPreviewDirectory(AddeImageDescriptor aid) {
2217            AreaDirectory directory = aid.getDirectory();
2218            int times = imageTimes.size();
2219            if (times == 1) return directory;
2220            String src = aid.getSource();
2221    
2222            src = removeKey(src, LATLON_KEY);
2223            src = removeKey(src, LINELE_KEY);
2224            src = removeKey(src, PLACE_KEY);
2225            src = removeKey(src, SIZE_KEY);
2226            src = removeKey(src, UNIT_KEY);
2227            src = removeKey(src, MAG_KEY);
2228            src = removeKey(src, SPAC_KEY);
2229            src = removeKey(src, NAV_KEY);
2230            src = removeKey(src, AUX_KEY);
2231            src = removeKey(src, DOC_KEY);
2232    
2233            int maxLine = 0;
2234            int maxEle = 0;
2235            int imageSize = 0;
2236            src = src.replace("imagedata", "imagedir");
2237            boolean isRelative = aid.getIsRelative();
2238            for (int i=0; i<times; i++) {
2239                if (isRelative) {
2240                    src = replaceKey(src, "POS", new Integer(i).toString());
2241                } else {
2242                    DateTime dt = (DateTime)imageTimes.get(i);
2243                    String timeStr = dt.timeString();
2244                    timeStr = timeStr.replace("Z", " ");
2245                    src = removeKey(src, "POS");
2246                    src = replaceKey(src, "TIME", timeStr + timeStr + "I");
2247                }
2248                try {
2249                    AreaDirectoryList dirList = new AreaDirectoryList(src);
2250                    List ad = dirList.getDirs();
2251                    AreaDirectory areaDir = (AreaDirectory)ad.get(0);
2252                    int lines = areaDir.getLines();
2253                    int eles =  areaDir.getElements();
2254                    if (imageSize < lines*eles) {
2255                        imageSize = lines * eles;
2256                        maxLine = lines;
2257                        maxEle = eles;
2258                        directory = areaDir;
2259                    }
2260                } catch (Exception e) {
2261                    logger.error("problem when dealing with AREA directory", e);
2262                }
2263            }
2264    
2265            return directory;
2266        }
2267    
2268        private String getServer(String urlString) {
2269            int ix = urlString.indexOf("//") + 2;
2270            String temp = urlString.substring(ix);
2271            ix = temp.indexOf("/");
2272            String retStr = temp.substring(0, ix);
2273            return retStr;
2274        }
2275    
2276        public void setDisplaySource(String src, Hashtable props) {
2277             if (!props.isEmpty()) {
2278                 Enumeration propEnum = props.keys();
2279                 for (int i=0; propEnum.hasMoreElements(); i++) {
2280                     String key = propEnum.nextElement().toString();
2281                     Object val = props.get(key);
2282                     if (getKey(src, key).length() != 0) {
2283                         src = replaceKey(src, key, val);
2284                     }
2285                 }
2286             }
2287             this.displaySource = src;
2288             String unit = getKey(src, UNIT_KEY);
2289             if (unit.length() != 0) {
2290                 sourceProps.put(UNIT_KEY.toUpperCase(), unit);
2291             }
2292        }
2293    
2294        public String getDisplaySource() {
2295            return this.displaySource;
2296        }
2297    
2298    
2299        private float[] getLineEleResolution(AreaDirectory ad) {
2300            logger.trace("ad: {} sensor: {}", ad, ad.getSensorID());
2301            float[] res = {(float)1.0, (float)1.0};
2302            int sensor = ad.getSensorID();
2303            List lines = null;
2304            try {
2305                String buff = getUrl();
2306    
2307                lines = readTextLines(buff);
2308                if (lines == null) {
2309                    return res;
2310                }
2311    
2312                int gotit = -1;
2313                String[] cards = StringUtil.listToStringArray(lines);
2314                logger.trace("cards: {}", cards);
2315    
2316                for (int i=0; i<cards.length; i++) {
2317                    if ( ! cards[i].startsWith("Sat ")) continue;
2318                    StringTokenizer st = new StringTokenizer(cards[i]," ");
2319                    String temp = st.nextToken();  // throw away the key
2320                    int m = st.countTokens();
2321                    for (int k=0; k<m; k++) {
2322                        int ss = Integer.parseInt(st.nextToken().trim());
2323                        if (ss == sensor) {
2324                            gotit = i;
2325                            break;
2326                        }
2327                    }
2328    
2329                    if (gotit != -1) {
2330                        break;
2331                    }
2332                }
2333    
2334                if (gotit == -1) {
2335                    return res;
2336                }
2337    
2338                int gotSrc = -1;
2339                for (int i=gotit; i<cards.length; i++) {
2340                    if (cards[i].startsWith("EndSat")) {
2341                            return res;
2342                    }
2343                    if (!cards[i].startsWith("B") ) {
2344                            continue;
2345                    }
2346                    StringTokenizer tok = new StringTokenizer(cards[i]);
2347                    String str = tok.nextToken();
2348                    str = tok.nextToken();
2349                    Float flt = new Float(str);
2350                    res[0] = flt.floatValue();
2351                    str = tok.nextToken();
2352                    flt = new Float(str);
2353                    res[1] = flt.floatValue();
2354                    return res;
2355                }
2356            } catch (Exception e) {
2357                logger.error("problem getting the line+element rez", e);
2358            }
2359            return res;
2360        }
2361    
2362    
2363        /**
2364         * Read the adde text url and return the lines of text.
2365         * If unsuccessful return null.
2366         *
2367         * @param url adde url to a text file
2368         *
2369         * @return List of lines or {@code null} if in error.
2370         */
2371        protected List readTextLines(String url) {
2372            AddeTextReader reader = new AddeTextReader(url);
2373            List lines = null;
2374            if ("OK".equals(reader.getStatus())) {
2375                lines = reader.getLinesOfText();
2376            }
2377            return lines;
2378        }
2379    
2380        /**
2381         * Create the first part of the ADDE request URL
2382         *
2383         * @param requestType type of request
2384         * @return ADDE URL prefix
2385         */
2386        protected String getUrl() {
2387            String str = source;
2388            str = str.replaceFirst("imagedata", "text");
2389            int indx = str.indexOf("VERSION");
2390            str = str.substring(0, indx);
2391            str = str.concat("file=SATBAND");
2392            return str;
2393        }
2394    
2395        public Hashtable getSourceProps() {
2396            return this.sourceProps;
2397        }
2398    
2399        public void setSourceProps(Hashtable sourceProps) {
2400            this.sourceProps = sourceProps;
2401        }
2402    
2403    //    public MapProjection getSampleMapProjection() {
2404    //        return this.sampleMapProjection;
2405    //    }
2406    //
2407    //    public void setSampleMapProjection(MapProjection sampleMapProjection) {
2408    //        this.sampleMapProjection = sampleMapProjection;
2409    //    }
2410    
2411        public String getChoiceName() {
2412            return this.choiceName;
2413        }
2414    
2415        public void setChoiceName(String choiceName) {
2416            this.choiceName = choiceName;
2417        }
2418    
2419    //    public MapProjection getPreviewProjection() {
2420    //        return this.previewProjection;
2421    //    }
2422    //
2423    //    public void setPreviewProjection(MapProjection previewProjection) {
2424    //        this.previewProjection = previewProjection;
2425    //    }
2426    //
2427    //    public AreaDirectory getPreviewDir() {
2428    //        return this.previewDir;
2429    //    }
2430    //
2431    //    public void setPreviewDir(AreaDirectory previewDir) {
2432    //        this.previewDir = previewDir;
2433    //    }
2434    
2435        public String getSavePlace() {
2436            return this.savePlace;
2437        }
2438    
2439        public void setSavePlace(String savePlace) {
2440            this.savePlace = savePlace;
2441        }
2442    
2443        public double getSaveLat() {
2444            return this.saveLat;
2445        }
2446    
2447        public void setSaveLat(double saveLat) {
2448            this.saveLat = saveLat;
2449        }
2450    
2451        public double getSaveLon() {
2452            return this.saveLon;
2453        }
2454    
2455        public void setSaveLon(double saveLon) {
2456            this.saveLon = saveLon;
2457        }
2458    
2459        public int getSaveNumLine() {
2460            return this.saveNumLine;
2461        }
2462    
2463        public void setSaveNumLine(int saveNumLine) {
2464            this.saveNumLine = saveNumLine;
2465        }
2466    
2467        public int getSaveNumEle() {
2468            return this.saveNumEle;
2469        }
2470    
2471        public void setSaveNumEle(int saveNumEle) {
2472            this.saveNumEle = saveNumEle;
2473        }
2474    
2475        public int getSaveLineMag() {
2476            return this.saveLineMag;
2477        }
2478    
2479        public void setSaveLineMag(int saveLineMag) {
2480            this.saveLineMag = saveLineMag;
2481        }
2482    
2483        public int getSaveEleMag() {
2484            return this.saveEleMag;
2485        }
2486    
2487        public void setSaveEleMag(int saveEleMag) {
2488            this.saveEleMag = saveEleMag;
2489        }
2490    
2491        public String getSource() {
2492            return this.source;
2493        }
2494    
2495        public void setSource(String source) {
2496            this.source = source;
2497        }
2498    
2499        public boolean getShowPreview() {
2500            return this.showPreview;
2501        }
2502    
2503        public void setShowPreview(boolean showPreview) {
2504            this.showPreview = showPreview;
2505        }
2506    
2507        public boolean getSaveShowPreview() {
2508            return this.saveShowPreview;
2509        }
2510    
2511        public void setSaveShowPreview(boolean saveShowPreview) {
2512            this.saveShowPreview = saveShowPreview;
2513        }
2514    
2515        private void getSaveComponents() {
2516            saveCoordType = this.laLoSel.getCoordinateType();
2517            savePlace = this.laLoSel.getPlace();
2518            if (saveCoordType.equals(this.laLoSel.getLatLonType())) {
2519                saveLat = this.laLoSel.getLatitude();
2520                saveLon = this.laLoSel.getLongitude();
2521            }
2522            saveNumLine = this.laLoSel.getNumLines();
2523            saveNumEle = this.laLoSel.getNumEles();
2524            saveLineMag = this.laLoSel.getLineMag();
2525            saveEleMag = this.laLoSel.getElementMag();
2526        }
2527        
2528        public static class BundlePreviewSelection extends DataSelectionComponent {
2529            final String label;
2530            public BundlePreviewSelection(final String label) {
2531                super(label);
2532                this.label = label;
2533            }
2534    
2535            @Override protected JComponent doMakeContents() {
2536                // TODO Auto-generated method stub
2537                JPanel panel = new JPanel();
2538                panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
2539                JLabel label1 = new JLabel("Area coverage has been defined by the data bundle;");
2540                JLabel label2 = new JLabel("further subsetting is not currently supported.");
2541                label1.setAlignmentX(Component.CENTER_ALIGNMENT);
2542                label2.setAlignmentX(Container.CENTER_ALIGNMENT);
2543                panel.add(label1);
2544                panel.add(label2);
2545                return panel;
2546            }
2547    
2548            @Override public void applyToDataSelection(DataSelection dataSelection) {
2549            }
2550    
2551            /**
2552             * Overridden to disable these dummy tabs from showing up in properties
2553             * dialog.
2554             */
2555            @Override public boolean getShowInControlProperties() {
2556                return false;
2557            }
2558        }
2559    }