001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2024
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 https://www.gnu.org/licenses/.
027 */
028
029package edu.wisc.ssec.mcidasv.data;
030
031import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.list;
032
033import java.nio.file.Path;
034import java.nio.file.Paths;
035import java.rmi.RemoteException;
036import java.util.Hashtable;
037import java.util.List;
038
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041import ucar.unidata.data.CompositeDataChoice;
042import ucar.unidata.data.DataCategory;
043import ucar.unidata.data.DataChoice;
044import ucar.unidata.data.DataSelection;
045import ucar.unidata.data.DataSourceDescriptor;
046import ucar.unidata.data.DirectDataChoice;
047import ucar.unidata.data.FilesDataSource;
048import ucar.unidata.util.Misc;
049import visad.Data;
050import visad.VisADException;
051
052/**
053 * This is an implementation that will read in a generic data file and return
054 * a single Data choice that is a VisAD Data object.
055 */
056public class FlatFileDataSource extends FilesDataSource {
057
058    private static final Logger logger =
059        LoggerFactory.getLogger(FlatFileDataSource.class);
060
061    /**
062     *  Parameterless ctor
063     */
064    public FlatFileDataSource() {}
065
066    /**
067     * Just pass through to the base class the ctor arguments.
068     * @param descriptor    Describes this data source, has a label etc.
069     * @param filename      This is the filename (or url) that
070     *                      points to the actual data source.
071     * @param properties General properties used in the base class
072     *
073     * @throws VisADException   problem getting the data
074     */
075    public FlatFileDataSource(DataSourceDescriptor descriptor,
076                              String filename, Hashtable properties)
077            throws VisADException {
078        super(descriptor, filename, "Image flat file data source", properties);
079        Path p = Paths.get(filename);
080        setName(p.getName(p.getNameCount() - 1).toString());
081        logger.trace("descriptor: '{}', filename: '{}', properties: '{}'", descriptor, filename, properties);
082    }
083
084    /**
085     * This method is called at initialization time and  should create
086     * a set of {@link ucar.unidata.data.DirectDataChoice}-s  and add them
087     * into the base class managed list of DataChoice-s with the method
088     * addDataChoice.
089     */
090    protected void doMakeDataChoices() {
091//        String xmlFile = getFilePath();
092//        List bandsDefault = new ArrayList();
093//        bandsDefault.add("Band 1");
094//        String name = getProperty("FLAT.NAME", "Unknown name");
095//        List bandNames = (List)getProperty("FLAT.BANDNAMES", bandsDefault);
096//        List bandFiles = (List)getProperty("FLAT.BANDFILES", bandsDefault);
097//
098//        int lines = getProperty("FLAT.LINES", (int)0);
099//        int elements = getProperty("FLAT.ELEMENTS", (int)0);
100//        String unit = getProperty("FLAT.UNIT", "");
101//        int stride = getProperty("FLAT.STRIDE", (int)1);
102//
103////        if (bandNames.size() == bandFiles.size()) {
104////            for (int i=0; i<bandNames.size(); i++) {
105////                System.out.println(bandNames.get(i) + ": " + bandFiles.get(i));
106////            }
107////        } else {
108////            System.err.println("bandNames: " + bandNames.toString());
109////            System.err.println("bandFiles: " + bandFiles.toString());
110////            System.err.println("Huh... bandNames (" + bandNames.size() + ") and bandFiles (" + bandFiles.size() + ") should be the same size");
111////        }
112//
113//        Hashtable imageProps = Misc.newHashtable(DataChoice.PROP_ICON, "/auxdata/ui/icons/Earth16.gif");
114
115        // Navigation
116        String navType = getProperty("NAV.TYPE", "UNKNOWN");
117        double ulLat = 0;
118        double ulLon = 0;
119        double lrLat = 0;
120        double lrLon = 0;
121        String latFile = null;
122        String lonFile = null;
123        switch (navType) {
124            case "FILES":
125                latFile = getProperty("FILE.LAT", "");
126                lonFile = getProperty("FILE.LON", "");
127                break;
128            case "BOUNDS":
129                ulLat = getProperty("BOUNDS.ULLAT", (double)0);
130                ulLon = getProperty("BOUNDS.ULLON", (double)0);
131                lrLat = getProperty("BOUNDS.LRLAT", (double)0);
132                lrLon = getProperty("BOUNDS.LRLON", (double)0);
133                break;
134            default:
135                logger.warn("unknown navType '{}'", navType);
136        }
137
138        int scale = getProperty("NAV.SCALE", 1);
139        boolean eastPositive = getProperty("NAV.EASTPOS", false);
140
141        // Format
142        String formatType = getProperty("FORMAT.TYPE", "UNKNOWN");
143        switch (formatType) {
144            case "BINARY":
145                handleBinaryFormat(ulLat, ulLon, lrLat, lrLon, latFile, lonFile, scale, eastPositive);
146                break;
147            case "ASCII":
148                handleAsciiFormat(ulLat, ulLon, lrLat, lrLon, latFile, lonFile, scale, eastPositive);
149                break;
150            case "IMAGE":
151                handleImageFormat(ulLat, ulLon, lrLat, lrLon, latFile, lonFile, scale, eastPositive);
152                break;
153            default:
154                logger.warn("unknown formatType '{}'", formatType);
155                break;
156        }
157    }
158
159    private void handleImageFormat(double ulLat, double ulLon, double lrLat, double lrLon, String latFile, String lonFile, int scale, boolean eastPositive) {
160        List<String> bandsDefault = list("Band 1");
161        List<String> bandNames = (List<String>)getProperty("FLAT.BANDNAMES", bandsDefault);
162        List<String> bandFiles = (List<String>)getProperty("FLAT.BANDFILES", bandsDefault);
163
164        int lines = getProperty("FLAT.LINES", 0);
165        int elements = getProperty("FLAT.ELEMENTS", 0);
166        String unit = getProperty("FLAT.UNIT", "");
167        int stride = getProperty("FLAT.STRIDE", 1);
168
169        Hashtable imageProps = Misc.newHashtable(DataChoice.PROP_ICON, "/auxdata/ui/icons/Earth16.gif");
170
171        List categories = DataCategory.parseCategories("RGBIMAGE", false);
172        FlatFileReader dataChoiceData = new FlatFileReader(bandFiles.get(0), lines, elements);
173        dataChoiceData.setImageInfo();
174        dataChoiceData.setUnit(unit);
175        dataChoiceData.setEastPositive(eastPositive);
176        dataChoiceData.setStride(stride);
177        if ((latFile != null) && (lonFile != null)) {
178            dataChoiceData.setNavFiles(latFile, lonFile, scale);
179        } else {
180            dataChoiceData.setNavBounds(ulLat, ulLon, lrLat, lrLon);
181        }
182        String bandName = bandNames.get(0);
183        DirectDataChoice ddc = new DirectDataChoice(this, dataChoiceData, bandName, bandName, categories, imageProps);
184        addDataChoice(ddc);
185    }
186
187    private void handleAsciiFormat(double ulLat, double ulLon, double lrLat, double lrLon, String latFile, String lonFile, int scale, boolean eastPositive) {
188        String name = getProperty("FLAT.NAME", "Unknown name");
189        List<String> bandsDefault = list("Band 1");
190        List<String> bandNames = (List<String>)getProperty("FLAT.BANDNAMES", bandsDefault);
191        List<String> bandFiles = (List<String>)getProperty("FLAT.BANDFILES", bandsDefault);
192
193        int lines = getProperty("FLAT.LINES", 0);
194        int elements = getProperty("FLAT.ELEMENTS", 0);
195        String unit = getProperty("FLAT.UNIT", "");
196        int stride = getProperty("FLAT.STRIDE", 1);
197
198        Hashtable imageProps = Misc.newHashtable(DataChoice.PROP_ICON, "/auxdata/ui/icons/Earth16.gif");
199        String delimiter = getProperty("ASCII.DELIMITER", "");
200
201        List categories = DataCategory.parseCategories("IMAGE", false);
202        CompositeDataChoice cdc = new CompositeDataChoice(this, "", name, name, null);
203        for (int i=0; i<bandFiles.size(); i++) {
204            FlatFileReader dataChoiceData = new FlatFileReader(bandFiles.get(i), lines, elements);
205            dataChoiceData.setAsciiInfo(delimiter, 1);
206            dataChoiceData.setUnit(unit);
207            dataChoiceData.setEastPositive(eastPositive);
208            dataChoiceData.setStride(stride);
209            if ((latFile != null) && (lonFile != null)) {
210                dataChoiceData.setNavFiles(latFile, lonFile, scale);
211            } else {
212                dataChoiceData.setNavBounds(ulLat, ulLon, lrLat, lrLon);
213            }
214            String bandName = bandNames.get(i);
215            DirectDataChoice ddc = new DirectDataChoice(this, dataChoiceData, bandName, bandName, categories, imageProps);
216            cdc.addDataChoice(ddc);
217        }
218        addDataChoice(cdc);
219//            System.err.println("Still working on ascii data...");
220    }
221
222    private void handleBinaryFormat(double ulLat, double ulLon, double lrLat, double lrLon, String latFile, String lonFile, int scale, boolean eastPositive) {
223        String name = getProperty("FLAT.NAME", "Unknown name");
224        List<String> bandsDefault = list("Band 1");
225        List<String> bandNames = (List<String>)getProperty("FLAT.BANDNAMES", bandsDefault);
226        List<String> bandFiles = (List<String>)getProperty("FLAT.BANDFILES", bandsDefault);
227
228        int lines = getProperty("FLAT.LINES", 0);
229        int elements = getProperty("FLAT.ELEMENTS", 0);
230        String unit = getProperty("FLAT.UNIT", "");
231        int stride = getProperty("FLAT.STRIDE", 1);
232
233        Hashtable imageProps = Misc.newHashtable(DataChoice.PROP_ICON, "/auxdata/ui/icons/Earth16.gif");
234        int format = getProperty("BINARY.FORMAT", HeaderInfo.kFormat1ByteUInt);
235        String interleave = getProperty("BINARY.INTERLEAVE", HeaderInfo.kInterleaveSequential);
236        boolean bigEndian = getProperty("BINARY.BIGENDIAN", false);
237        int offset = getProperty("BINARY.OFFSET", 0);
238
239        List categories = DataCategory.parseCategories("IMAGE", false);
240        CompositeDataChoice cdc = new CompositeDataChoice(this, "", name, name, null);
241        for (int i=0; i<bandFiles.size(); i++) {
242            FlatFileReader dataChoiceData = new FlatFileReader(bandFiles.get(i), lines, elements);
243            dataChoiceData.setBinaryInfo(format, interleave, bigEndian, offset, i+1, bandFiles.size());
244            dataChoiceData.setUnit(unit);
245            dataChoiceData.setEastPositive(eastPositive);
246            dataChoiceData.setStride(stride);
247            if ((latFile != null) && (lonFile != null)) {
248                dataChoiceData.setNavFiles(latFile, lonFile, scale);
249            } else {
250                dataChoiceData.setNavBounds(ulLat, ulLon, lrLat, lrLon);
251            }
252            String bandName = bandNames.get(i);
253            DirectDataChoice ddc = new DirectDataChoice(this, dataChoiceData, bandName, bandName, categories, imageProps);
254            cdc.addDataChoice(ddc);
255        }
256        addDataChoice(cdc);
257        //            System.err.println("Still working on binary data...");
258    }
259
260    /**
261     * This method should create and return the visad.Data that is
262     * identified by the given {@link DataChoice}.
263     *
264     * @param dataChoice     This is one of the DataChoice-s that was created
265     *                       in the doMakeDataChoices call above.
266     * @param category       The specific {@link DataCategory}
267     *                       which the {@link ucar.unidata.idv.DisplayControl}
268     *                       was instantiated with. Usually can be ignored.
269     * @param dataSelection  This may contain a list of times which
270     *                       subsets the request.
271     * @param requestProperties  extra request properties
272     *
273     * @return {@link Data} object represented by the given dataChoice
274     *
275     * @throws RemoteException Java RMI problem.
276     * @throws VisADException VisAD problem.
277     */
278    protected Data getDataInner(DataChoice dataChoice, DataCategory category,
279                                DataSelection dataSelection,
280                                Hashtable requestProperties)
281        throws VisADException, RemoteException
282    {
283        FlatFileReader stuff = (FlatFileReader) dataChoice.getId();
284        return stuff.getData();
285    }
286
287}
288