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