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