001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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 * SubseriesDataset.java
029 * ---------------------
030 * (C) Copyright 2001-2007, by Bill Kelemen and Contributors.
031 *
032 * Original Author:  Bill Kelemen;
033 * Contributor(s):   Sylvain Vieujot;
034 *                   David Gilbert (for Object Refinery Limited);
035 *
036 * Changes
037 * -------
038 * 06-Dec-2001 : Version 1 (BK);
039 * 05-Feb-2002 : Added SignalsDataset (and small change to HighLowDataset 
040 *               interface) as requested by Sylvain Vieujot (DG);
041 * 28-Feb-2002 : Fixed bug: missing map[series] in IntervalXYDataset and 
042 *               SignalsDataset methods (BK);
043 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
044 * 06-May-2004 : Now extends AbstractIntervalXYDataset (DG);
045 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
046 *               getYValue() (DG);
047 * 29-Nov-2005 : Removed SignalsDataset (DG);
048 * ------------- JFREECHART 1.0.x ---------------------------------------------
049 * 02-Feb-2007 : Removed author tags from all over JFreeChart sources (DG);
050 *
051 */
052
053package org.jfree.data.general;
054
055import org.jfree.data.xy.AbstractIntervalXYDataset;
056import org.jfree.data.xy.IntervalXYDataset;
057import org.jfree.data.xy.OHLCDataset;
058import org.jfree.data.xy.XYDataset;
059
060/**
061 * This class will create a dataset with one or more series from another
062 * {@link SeriesDataset}. 
063 */
064public class SubSeriesDataset extends AbstractIntervalXYDataset
065                              implements OHLCDataset,
066                                         IntervalXYDataset,
067                                         CombinationDataset {
068
069    /** The parent dataset. */
070    private SeriesDataset parent = null;
071
072    /** Storage for map. */
073    private int[] map;  // maps our series into our parent's
074
075    /**
076     * Creates a SubSeriesDataset using one or more series from 
077     * <code>parent</code>.  The series to use are passed as an array of int.
078     *
079     * @param parent  underlying dataset
080     * @param map  int[] of series from parent to include in this Dataset
081     */
082    public SubSeriesDataset(SeriesDataset parent, int[] map) {
083        this.parent = parent;
084        this.map = map;
085    }
086
087    /**
088     * Creates a SubSeriesDataset using one series from <code>parent</code>.
089     * The series to is passed as an int.
090     *
091     * @param parent  underlying dataset
092     * @param series  series from parent to include in this Dataset
093     */
094    public SubSeriesDataset(SeriesDataset parent, int series) {
095        this(parent, new int[] {series});
096    }
097
098    ///////////////////////////////////////////////////////////////////////////
099    // From HighLowDataset
100    ///////////////////////////////////////////////////////////////////////////
101
102    /**
103     * Returns the high-value for the specified series and item.
104     * <p>
105     * Note: throws <code>ClassCastException</code> if the series if not from a 
106     * {@link OHLCDataset}.
107     *
108     * @param series  the index of the series of interest (zero-based).
109     * @param item  the index of the item of interest (zero-based).
110     *
111     * @return The high-value for the specified series and item.
112     */
113    public Number getHigh(int series, int item) {
114        return ((OHLCDataset) this.parent).getHigh(this.map[series], item);
115    }
116
117    /**
118     * Returns the high-value (as a double primitive) for an item within a 
119     * series.
120     * 
121     * @param series  the series (zero-based index).
122     * @param item  the item (zero-based index).
123     * 
124     * @return The high-value.
125     */
126    public double getHighValue(int series, int item) {
127        double result = Double.NaN;
128        Number high = getHigh(series, item);
129        if (high != null) {
130            result = high.doubleValue();   
131        }
132        return result;   
133    }
134
135    /**
136     * Returns the low-value for the specified series and item.
137     * <p>
138     * Note: throws <code>ClassCastException</code> if the series if not from a 
139     * {@link OHLCDataset}.
140     *
141     * @param series  the index of the series of interest (zero-based).
142     * @param item  the index of the item of interest (zero-based).
143     *
144     * @return The low-value for the specified series and item.
145     */
146    public Number getLow(int series, int item) {
147        return ((OHLCDataset) this.parent).getLow(this.map[series], item);
148    }
149
150    /**
151     * Returns the low-value (as a double primitive) for an item within a 
152     * series.
153     * 
154     * @param series  the series (zero-based index).
155     * @param item  the item (zero-based index).
156     * 
157     * @return The low-value.
158     */
159    public double getLowValue(int series, int item) {
160        double result = Double.NaN;
161        Number low = getLow(series, item);
162        if (low != null) {
163            result = low.doubleValue();   
164        }
165        return result;   
166    }
167
168    /**
169     * Returns the open-value for the specified series and item.
170     * <p>
171     * Note: throws <code>ClassCastException</code> if the series if not from a 
172     * {@link OHLCDataset}.
173     *
174     * @param series  the index of the series of interest (zero-based).
175     * @param item  the index of the item of interest (zero-based).
176     *
177     * @return The open-value for the specified series and item.
178     */
179    public Number getOpen(int series, int item) {
180        return ((OHLCDataset) this.parent).getOpen(this.map[series], item);
181    }
182
183    /**
184     * Returns the open-value (as a double primitive) for an item within a 
185     * series.
186     * 
187     * @param series  the series (zero-based index).
188     * @param item  the item (zero-based index).
189     * 
190     * @return The open-value.
191     */
192    public double getOpenValue(int series, int item) {
193        double result = Double.NaN;
194        Number open = getOpen(series, item);
195        if (open != null) {
196            result = open.doubleValue();   
197        }
198        return result;   
199    }
200
201    /**
202     * Returns the close-value for the specified series and item.
203     * <p>
204     * Note: throws <code>ClassCastException</code> if the series if not from a 
205     * {@link OHLCDataset}.
206     *
207     * @param series  the index of the series of interest (zero-based).
208     * @param item  the index of the item of interest (zero-based).
209     *
210     * @return The close-value for the specified series and item.
211     */
212    public Number getClose(int series, int item) {
213        return ((OHLCDataset) this.parent).getClose(this.map[series], item);
214    }
215
216    /**
217     * Returns the close-value (as a double primitive) for an item within a 
218     * series.
219     * 
220     * @param series  the series (zero-based index).
221     * @param item  the item (zero-based index).
222     * 
223     * @return The close-value.
224     */
225    public double getCloseValue(int series, int item) {
226        double result = Double.NaN;
227        Number close = getClose(series, item);
228        if (close != null) {
229            result = close.doubleValue();   
230        }
231        return result;   
232    }
233
234    /**
235     * Returns the volume.
236     * <p>
237     * Note: throws <code>ClassCastException</code> if the series if not from a 
238     * {@link OHLCDataset}.
239     *
240     * @param series  the series (zero based index).
241     * @param item  the item (zero based index).
242     *
243     * @return The volume.
244     */
245    public Number getVolume(int series, int item) {
246        return ((OHLCDataset) this.parent).getVolume(this.map[series], item);
247    }
248
249    /**
250     * Returns the volume-value (as a double primitive) for an item within a 
251     * series.
252     * 
253     * @param series  the series (zero-based index).
254     * @param item  the item (zero-based index).
255     * 
256     * @return The volume-value.
257     */
258    public double getVolumeValue(int series, int item) {
259        double result = Double.NaN;
260        Number volume = getVolume(series, item);
261        if (volume != null) {
262            result = volume.doubleValue();   
263        }
264        return result;   
265    }
266
267    ///////////////////////////////////////////////////////////////////////////
268    // From XYDataset
269    ///////////////////////////////////////////////////////////////////////////
270
271    /**
272     * Returns the X-value for the specified series and item.
273     * <p>
274     * Note: throws <code>ClassCastException</code> if the series if not from a 
275     * {@link XYDataset}.
276     *
277     * @param series  the index of the series of interest (zero-based);
278     * @param item  the index of the item of interest (zero-based).
279     *
280     * @return The X-value for the specified series and item.
281     */
282    public Number getX(int series, int item) {
283        return ((XYDataset) this.parent).getX(this.map[series], item);
284    }
285
286    /**
287     * Returns the Y-value for the specified series and item.
288     * <p>
289     * Note: throws <code>ClassCastException</code> if the series if not from a 
290     * {@link XYDataset}.
291     *
292     * @param series  the index of the series of interest (zero-based).
293     * @param item  the index of the item of interest (zero-based).
294     *
295     * @return The Y-value for the specified series and item.
296     */
297    public Number getY(int series, int item) {
298        return ((XYDataset) this.parent).getY(this.map[series], item);
299    }
300
301    /**
302     * Returns the number of items in a series.
303     * <p>
304     * Note: throws <code>ClassCastException</code> if the series if not from a 
305     * {@link XYDataset}.
306     *
307     * @param series  the index of the series of interest (zero-based).
308     *
309     * @return The number of items in a series.
310     */
311    public int getItemCount(int series) {
312        return ((XYDataset) this.parent).getItemCount(this.map[series]);
313    }
314
315    ///////////////////////////////////////////////////////////////////////////
316    // From SeriesDataset
317    ///////////////////////////////////////////////////////////////////////////
318
319    /**
320     * Returns the number of series in the dataset.
321     *
322     * @return The number of series in the dataset.
323     */
324    public int getSeriesCount() {
325        return this.map.length;
326    }
327
328    /**
329     * Returns the key for a series.
330     *
331     * @param series  the series (zero-based index).
332     *
333     * @return The name of a series.
334     */
335    public Comparable getSeriesKey(int series) {
336        return this.parent.getSeriesKey(this.map[series]);
337    }
338
339    ///////////////////////////////////////////////////////////////////////////
340    // From IntervalXYDataset
341    ///////////////////////////////////////////////////////////////////////////
342
343    /**
344     * Returns the starting X value for the specified series and item.
345     *
346     * @param series  the index of the series of interest (zero-based).
347     * @param item  the index of the item of interest (zero-based).
348     *
349     * @return The starting X value for the specified series and item.
350     */
351    public Number getStartX(int series, int item) {
352        if (this.parent instanceof IntervalXYDataset) {
353            return ((IntervalXYDataset) this.parent).getStartX(
354                this.map[series], item
355            );
356        }
357        else {
358            return getX(series, item);
359        }
360    }
361
362    /**
363     * Returns the ending X value for the specified series and item.
364     *
365     * @param series  the index of the series of interest (zero-based).
366     * @param item  the index of the item of interest (zero-based).
367     *
368     * @return The ending X value for the specified series and item.
369     */
370    public Number getEndX(int series, int item) {
371        if (this.parent instanceof IntervalXYDataset) {
372            return ((IntervalXYDataset) this.parent).getEndX(
373                this.map[series], item
374            );
375        }
376        else {
377            return getX(series, item);
378        }
379    }
380
381    /**
382     * Returns the starting Y value for the specified series and item.
383     *
384     * @param series  the index of the series of interest (zero-based).
385     * @param item  the index of the item of interest (zero-based).
386     *
387     * @return The starting Y value for the specified series and item.
388     */
389    public Number getStartY(int series, int item) {
390        if (this.parent instanceof IntervalXYDataset) {
391            return ((IntervalXYDataset) this.parent).getStartY(
392                this.map[series], item
393            );
394        }
395        else {
396            return getY(series, item);
397        }
398    }
399
400    /**
401     * Returns the ending Y value for the specified series and item.
402     *
403     * @param series  the index of the series of interest (zero-based).
404     * @param item  the index of the item of interest (zero-based).
405     *
406     * @return The ending Y value for the specified series and item.
407     */
408    public Number getEndY(int series,  int item) {
409        if (this.parent instanceof IntervalXYDataset) {
410            return ((IntervalXYDataset) this.parent).getEndY(
411                this.map[series], item
412            );
413        }
414        else {
415            return getY(series, item);
416        }
417    }
418
419    ///////////////////////////////////////////////////////////////////////////
420    // New methods from CombinationDataset
421    ///////////////////////////////////////////////////////////////////////////
422
423    /**
424     * Returns the parent Dataset of this combination.
425     *
426     * @return The parent Dataset of this combination.
427     */
428    public SeriesDataset getParent() {
429        return this.parent;
430    }
431
432    /**
433     * Returns a map or indirect indexing form our series into parent's series.
434     *
435     * @return A map or indirect indexing form our series into parent's series.
436     */
437    public int[] getMap() {
438        return (int[]) this.map.clone();
439    }
440
441}