001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     *
027     * -----------------------
028     * DefaultWindDataset.java
029     * -----------------------
030     * (C) Copyright 2001-2005, by Achilleus Mantzios and Contributors.
031     *
032     * Original Author:  Achilleus Mantzios;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *
035     * $Id: DefaultWindDataset.java,v 1.5.2.1 2005/10/25 21:36:51 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 06-Feb-2002 : Version 1, based on code contributed by Achilleus 
040     *               Mantzios (DG);
041     * 05-May-2004 : Now extends AbstractXYDataset (DG);
042     * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
043     *               getYValue() (DG);
044     *
045     */
046    
047    package org.jfree.data.xy;
048    
049    import java.util.Arrays;
050    import java.util.Collections;
051    import java.util.Date;
052    import java.util.List;
053    
054    /**
055     * A default implementation of the {@link WindDataset} interface.
056     *
057     * @author Achilleus Mantzios
058     */
059    public class DefaultWindDataset extends AbstractXYDataset 
060                                    implements WindDataset {
061    
062        /** The keys for the series. */
063        private List seriesKeys;
064    
065        /** Storage for the series data. */
066        private List allSeriesData;
067    
068        /**
069         * Constructs a new, empty, dataset.
070         */
071        public DefaultWindDataset() {
072            this.seriesKeys = new java.util.ArrayList();
073            this.allSeriesData = new java.util.ArrayList();
074        }
075    
076        /**
077         * Constructs a dataset based on the specified data array.
078         *
079         * @param data  the data.
080         */
081        public DefaultWindDataset(Object[][][] data) {
082            this(seriesNameListFromDataArray(data), data);
083        }
084    
085        /**
086         * Constructs a dataset based on the specified data array.
087         *
088         * @param seriesNames    the names of the series.
089         * @param data  the wind data.
090         */
091        public DefaultWindDataset(String[] seriesNames, Object[][][] data) {
092            this(Arrays.asList(seriesNames), data);
093        }
094    
095        /**
096         * Constructs a dataset based on the specified data array.  The array
097         * can contain multiple series, each series can contain multiple items,
098         * and each item is as follows:
099         * <ul>
100         * <li><code>data[series][item][0]</code> - the date (either a 
101         *   <code>Date</code> or a <code>Number</code> that is the milliseconds 
102         *   since 1-Jan-1970);</li>
103         * <li><code>data[series][item][1]</code> - the wind direction (1 - 12, 
104         *   like the numbers on a clock face);</li>
105         * <li><code>data[series][item][2]</code> - the wind force (1 - 12 on the
106         *   Beaufort scale)</li>
107         * </ul>
108         * 
109         * @param seriesKeys  the names of the series.
110         * @param data  the wind dataset.
111         */
112        public DefaultWindDataset(List seriesKeys, Object[][][] data) {
113    
114            this.seriesKeys = seriesKeys;
115            int seriesCount = data.length;
116            this.allSeriesData = new java.util.ArrayList(seriesCount);
117    
118            for (int seriesIndex = 0; seriesIndex < seriesCount; seriesIndex++) {
119                List oneSeriesData = new java.util.ArrayList();
120                int maxItemCount = data[seriesIndex].length;
121                for (int itemIndex = 0; itemIndex < maxItemCount; itemIndex++) {
122                    Object xObject = data[seriesIndex][itemIndex][0];
123                    if (xObject != null) {
124                        Number xNumber;
125                        if (xObject instanceof Number) {
126                            xNumber = (Number) xObject;
127                        }
128                        else {
129                            if (xObject instanceof Date) {
130                                Date xDate = (Date) xObject;
131                                xNumber = new Long(xDate.getTime());
132                            }
133                            else {
134                                xNumber = new Integer(0);
135                            }
136                        }
137                        Number windDir = (Number) data[seriesIndex][itemIndex][1];
138                        Number windForce = (Number) data[seriesIndex][itemIndex][2];
139                        oneSeriesData.add(
140                            new WindDataItem(xNumber, windDir, windForce)
141                        );
142                    }
143                }
144                Collections.sort(oneSeriesData);
145                this.allSeriesData.add(seriesIndex, oneSeriesData);
146            }
147    
148        }
149    
150        /**
151         * Returns the number of series in the dataset.
152         * 
153         * @return The series count.
154         */
155        public int getSeriesCount() {
156            return this.allSeriesData.size();
157        }
158    
159        /**
160         * Returns the number of items in a series.
161         * 
162         * @param series  the series (zero-based index).
163         * 
164         * @return The item count.
165         */
166        public int getItemCount(int series) {
167            List oneSeriesData = (List) this.allSeriesData.get(series);
168            return oneSeriesData.size();
169        }
170    
171        /**
172         * Returns the key for a series.
173         * 
174         * @param series  the series (zero-based index).
175         * 
176         * @return The series key.
177         */
178        public Comparable getSeriesKey(int series) {
179            return this.seriesKeys.get(series).toString();
180        }
181    
182        /**
183         * Returns the x-value for one item within a series.  This should represent
184         * a point in time, encoded as milliseconds in the same way as
185         * java.util.Date.
186         *
187         * @param series  the series (zero-based index).
188         * @param item  the item (zero-based index).
189         * 
190         * @return The x-value for the item within the series.
191         */
192        public Number getX(int series, int item) {
193            List oneSeriesData = (List) this.allSeriesData.get(series);
194            WindDataItem windItem = (WindDataItem) oneSeriesData.get(item);
195            return windItem.getX();
196        }
197    
198        /**
199         * Returns the y-value for one item within a series.  This maps to the
200         * {@link #getWindForce(int, int)} method and is implemented because 
201         * <code>WindDataset</code> is an extension of {@link XYDataset}.
202         *
203         * @param series  the series (zero-based index).
204         * @param item  the item (zero-based index).
205         * 
206         * @return The y-value for the item within the series.
207         */
208        public Number getY(int series, int item) {
209            return getWindForce(series, item);
210        }
211    
212        /**
213         * Returns the wind direction for one item within a series.  This is a
214         * number between 0 and 12, like the numbers on a clock face.
215         * 
216         * @param series  the series (zero-based index).
217         * @param item  the item (zero-based index).
218         * 
219         * @return The wind direction for the item within the series.
220         */
221        public Number getWindDirection(int series, int item) {
222            List oneSeriesData = (List) this.allSeriesData.get(series);
223            WindDataItem windItem = (WindDataItem) oneSeriesData.get(item);
224            return windItem.getWindDirection();
225        }
226    
227        /**
228         * Returns the wind force for one item within a series.  This is a number
229         * between 0 and 12, as defined by the Beaufort scale.
230         * 
231         * @param series  the series (zero-based index).
232         * @param item  the item (zero-based index).
233         * 
234         * @return The wind force for the item within the series.
235         */
236        public Number getWindForce(int series, int item) {
237            List oneSeriesData = (List) this.allSeriesData.get(series);
238            WindDataItem windItem = (WindDataItem) oneSeriesData.get(item);
239            return windItem.getWindForce();
240        }
241    
242        /**
243         * Utility method for automatically generating series names.
244         * @param data  the wind dataset.
245         *
246         * @return An array of <i>Series N</i> with N = { 1 .. data.length }.
247         */
248        public static List seriesNameListFromDataArray(Object[][] data) {
249    
250            int seriesCount = data.length;
251            List seriesNameList = new java.util.ArrayList(seriesCount);
252            for (int i = 0; i < seriesCount; i++) {
253                seriesNameList.add("Series " + (i + 1));
254            }
255            return seriesNameList;
256    
257        }
258    
259    }
260    
261    /**
262     * A wind data item.
263     *
264     * @author Achilleus Mantzios
265     */
266    class WindDataItem implements Comparable {
267    
268        /** The x-value. */
269        private Number x;
270    
271        /** The wind direction. */
272        private Number windDir;
273    
274        /** The wind force. */
275        private Number windForce;
276    
277        /**
278         * Creates a new wind data item.
279         *
280         * @param x  the x-value.
281         * @param windDir  the direction.
282         * @param windForce  the force.
283         */
284        public WindDataItem(Number x, Number windDir, Number windForce) {
285            this.x = x;
286            this.windDir = windDir;
287            this.windForce = windForce;
288        }
289    
290        /**
291         * Returns the x-value.
292         *
293         * @return The x-value.
294         */
295        public Number getX() {
296            return this.x;
297        }
298    
299        /**
300         * Returns the wind direction.
301         *
302         * @return The wind direction.
303         */
304        public Number getWindDirection() {
305            return this.windDir;
306        }
307    
308        /**
309         * Returns the wind force.
310         *
311         * @return The wind force.
312         */
313        public Number getWindForce() {
314            return this.windForce;
315        }
316    
317        /**
318         * Compares this item to another object.
319         *
320         * @param object  the other object.
321         *
322         * @return An int that indicates the relative comparison.
323         */
324        public int compareTo(Object object) {
325            if (object instanceof WindDataItem) {
326                WindDataItem item = (WindDataItem) object;
327                if (this.x.doubleValue() > item.x.doubleValue()) {
328                    return 1;
329                }
330                else if (this.x.equals(item.x)) {
331                    return 0;
332                }
333                else {
334                    return -1;
335                }
336            }
337            else {
338                throw new ClassCastException("WindDataItem.compareTo(error)");
339            }
340        }
341    
342    }