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    
053    package org.jfree.data.general;
054    
055    import org.jfree.data.xy.AbstractIntervalXYDataset;
056    import org.jfree.data.xy.IntervalXYDataset;
057    import org.jfree.data.xy.OHLCDataset;
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    public 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    }