001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2006, 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     * DefaultHighLowDataset.java
029     * --------------------------
030     * (C) Copyright 2002-2006, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: DefaultHighLowDataset.java,v 1.6.2.2 2006/11/28 10:41:51 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 21-Mar-2002 : Version 1 (DG);
040     * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
041     * 06-May-2004 : Now extends AbstractXYDataset and added new methods from 
042     *               HighLowDataset (DG);
043     * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
044     *               getYValue() (DG);
045     * ------------- JFREECHART 1.0.x ---------------------------------------------
046     * 28-Nov-2006 : Added equals() method override (DG);
047     *
048     */
049    
050    package org.jfree.data.xy;
051    
052    import java.util.Arrays;
053    import java.util.Date;
054    
055    /**
056     * A simple implementation of the {@link OHLCDataset} interface.  See also
057     * the {@link DefaultOHLCDataset} class, which provides another implementation
058     * that is very similar.
059     */
060    public class DefaultHighLowDataset extends AbstractXYDataset 
061                                       implements OHLCDataset {
062    
063        /** The series key. */
064        private Comparable seriesKey;
065    
066        /** Storage for the dates. */
067        private Date[] date;
068    
069        /** Storage for the high values. */
070        private Number[] high;
071    
072        /** Storage for the low values. */
073        private Number[] low;
074    
075        /** Storage for the open values. */
076        private Number[] open;
077    
078        /** Storage for the close values. */
079        private Number[] close;
080    
081        /** Storage for the volume values. */
082        private Number[] volume;
083    
084        /**
085         * Constructs a new high/low/open/close dataset.
086         * <p>
087         * The current implementation allows only one series in the dataset.
088         * This may be extended in a future version.
089         *
090         * @param seriesKey  the key for the series (<code>null</code> not 
091         *     permitted).
092         * @param date  the dates (<code>null</code> not permitted).
093         * @param high  the high values (<code>null</code> not permitted).
094         * @param low  the low values (<code>null</code> not permitted).
095         * @param open  the open values (<code>null</code> not permitted).
096         * @param close  the close values (<code>null</code> not permitted).
097         * @param volume  the volume values (<code>null</code> not permitted).
098         */
099        public DefaultHighLowDataset(Comparable seriesKey, Date[] date, 
100                double[] high, double[] low, double[] open, double[] close,
101                double[] volume) {
102    
103            if (seriesKey == null) {
104                throw new IllegalArgumentException("Null 'series' argument.");
105            }
106            if (date == null) {
107                throw new IllegalArgumentException("Null 'date' argument.");
108            }
109            this.seriesKey = seriesKey;
110            this.date = date;
111            this.high = createNumberArray(high);
112            this.low = createNumberArray(low);
113            this.open = createNumberArray(open);
114            this.close = createNumberArray(close);
115            this.volume = createNumberArray(volume);
116    
117        }
118    
119        /**
120         * Returns the key for the series stored in this dataset.
121         *
122         * @param series  the index of the series (ignored, this dataset supports 
123         *     only one series and this method always returns the key for series 0).
124         * 
125         * @return The series key (never <code>null</code>).
126         */
127        public Comparable getSeriesKey(int series) {
128            return this.seriesKey;
129        }
130        
131        /**
132         * Returns the x-value for one item in a series.  The value returned is a 
133         * <code>Long</code> instance generated from the underlying 
134         * <code>Date</code> object.  To avoid generating a new object instance,
135         * you might prefer to call {@link #getXValue(int, int)}.
136         *
137         * @param series  the series (zero-based index).
138         * @param item  the item (zero-based index).
139         *
140         * @return The x-value.
141         * 
142         * @see #getXValue(int, int)
143         * @see #getXDate(int, int)
144         */
145        public Number getX(int series, int item) {
146            return new Long(this.date[item].getTime());
147        }
148    
149        /**
150         * Returns the x-value for one item in a series, as a Date.
151         * <p>
152         * This method is provided for convenience only.
153         *
154         * @param series  the series (zero-based index).
155         * @param item  the item (zero-based index).
156         *
157         * @return The x-value as a Date.
158         * 
159         * @see #getX(int, int)
160         */
161        public Date getXDate(int series, int item) {
162            return this.date[item];
163        }
164    
165        /**
166         * Returns the y-value for one item in a series.
167         * <p>
168         * This method (from the {@link XYDataset} interface) is mapped to the 
169         * {@link #getCloseValue(int, int)} method.
170         *
171         * @param series  the series (zero-based index).
172         * @param item  the item (zero-based index).
173         *
174         * @return The y-value.
175         * 
176         * @see #getYValue(int, int)
177         */
178        public Number getY(int series, int item) {
179            return getClose(series, item);
180        }
181    
182        /**
183         * Returns the high-value for one item in a series.
184         *
185         * @param series  the series (zero-based index).
186         * @param item  the item (zero-based index).
187         *
188         * @return The high-value.
189         * 
190         * @see #getHighValue(int, int)
191         */
192        public Number getHigh(int series, int item) {
193            return this.high[item];
194        }
195    
196        /**
197         * Returns the high-value (as a double primitive) for an item within a 
198         * series.
199         * 
200         * @param series  the series (zero-based index).
201         * @param item  the item (zero-based index).
202         * 
203         * @return The high-value.
204         * 
205         * @see #getHigh(int, int)
206         */
207        public double getHighValue(int series, int item) {
208            double result = Double.NaN;
209            Number high = getHigh(series, item);
210            if (high != null) {
211                result = high.doubleValue();   
212            }
213            return result;   
214        }
215    
216        /**
217         * Returns the low-value for one item in a series.
218         *
219         * @param series  the series (zero-based index).
220         * @param item  the item (zero-based index).
221         *
222         * @return The low-value.
223         * 
224         * @see #getLowValue(int, int)
225         */
226        public Number getLow(int series, int item) {
227            return this.low[item];
228        }
229    
230        /**
231         * Returns the low-value (as a double primitive) for an item within a 
232         * series.
233         * 
234         * @param series  the series (zero-based index).
235         * @param item  the item (zero-based index).
236         * 
237         * @return The low-value.
238         * 
239         * @see #getLow(int, int)
240         */
241        public double getLowValue(int series, int item) {
242            double result = Double.NaN;
243            Number low = getLow(series, item);
244            if (low != null) {
245                result = low.doubleValue();   
246            }
247            return result;   
248        }
249    
250        /**
251         * Returns the open-value for one item in a series.
252         *
253         * @param series  the series (zero-based index).
254         * @param item  the item (zero-based index).
255         *
256         * @return The open-value.
257         * 
258         * @see #getOpenValue(int, int)
259         */
260        public Number getOpen(int series, int item) {
261            return this.open[item];
262        }
263    
264        /**
265         * Returns the open-value (as a double primitive) for an item within a 
266         * series.
267         * 
268         * @param series  the series (zero-based index).
269         * @param item  the item (zero-based index).
270         * 
271         * @return The open-value.
272         * 
273         * @see #getOpen(int, int)
274         */
275        public double getOpenValue(int series, int item) {
276            double result = Double.NaN;
277            Number open = getOpen(series, item);
278            if (open != null) {
279                result = open.doubleValue();   
280            }
281            return result;   
282        }
283    
284        /**
285         * Returns the close-value for one item in a series.
286         *
287         * @param series  the series (zero-based index).
288         * @param item  the item (zero-based index).
289         *
290         * @return The close-value.
291         * 
292         * @see #getCloseValue(int, int)
293         */
294        public Number getClose(int series, int item) {
295            return this.close[item];
296        }
297    
298        /**
299         * Returns the close-value (as a double primitive) for an item within a 
300         * series.
301         * 
302         * @param series  the series (zero-based index).
303         * @param item  the item (zero-based index).
304         * 
305         * @return The close-value.
306         * 
307         * @see #getClose(int, int)
308         */
309        public double getCloseValue(int series, int item) {
310            double result = Double.NaN;
311            Number close = getClose(series, item);
312            if (close != null) {
313                result = close.doubleValue();   
314            }
315            return result;   
316        }
317    
318        /**
319         * Returns the volume-value for one item in a series.
320         *
321         * @param series  the series (zero-based index).
322         * @param item  the item (zero-based index).
323         *
324         * @return The volume-value.
325         * 
326         * @see #getVolumeValue(int, int)
327         */
328        public Number getVolume(int series, int item) {
329            return this.volume[item];
330        }
331    
332        /**
333         * Returns the volume-value (as a double primitive) for an item within a 
334         * series.
335         * 
336         * @param series  the series (zero-based index).
337         * @param item  the item (zero-based index).
338         * 
339         * @return The volume-value.
340         * 
341         * @see #getVolume(int, int)
342         */
343        public double getVolumeValue(int series, int item) {
344            double result = Double.NaN;
345            Number volume = getVolume(series, item);
346            if (volume != null) {
347                result = volume.doubleValue();   
348            }
349            return result;   
350        }
351    
352        /**
353         * Returns the number of series in the dataset.
354         * <p>
355         * This implementation only allows one series.
356         *
357         * @return The number of series.
358         */
359        public int getSeriesCount() {
360            return 1;
361        }
362    
363        /**
364         * Returns the number of items in the specified series.
365         *
366         * @param series  the index (zero-based) of the series.
367         *
368         * @return The number of items in the specified series.
369         */
370        public int getItemCount(int series) {
371            return this.date.length;
372        }
373    
374        /**
375         * Tests this dataset for equality with an arbitrary instance.
376         * 
377         * @param obj  the object (<code>null</code> permitted).
378         * 
379         * @return A boolean.
380         */
381        public boolean equals(Object obj) {
382            if (obj == this) {
383                return true;
384            }
385            if (!(obj instanceof DefaultHighLowDataset)) {
386                return false;
387            }
388            DefaultHighLowDataset that = (DefaultHighLowDataset) obj;
389            if (!this.seriesKey.equals(that.seriesKey)) {
390                return false;
391            }
392            if (!Arrays.equals(this.date, that.date)) {
393                return false;
394            }
395            if (!Arrays.equals(this.open, that.open)) {
396                return false;
397            }
398            if (!Arrays.equals(this.high, that.high)) {
399                return false;
400            }
401            if (!Arrays.equals(this.low, that.low)) {
402                return false;
403            }
404            if (!Arrays.equals(this.close, that.close)) {
405                return false;
406            }
407            if (!Arrays.equals(this.volume, that.volume)) {
408                return false;
409            }
410            return true;    
411        }
412        
413        /**
414         * Constructs an array of Number objects from an array of doubles.
415         *
416         * @param data  the double values to convert (<code>null</code> not 
417         *     permitted).
418         *
419         * @return The data as an array of Number objects.
420         */
421        public static Number[] createNumberArray(double[] data) {
422            Number[] result = new Number[data.length];
423            for (int i = 0; i < data.length; i++) {
424                result[i] = new Double(data[i]);
425            }
426            return result;
427        }
428    
429    }