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