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     * OHLCSeriesCollection.java
029     * -------------------------
030     * (C) Copyright 2006, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: OHLCSeriesCollection.java,v 1.1.2.1 2006/12/04 17:08:36 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 04-Dec-2006 : Version 1 (DG);
040     *
041     */
042    
043    package org.jfree.data.time.ohlc;
044    
045    import java.io.Serializable;
046    import java.util.List;
047    
048    import org.jfree.data.general.DatasetChangeEvent;
049    import org.jfree.data.time.RegularTimePeriod;
050    import org.jfree.data.time.TimePeriodAnchor;
051    import org.jfree.data.xy.AbstractXYDataset;
052    import org.jfree.data.xy.OHLCDataset;
053    import org.jfree.util.ObjectUtilities;
054    
055    /**
056     * A collection of {@link OHLCSeries} objects.
057     *
058     * @since 1.0.4
059     *
060     * @see OHLCSeries
061     */
062    public class OHLCSeriesCollection extends AbstractXYDataset
063                                    implements OHLCDataset, Serializable {
064    
065        /** Storage for the data series. */
066        private List data;
067        
068        private TimePeriodAnchor xPosition = TimePeriodAnchor.MIDDLE;
069        
070        /** 
071         * Creates a new instance of <code>OHLCSeriesCollection</code>. 
072         */
073        public OHLCSeriesCollection() {
074            this.data = new java.util.ArrayList();
075        }
076    
077        /**
078         * Adds a series to the collection and sends a {@link DatasetChangeEvent} 
079         * to all registered listeners.
080         *
081         * @param series  the series (<code>null</code> not permitted).
082         */
083        public void addSeries(OHLCSeries series) {
084            if (series == null) {
085                throw new IllegalArgumentException("Null 'series' argument.");
086            }
087            this.data.add(series);
088            series.addChangeListener(this);
089            fireDatasetChanged();
090        }
091    
092        /**
093         * Returns the number of series in the collection.
094         *
095         * @return The series count.
096         */
097        public int getSeriesCount() {
098            return this.data.size();
099        }
100    
101        /**
102         * Returns a series from the collection.
103         *
104         * @param series  the series index (zero-based).
105         *
106         * @return The series.
107         * 
108         * @throws IllegalArgumentException if <code>series</code> is not in the
109         *     range <code>0</code> to <code>getSeriesCount() - 1</code>.
110         */
111        public OHLCSeries getSeries(int series) {
112            if ((series < 0) || (series >= getSeriesCount())) {
113                throw new IllegalArgumentException("Series index out of bounds");
114            }
115            return (OHLCSeries) this.data.get(series);
116        }
117    
118        /**
119         * Returns the key for a series.
120         *
121         * @param series  the series index (in the range <code>0</code> to 
122         *     <code>getSeriesCount() - 1</code>).
123         *
124         * @return The key for a series.
125         * 
126         * @throws IllegalArgumentException if <code>series</code> is not in the
127         *     specified range.
128         */
129        public Comparable getSeriesKey(int series) {
130            // defer argument checking
131            return getSeries(series).getKey();
132        }
133    
134        /**
135         * Returns the number of items in the specified series.
136         *
137         * @param series  the series (zero-based index).
138         *
139         * @return The item count.
140         * 
141         * @throws IllegalArgumentException if <code>series</code> is not in the
142         *     range <code>0</code> to <code>getSeriesCount() - 1</code>.
143         */
144        public int getItemCount(int series) {
145            // defer argument checking
146            return getSeries(series).getItemCount();
147        }
148    
149        /**
150         * Returns the x-value for a time period.
151         *
152         * @param period  the time period (<code>null</code> not permitted).
153         *
154         * @return The x-value.
155         */
156        protected synchronized long getX(RegularTimePeriod period) {
157            long result = 0L;
158            if (this.xPosition == TimePeriodAnchor.START) {
159                result = period.getFirstMillisecond();
160            }
161            else if (this.xPosition == TimePeriodAnchor.MIDDLE) {
162                result = period.getMiddleMillisecond();
163            }
164            else if (this.xPosition == TimePeriodAnchor.END) {
165                result = period.getLastMillisecond(); 
166            }
167            return result;
168        }
169    
170        /**
171         * Returns the x-value for an item within a series.
172         *
173         * @param series  the series index.
174         * @param item  the item index.
175         *
176         * @return The x-value.
177         */
178        public double getXValue(int series, int item) {
179            OHLCSeries s = (OHLCSeries) this.data.get(series);
180            OHLCItem di = (OHLCItem) s.getDataItem(item);
181            RegularTimePeriod period = di.getPeriod();
182            return getX(period);
183        }
184    
185        /**
186         * Returns the x-value for an item within a series.
187         *
188         * @param series  the series index.
189         * @param item  the item index.
190         *
191         * @return The x-value.
192         */
193        public Number getX(int series, int item) {
194            return new Double(getXValue(series, item));
195        }
196    
197        /**
198         * Returns the y-value for an item within a series.
199         *
200         * @param series  the series index.
201         * @param item  the item index.
202         *
203         * @return The y-value.
204         */
205        public Number getY(int series, int item) {
206            OHLCSeries s = (OHLCSeries) this.data.get(series);
207            OHLCItem di = (OHLCItem) s.getDataItem(item);
208            return new Double(di.getYValue());
209        }
210    
211        /**
212         * Returns the open-value for an item within a series.
213         *
214         * @param series  the series index.
215         * @param item  the item index.
216         *
217         * @return The open-value.
218         */
219        public double getOpenValue(int series, int item) {
220            OHLCSeries s = (OHLCSeries) this.data.get(series);
221            OHLCItem di = (OHLCItem) s.getDataItem(item);
222            return di.getOpenValue();
223        }
224        
225        /**
226         * Returns the open-value for an item within a series.
227         *
228         * @param series  the series index.
229         * @param item  the item index.
230         *
231         * @return The open-value.
232         */
233        public Number getOpen(int series, int item) {
234            return new Double(getOpenValue(series, item));
235        }
236        
237        /**
238         * Returns the close-value for an item within a series.
239         *
240         * @param series  the series index.
241         * @param item  the item index.
242         *
243         * @return The close-value.
244         */
245        public double getCloseValue(int series, int item) {
246            OHLCSeries s = (OHLCSeries) this.data.get(series);
247            OHLCItem di = (OHLCItem) s.getDataItem(item);
248            return di.getCloseValue();
249        }
250        
251        /**
252         * Returns the close-value for an item within a series.
253         *
254         * @param series  the series index.
255         * @param item  the item index.
256         *
257         * @return The close-value.
258         */
259        public Number getClose(int series, int item) {
260            return new Double(getCloseValue(series, item));
261        }
262        
263        /**
264         * Returns the high-value for an item within a series.
265         *
266         * @param series  the series index.
267         * @param item  the item index.
268         *
269         * @return The high-value.
270         */
271        public double getHighValue(int series, int item) {
272            OHLCSeries s = (OHLCSeries) this.data.get(series);
273            OHLCItem di = (OHLCItem) s.getDataItem(item);
274            return di.getHighValue();
275        }
276        
277        /**
278         * Returns the high-value for an item within a series.
279         *
280         * @param series  the series index.
281         * @param item  the item index.
282         *
283         * @return The high-value.
284         */
285        public Number getHigh(int series, int item) {
286            return new Double(getHighValue(series, item));
287        }
288        
289        /**
290         * Returns the low-value for an item within a series.
291         *
292         * @param series  the series index.
293         * @param item  the item index.
294         *
295         * @return The low-value.
296         */
297        public double getLowValue(int series, int item) {
298            OHLCSeries s = (OHLCSeries) this.data.get(series);
299            OHLCItem di = (OHLCItem) s.getDataItem(item);
300            return di.getLowValue();
301        }
302        
303        /**
304         * Returns the low-value for an item within a series.
305         *
306         * @param series  the series index.
307         * @param item  the item index.
308         *
309         * @return The low-value.
310         */
311        public Number getLow(int series, int item) {
312            return new Double(getLowValue(series, item));
313        }
314        
315        public Number getVolume(int series, int item) {
316            return null;
317        }
318        
319        public double getVolumeValue(int series, int item) {
320            return Double.NaN;
321        }
322        
323        /**
324         * Tests this instance for equality with an arbitrary object.
325         *
326         * @param obj  the object (<code>null</code> permitted).
327         *
328         * @return A boolean. 
329         */
330        public boolean equals(Object obj) {
331            if (obj == this) {
332                return true;
333            }
334            if (!(obj instanceof OHLCSeriesCollection)) {
335                return false;
336            }
337            OHLCSeriesCollection that = (OHLCSeriesCollection) obj;
338            return ObjectUtilities.equal(this.data, that.data);
339        }
340        
341        /**
342         * Returns a clone of this instance.
343         * 
344         * @return A clone.
345         * 
346         * @throws CloneNotSupportedException if there is a problem.
347         */
348        public Object clone() throws CloneNotSupportedException {
349            OHLCSeriesCollection clone 
350                    = (OHLCSeriesCollection) super.clone();
351            clone.data = (List) ObjectUtilities.deepClone(this.data);
352            return clone;
353        }
354        
355    }