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 java.util.List;
032import java.util.StringTokenizer;
033
034import java.awt.Image;
035
036import ucar.unidata.util.ColorTable;
037
038/**
039 * Class to hold McIDAS-X frame data sets.
040 */
041public class McIdasFrame {
042
043    /** frame data */
044    private int myFrameNumber = 0;
045    private McIdasXFrameInfo myXFrameInfo;
046
047    /**
048     * Keep local copies of everything so we don't have to go back over the
049     * bridge unless asked to refresh
050     */
051    private int myLineSize = -1;
052    private int myElementSize = -1;
053    private FrameDirectory myFrameDirectory;
054    private ColorTable myColorTable;
055    private byte[] myImage;
056    private byte[] myGraphics;
057
058    /**
059     *  Empty constructor for XML encoding
060     */
061    public McIdasFrame() {}
062
063    /**
064     * Construct a new McIdasFrame from the given frame number
065     *
066     * @param frameNumber Frame number.
067     * @param xInfo State of McIDAS-X session.
068     */
069    public McIdasFrame(int frameNumber, McIdasXInfo xInfo) {
070//      System.out.println("McIdasFrame constructor for frame: " + frameNumber);
071        this.myFrameNumber = frameNumber;
072        this.myXFrameInfo = new McIdasXFrameInfo(frameNumber, xInfo);
073    }
074
075    /**
076     * Returns frame number.
077     *
078     * @return {@link #myFrameNumber}.
079     */
080    public int getFrameNumber() {
081//      System.out.println("McIdasFrame getFrameNumber: " + this.myFrameNumber);
082        return this.myFrameNumber;
083    }
084
085    /**
086     * Tell {@link #myXFrameInfo} to refresh the cached data.
087     *
088     * @param refresh Whether or not to refresh cached data.
089     */
090    public void setRefreshData(boolean refresh) {
091//              System.out.println("McIdasFrame setRefreshData(" + refresh + ")");
092        this.myXFrameInfo.setRefreshData(refresh);
093    }
094
095    /**
096     * Returns line size.
097     *
098     * @param refresh Whether or not to refresh {@link #myLineSize}.
099     *
100     * @return {@link #myLineSize}.
101     */
102    public int getLineSize(boolean refresh) {
103//              System.out.println("McIdasFrame getLineSize(" + refresh + ")");
104        if (this.myLineSize < 0 || refresh) {
105            this.myLineSize = this.myXFrameInfo.getLineSize();
106        }
107        return this.myLineSize;
108    }
109
110    /**
111     * Returns element size.
112     *
113     * @param refresh Whether or not {@link #myElementSize} should be refreshed.
114     *
115     * @return {@link #myElementSize}.
116     */
117    public int getElementSize(boolean refresh) {
118//              System.out.println("McIdasFrame getElementSize(" + refresh + ")");
119        if (this.myElementSize <0 || refresh) {
120            this.myElementSize = this.myXFrameInfo.getElementSize();
121        }
122        return this.myElementSize;
123    }
124
125    /**
126     * Returns frame directory.
127     *
128     * @param refresh Whether or not {@link #myFrameDirectory} should be
129     *                refreshed.
130     *
131     * @return {@link #myFrameDirectory}.
132     */
133    public FrameDirectory getFrameDirectory(boolean refresh) {
134//              System.out.println("McIdasFrame getFrameDirectory(" + refresh + ")");
135        if (this.myFrameDirectory == null || refresh) {
136            this.myFrameDirectory =
137                new FrameDirectory(this.myXFrameInfo.getFrameDirectory());
138        }
139        return this.myFrameDirectory;
140    }
141
142    /**
143     * Returns {@link ColorTable} used by {@link #myXFrameInfo}.
144     *
145     * @param refresh Whether or not {@link #myColorTable} should be refreshed.
146     *
147     * @return {@link #myColorTable}.
148     */
149    public ColorTable getColorTable(boolean refresh) {
150//              System.out.println("McIdasFrame getColorTable(" + refresh + ")");
151        if (this.myColorTable == null || refresh) {
152            this.myColorTable =
153                new ColorTable("McIDAS-X",ColorTable.CATEGORY_BASIC,
154                    this.myXFrameInfo.getEnhancementTable());
155        }
156        return this.myColorTable;
157    }
158
159    /**
160     * Returns image data.
161     *
162     * @param refresh Whether or not {@link #myImage} should be refreshed.
163     *
164     * @return {@link #myImage}.
165     */
166    public byte[] getImageData(boolean refresh) {
167//              System.out.println("McIdasFrame getImageData(" + refresh + ")");
168        if (this.myImage == null || refresh) {
169            byte[] image = this.myXFrameInfo.getImage();
170            int height = this.myLineSize;
171            int width = this.myElementSize;
172            this.myImage = new byte[height * width];
173            for (int i = 0; i < height; i++) {
174                for (int j = 0; j < width; j++) {
175                    this.myImage[i * width + j] =
176                        image[(height - i - 1) * width + j];
177                }
178            }
179        }
180        return this.myImage;
181    }
182
183    /**
184     * Returns graphics data.
185     *
186     * @param refresh Whether or not {@link #myGraphics} should be refreshed.
187     *
188     * @return {@link #myGraphics}.
189     */
190    public byte[] getGraphicsData(boolean refresh) {
191//              System.out.println("McIdasFrame getGraphicsData(" + refresh + ")");
192        if (this.myGraphics == null || refresh) {
193            List graphics = this.myXFrameInfo.getGraphics();
194            int height = this.myLineSize;
195            int width = this.myElementSize;
196            this.myGraphics = new byte[height*width];
197            for (int i = 0; i < this.myGraphics.length; i++) {
198                this.myGraphics[i] = (byte)255;
199            }
200            String line;
201            StringTokenizer tok;
202            int[] graphicsPt = new int[3];
203            for (int i = 0; i < graphics.size(); i++) {
204                line = (String)(graphics.get(i));
205                tok = new StringTokenizer(line);
206                for (int j = 0; j < 3; j++) {
207                    graphicsPt[j] = new Integer(tok.nextToken()).intValue();
208                }
209                int color = graphicsPt[2];
210                int x = graphicsPt[1] - 1;
211                int y = graphicsPt[0] - 1;
212                if (((y < height) && ( y > 0)) && ((x < width) && (x > 0))) {
213                    this.myGraphics[y*width + x] = (byte)color;
214                }
215            }
216        }
217        return this.myGraphics;
218    }
219
220    /**
221     * Returns image data as GIF.
222     *
223     * @return {@link #myXFrameInfo} in GIF format.
224     */
225    public Image getGIF() {
226        return this.myXFrameInfo.getGIF();
227    }
228
229    /**
230     * See if this McIdasFrame is equal to the object in question.
231     *
232     * @param o Object in question.
233     *
234     * @return true if {@code o} is a McIdasFrame and they area equivalent.
235     */
236    public boolean equals(Object o) {
237        if ( !(o instanceof McIdasFrame)) {
238            return false;
239        }
240        McIdasFrame that = (McIdasFrame) o;
241//        System.out.println("McIdasFrame equals: " + this.toString() + " vs " + that.toString());
242        return (this.myFrameNumber == that.myFrameNumber);
243    }
244
245    /**
246     * Get a String representation of this object
247     *
248     * @return a string representation
249     */
250    public String toString() {
251        StringBuffer buf = new StringBuffer();
252        if (this.myFrameNumber > 0) {
253            buf.append("Frame " + this.myFrameNumber);
254        }
255//      System.out.println("McIdasFrame toString: " + buf);
256        return buf.toString();
257    }
258}