    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    }