001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2008, 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 * DefaultHighLowDataset.java
029 * --------------------------
030 * (C) Copyright 2002-2008, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * Changes
036 * -------
037 * 21-Mar-2002 : Version 1 (DG);
038 * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
039 * 06-May-2004 : Now extends AbstractXYDataset and added new methods from
040 * HighLowDataset (DG);
041 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
042 * getYValue() (DG);
043 * ------------- JFREECHART 1.0.x ---------------------------------------------
044 * 28-Nov-2006 : Added equals() method override (DG);
045 * 22-Apr-2008 : Implemented PublicCloneable (DG);
046 *
047 */
048
049 package org.jfree.data.xy;
050
051 import java.util.Arrays;
052 import java.util.Date;
053
054 import org.jfree.util.PublicCloneable;
055
056 /**
057 * A simple implementation of the {@link OHLCDataset} interface. See also
058 * the {@link DefaultOHLCDataset} class, which provides another implementation
059 * that is very similar.
060 */
061 public class DefaultHighLowDataset extends AbstractXYDataset
062 implements OHLCDataset, PublicCloneable {
063
064 /** The series key. */
065 private Comparable seriesKey;
066
067 /** Storage for the dates. */
068 private Date[] date;
069
070 /** Storage for the high values. */
071 private Number[] high;
072
073 /** Storage for the low values. */
074 private Number[] low;
075
076 /** Storage for the open values. */
077 private Number[] open;
078
079 /** Storage for the close values. */
080 private Number[] close;
081
082 /** Storage for the volume values. */
083 private Number[] volume;
084
085 /**
086 * Constructs a new high/low/open/close dataset.
087 * <p>
088 * The current implementation allows only one series in the dataset.
089 * This may be extended in a future version.
090 *
091 * @param seriesKey the key for the series (<code>null</code> not
092 * permitted).
093 * @param date the dates (<code>null</code> not permitted).
094 * @param high the high values (<code>null</code> not permitted).
095 * @param low the low values (<code>null</code> not permitted).
096 * @param open the open values (<code>null</code> not permitted).
097 * @param close the close values (<code>null</code> not permitted).
098 * @param volume the volume values (<code>null</code> not permitted).
099 */
100 public DefaultHighLowDataset(Comparable seriesKey, Date[] date,
101 double[] high, double[] low, double[] open, double[] close,
102 double[] volume) {
103
104 if (seriesKey == null) {
105 throw new IllegalArgumentException("Null 'series' argument.");
106 }
107 if (date == null) {
108 throw new IllegalArgumentException("Null 'date' argument.");
109 }
110 this.seriesKey = seriesKey;
111 this.date = date;
112 this.high = createNumberArray(high);
113 this.low = createNumberArray(low);
114 this.open = createNumberArray(open);
115 this.close = createNumberArray(close);
116 this.volume = createNumberArray(volume);
117
118 }
119
120 /**
121 * Returns the key for the series stored in this dataset.
122 *
123 * @param series the index of the series (ignored, this dataset supports
124 * only one series and this method always returns the key for series 0).
125 *
126 * @return The series key (never <code>null</code>).
127 */
128 public Comparable getSeriesKey(int series) {
129 return this.seriesKey;
130 }
131
132 /**
133 * Returns the x-value for one item in a series. The value returned is a
134 * <code>Long</code> instance generated from the underlying
135 * <code>Date</code> object. To avoid generating a new object instance,
136 * you might prefer to call {@link #getXValue(int, int)}.
137 *
138 * @param series the series (zero-based index).
139 * @param item the item (zero-based index).
140 *
141 * @return The x-value.
142 *
143 * @see #getXValue(int, int)
144 * @see #getXDate(int, int)
145 */
146 public Number getX(int series, int item) {
147 return new Long(this.date[item].getTime());
148 }
149
150 /**
151 * Returns the x-value for one item in a series, as a Date.
152 * <p>
153 * This method is provided for convenience only.
154 *
155 * @param series the series (zero-based index).
156 * @param item the item (zero-based index).
157 *
158 * @return The x-value as a Date.
159 *
160 * @see #getX(int, int)
161 */
162 public Date getXDate(int series, int item) {
163 return this.date[item];
164 }
165
166 /**
167 * Returns the y-value for one item in a series.
168 * <p>
169 * This method (from the {@link XYDataset} interface) is mapped to the
170 * {@link #getCloseValue(int, int)} method.
171 *
172 * @param series the series (zero-based index).
173 * @param item the item (zero-based index).
174 *
175 * @return The y-value.
176 *
177 * @see #getYValue(int, int)
178 */
179 public Number getY(int series, int item) {
180 return getClose(series, item);
181 }
182
183 /**
184 * Returns the high-value for one item in a series.
185 *
186 * @param series the series (zero-based index).
187 * @param item the item (zero-based index).
188 *
189 * @return The high-value.
190 *
191 * @see #getHighValue(int, int)
192 */
193 public Number getHigh(int series, int item) {
194 return this.high[item];
195 }
196
197 /**
198 * Returns the high-value (as a double primitive) for an item within a
199 * series.
200 *
201 * @param series the series (zero-based index).
202 * @param item the item (zero-based index).
203 *
204 * @return The high-value.
205 *
206 * @see #getHigh(int, int)
207 */
208 public double getHighValue(int series, int item) {
209 double result = Double.NaN;
210 Number high = getHigh(series, item);
211 if (high != null) {
212 result = high.doubleValue();
213 }
214 return result;
215 }
216
217 /**
218 * Returns the low-value for one item in a series.
219 *
220 * @param series the series (zero-based index).
221 * @param item the item (zero-based index).
222 *
223 * @return The low-value.
224 *
225 * @see #getLowValue(int, int)
226 */
227 public Number getLow(int series, int item) {
228 return this.low[item];
229 }
230
231 /**
232 * Returns the low-value (as a double primitive) for an item within a
233 * series.
234 *
235 * @param series the series (zero-based index).
236 * @param item the item (zero-based index).
237 *
238 * @return The low-value.
239 *
240 * @see #getLow(int, int)
241 */
242 public double getLowValue(int series, int item) {
243 double result = Double.NaN;
244 Number low = getLow(series, item);
245 if (low != null) {
246 result = low.doubleValue();
247 }
248 return result;
249 }
250
251 /**
252 * Returns the open-value for one item in a series.
253 *
254 * @param series the series (zero-based index).
255 * @param item the item (zero-based index).
256 *
257 * @return The open-value.
258 *
259 * @see #getOpenValue(int, int)
260 */
261 public Number getOpen(int series, int item) {
262 return this.open[item];
263 }
264
265 /**
266 * Returns the open-value (as a double primitive) for an item within a
267 * series.
268 *
269 * @param series the series (zero-based index).
270 * @param item the item (zero-based index).
271 *
272 * @return The open-value.
273 *
274 * @see #getOpen(int, int)
275 */
276 public double getOpenValue(int series, int item) {
277 double result = Double.NaN;
278 Number open = getOpen(series, item);
279 if (open != null) {
280 result = open.doubleValue();
281 }
282 return result;
283 }
284
285 /**
286 * Returns the close-value for one item in a series.
287 *
288 * @param series the series (zero-based index).
289 * @param item the item (zero-based index).
290 *
291 * @return The close-value.
292 *
293 * @see #getCloseValue(int, int)
294 */
295 public Number getClose(int series, int item) {
296 return this.close[item];
297 }
298
299 /**
300 * Returns the close-value (as a double primitive) for an item within a
301 * series.
302 *
303 * @param series the series (zero-based index).
304 * @param item the item (zero-based index).
305 *
306 * @return The close-value.
307 *
308 * @see #getClose(int, int)
309 */
310 public double getCloseValue(int series, int item) {
311 double result = Double.NaN;
312 Number close = getClose(series, item);
313 if (close != null) {
314 result = close.doubleValue();
315 }
316 return result;
317 }
318
319 /**
320 * Returns the volume-value for one item in a series.
321 *
322 * @param series the series (zero-based index).
323 * @param item the item (zero-based index).
324 *
325 * @return The volume-value.
326 *
327 * @see #getVolumeValue(int, int)
328 */
329 public Number getVolume(int series, int item) {
330 return this.volume[item];
331 }
332
333 /**
334 * Returns the volume-value (as a double primitive) for an item within a
335 * series.
336 *
337 * @param series the series (zero-based index).
338 * @param item the item (zero-based index).
339 *
340 * @return The volume-value.
341 *
342 * @see #getVolume(int, int)
343 */
344 public double getVolumeValue(int series, int item) {
345 double result = Double.NaN;
346 Number volume = getVolume(series, item);
347 if (volume != null) {
348 result = volume.doubleValue();
349 }
350 return result;
351 }
352
353 /**
354 * Returns the number of series in the dataset.
355 * <p>
356 * This implementation only allows one series.
357 *
358 * @return The number of series.
359 */
360 public int getSeriesCount() {
361 return 1;
362 }
363
364 /**
365 * Returns the number of items in the specified series.
366 *
367 * @param series the index (zero-based) of the series.
368 *
369 * @return The number of items in the specified series.
370 */
371 public int getItemCount(int series) {
372 return this.date.length;
373 }
374
375 /**
376 * Tests this dataset for equality with an arbitrary instance.
377 *
378 * @param obj the object (<code>null</code> permitted).
379 *
380 * @return A boolean.
381 */
382 public boolean equals(Object obj) {
383 if (obj == this) {
384 return true;
385 }
386 if (!(obj instanceof DefaultHighLowDataset)) {
387 return false;
388 }
389 DefaultHighLowDataset that = (DefaultHighLowDataset) obj;
390 if (!this.seriesKey.equals(that.seriesKey)) {
391 return false;
392 }
393 if (!Arrays.equals(this.date, that.date)) {
394 return false;
395 }
396 if (!Arrays.equals(this.open, that.open)) {
397 return false;
398 }
399 if (!Arrays.equals(this.high, that.high)) {
400 return false;
401 }
402 if (!Arrays.equals(this.low, that.low)) {
403 return false;
404 }
405 if (!Arrays.equals(this.close, that.close)) {
406 return false;
407 }
408 if (!Arrays.equals(this.volume, that.volume)) {
409 return false;
410 }
411 return true;
412 }
413
414 /**
415 * Constructs an array of Number objects from an array of doubles.
416 *
417 * @param data the double values to convert (<code>null</code> not
418 * permitted).
419 *
420 * @return The data as an array of Number objects.
421 */
422 public static Number[] createNumberArray(double[] data) {
423 Number[] result = new Number[data.length];
424 for (int i = 0; i < data.length; i++) {
425 result[i] = new Double(data[i]);
426 }
427 return result;
428 }
429
430 }