001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2023
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 * 
010 * All Rights Reserved
011 * 
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.  
014 * 
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 * 
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023 * GNU Lesser Public License for more details.
024 * 
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program.  If not, see http://www.gnu.org/licenses.
027 */
028
029package edu.wisc.ssec.mcidasv.data;
030
031import java.util.ArrayList;
032import java.util.Collections;
033import java.util.Comparator;
034import java.util.HashMap;
035import java.util.Map;
036
037import ucar.unidata.data.DataChoice;
038import ucar.unidata.data.DataContext;
039import ucar.unidata.data.DataManager;
040import ucar.unidata.data.DataSource;
041
042import ucar.unidata.util.TwoFacedObject;
043
044import ucar.unidata.xml.XmlResourceCollection;
045
046import edu.wisc.ssec.mcidasv.control.HydraControl;
047import edu.wisc.ssec.mcidasv.control.MultiSpectralControl;
048
049import edu.wisc.ssec.mcidasv.display.hydra.MultiSpectralDisplay;
050
051/**
052 * <p>
053 * The McvDataManager exists purely as a UI nicety. In the IDV, the list of
054 * {@link DataSource}s are presented in the same ordering found in
055 * {@code datasources.xml}.
056 * </p>
057 * 
058 * <p>
059 * While ordering the contents of {@code datasources.xml} certainly would have
060 * been easier, the approach taken here is a bit more future-proof. McV simply
061 * sorts the data sources known to the IDV.
062 * </p>
063 */
064public class McvDataManager extends DataManager {
065
066    /**
067     * ID of the "I'm Still Feeling Lucky" data source. The IDV lowercases it
068     * automatically.
069     */
070    private static final String STILL_LUCKY_ID = "file.any";
071
072    private final Map<DataChoice, HydraControl> hydraDataToControl = new HashMap<DataChoice, HydraControl>();
073    private final Map<DataChoice, MultiSpectralDisplay> hydraDataToDisplay = new HashMap<DataChoice, MultiSpectralDisplay>();
074
075    /**
076     * Default constructor.
077     */
078    public McvDataManager() {
079        super(null);
080    }
081
082    /**
083     * Creates a new DataManager with the given {@link DataContext}.
084     * 
085     * @param dataContext The {@code DataContext} that this DataManager exists
086     *        within (this is usually an instance of
087     *        {@link ucar.unidata.idv.IntegratedDataViewer}).
088     */
089    public McvDataManager(final DataContext dataContext) {
090        super(dataContext);
091    }
092
093    public boolean containsHydraControl(final DataChoice choice) {
094        return hydraDataToControl.containsKey(choice);
095    }
096
097    public boolean containsHydraDisplay(final DataChoice choice) {
098        return hydraDataToDisplay.containsKey(choice);
099    }
100
101    public void setHydraControl(final DataChoice choice, final HydraControl control) {
102        hydraDataToControl.put(choice, control);
103    }
104
105    public void setHydraDisplay(final DataChoice choice, final MultiSpectralDisplay display) {
106        hydraDataToDisplay.put(choice, display);
107    }
108
109    public HydraControl getHydraControl(final DataChoice choice) {
110        return hydraDataToControl.get(choice);
111    }
112
113    public MultiSpectralDisplay getHydraDisplay(final DataChoice choice) {
114        return hydraDataToDisplay.get(choice);
115    }
116
117    /**
118     * Process the list of xml documents that define the different
119     * {@link DataSource}s used within the idv. Overridden so that McIDAS-V
120     * can alphabetize the lists of {@link DataSource}s presented in the UI.
121     * 
122     * @param resources The {@link XmlResourceCollection} that holds the set of
123     *        datasource xml documents. This may be null.
124     */
125    @Override public void loadDataSourceXml(
126        final XmlResourceCollection resources) {
127        super.loadDataSourceXml(resources);
128        allDataSourceIds = sortTwoFacedObjects(allDataSourceIds);
129        fileDataSourceIds = sortTwoFacedObjects(fileDataSourceIds);
130    }
131
132    /**
133     * <p>
134     * Sorts an {@link ArrayList} of {@link TwoFacedObject}s by label. Case is
135     * ignored.
136     * </p>
137     * 
138     * <p>
139     * <b>NOTE:</b> If the ID of one of the objects represents the "I'm Still
140     * Feeling Lucky" data source, it'll always wind up at the end of the list.
141     * </p>
142     * 
143     * @param objs The list that needs some sortin' out.
144     * 
145     * @return The sorted contents of {@code objs}.
146     */
147    private ArrayList<TwoFacedObject> sortTwoFacedObjects(final ArrayList<TwoFacedObject> objs) {
148        Comparator<TwoFacedObject> comp = new Comparator<TwoFacedObject>() {
149
150            public int compare(final TwoFacedObject a, final TwoFacedObject b) {
151
152                // make sure "I'm still feeling lucky" is always last.
153                if (a.getId().equals(STILL_LUCKY_ID))
154                    return 1;
155
156                // same as above!
157                if (b.getId().equals(STILL_LUCKY_ID))
158                    return -1;
159
160                // otherwise sorting by label is just fine.
161                return ((String)a.getLabel()).compareToIgnoreCase((String)b.getLabel());
162            }
163
164            @Override public boolean equals(Object o) {
165                return (o == this);
166            }
167        };
168
169        ArrayList<TwoFacedObject> reordered = new ArrayList<TwoFacedObject>(objs);
170        Collections.sort(reordered, comp);
171        return reordered;
172    }
173}