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