KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > data > time > TimeSeries


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------------
27  * TimeSeries.java
28  * ---------------
29  * (C) Copyright 2001-2003, by Object Refinery Limited.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): Bryan Scott;
33  *
34  * $Id: TimeSeries.java,v 1.10 2005/05/20 08:20:04 mungady Exp $
35  *
36  * Changes
37  * -------
38  * 11-Oct-2001 : Version 1 (DG);
39  * 14-Nov-2001 : Added listener mechanism (DG);
40  * 15-Nov-2001 : Updated argument checking and exceptions in add() method (DG);
41  * 29-Nov-2001 : Added properties to describe the domain and range (DG);
42  * 07-Dec-2001 : Renamed TimeSeries --> BasicTimeSeries (DG);
43  * 01-Mar-2002 : Updated import statements (DG);
44  * 28-Mar-2002 : Added a method add(TimePeriod, double) (DG);
45  * 27-Aug-2002 : Changed return type of delete method to void (DG);
46  * 04-Oct-2002 : Added itemCount and historyCount attributes, fixed errors
47  * reported by Checkstyle (DG);
48  * 29-Oct-2002 : Added series change notification to addOrUpdate() method (DG);
49  * 28-Jan-2003 : Changed name back to TimeSeries (DG);
50  * 13-Mar-2003 : Moved to com.jrefinery.data.time package and implemented
51  * Serializable (DG);
52  * 01-May-2003 : Updated equals() method (see bug report 727575) (DG);
53  * 14-Aug-2003 : Added ageHistoryCountItems method (copied existing code for
54  * contents) made a method and added to addOrUpdate. Made a
55  * public method to enable ageing against a specified time
56  * (eg now) as opposed to lastest time in series (BS);
57  * 15-Oct-2003 : Added fix for setItemCount method - see bug report 804425.
58  * Modified exception message in add() method to be more
59  * informative (DG);
60  * 13-Apr-2004 : Added clear() method (DG);
61  * 21-May-2004 : Added an extra addOrUpdate() method (DG);
62  * 15-Jun-2004 : Fixed NullPointerException in equals() method (DG);
63  * 29-Nov-2004 : Fixed bug 1075255 (DG);
64  *
65  */

66
67 package org.jfree.data.time;
68
69 import java.io.Serializable JavaDoc;
70 import java.util.Collection JavaDoc;
71 import java.util.Collections JavaDoc;
72 import java.util.List JavaDoc;
73
74 import org.jfree.data.general.Series;
75 import org.jfree.data.general.SeriesException;
76 import org.jfree.util.ObjectUtilities;
77
78 /**
79  * Represents a sequence of zero or more data items in the form (period, value).
80  */

81 public class TimeSeries extends Series implements Cloneable JavaDoc, Serializable JavaDoc {
82
83     /** For serialization. */
84     private static final long serialVersionUID = -5032960206869675528L;
85     
86     /** Default value for the domain description. */
87     protected static final String JavaDoc DEFAULT_DOMAIN_DESCRIPTION = "Time";
88
89     /** Default value for the range description. */
90     protected static final String JavaDoc DEFAULT_RANGE_DESCRIPTION = "Value";
91
92     /** A description of the domain. */
93     private String JavaDoc domain;
94
95     /** A description of the range. */
96     private String JavaDoc range;
97
98     /** The type of period for the data. */
99     protected Class JavaDoc timePeriodClass;
100
101     /** The list of data items in the series. */
102     protected List JavaDoc data;
103
104     /** The maximum number of items for the series. */
105     private int maximumItemCount;
106
107     /** The history count. */
108     private int historyCount;
109     
110     /**
111      * Creates a new (empty) time series. By default, a daily time series is
112      * created. Use one of the other constructors if you require a different
113      * time period.
114      *
115      * @param name the series name (<code>null</code> not permitted).
116      */

117     public TimeSeries(String JavaDoc name) {
118         this(
119             name, DEFAULT_DOMAIN_DESCRIPTION, DEFAULT_RANGE_DESCRIPTION,
120             Day.class
121         );
122     }
123
124     /**
125      * Creates a new (empty) time series.
126      *
127      * @param name the series name (<code>null</code> not permitted).
128      * @param timePeriodClass the type of time period (<code>null</code> not
129      * permitted).
130      */

131     public TimeSeries(String JavaDoc name, Class JavaDoc timePeriodClass) {
132         this(
133             name, DEFAULT_DOMAIN_DESCRIPTION, DEFAULT_RANGE_DESCRIPTION,
134             timePeriodClass
135         );
136     }
137
138     /**
139      * Creates a new time series that contains no data.
140      * <P>
141      * Descriptions can be specified for the domain and range. One situation
142      * where this is helpful is when generating a chart for the time series -
143      * axis labels can be taken from the domain and range description.
144      *
145      * @param name the name of the series (<code>null</code> not permitted).
146      * @param domain the domain description (<code>null</code> permitted).
147      * @param range the range description (<code>null</code> permitted).
148      * @param timePeriodClass the type of time period (<code>null</code> not
149      * permitted).
150      */

151     public TimeSeries(String JavaDoc name, String JavaDoc domain, String JavaDoc range,
152                       Class JavaDoc timePeriodClass) {
153
154         super(name);
155         this.domain = domain;
156         this.range = range;
157         this.timePeriodClass = timePeriodClass;
158         this.data = new java.util.ArrayList JavaDoc();
159         this.maximumItemCount = Integer.MAX_VALUE;
160         this.historyCount = 0;
161
162     }
163
164     /**
165      * Returns the domain description.
166      *
167      * @return The domain description (possibly <code>null</code>).
168      */

169     public String JavaDoc getDomainDescription() {
170         return this.domain;
171     }
172
173     /**
174      * Sets the domain description.
175      * <P>
176      * A property change event is fired, and an undoable edit is posted.
177      *
178      * @param description the description (<code>null</code> permitted).
179      */

180     public void setDomainDescription(String JavaDoc description) {
181         String JavaDoc old = this.domain;
182         this.domain = description;
183         firePropertyChange("Domain", old, description);
184     }
185
186     /**
187      * Returns the range description.
188      *
189      * @return The range description (possibly <code>null</code>).
190      */

191     public String JavaDoc getRangeDescription() {
192         return this.range;
193     }
194
195     /**
196      * Sets the range description and fires a property change event for the
197      * 'Range' property.
198      *
199      * @param description the description (<code>null</code> permitted).
200      */

201     public void setRangeDescription(String JavaDoc description) {
202         String JavaDoc old = this.range;
203         this.range = description;
204         firePropertyChange("Range", old, description);
205     }
206
207     /**
208      * Returns the number of items in the series.
209      *
210      * @return The item count.
211      */

212     public int getItemCount() {
213         return this.data.size();
214     }
215
216     /**
217      * Returns the list of data items for the series (the list contains
218      * {@link TimeSeriesDataItem} objects and is unmodifiable).
219      *
220      * @return The list of data items.
221      */

222     public List JavaDoc getItems() {
223         return Collections.unmodifiableList(this.data);
224     }
225
226     /**
227      * Returns the maximum number of items that will be retained in the series.
228      * <P>
229      * The default value is <code>Integer.MAX_VALUE</code>).
230      *
231      * @return The maximum item count.
232      */

233     public int getMaximumItemCount() {
234         return this.maximumItemCount;
235     }
236
237     /**
238      * Sets the maximum number of items that will be retained in the series.
239      * <P>
240      * If you add a new item to the series such that the number of items will
241      * exceed the maximum item count, then the FIRST element in the series is
242      * automatically removed, ensuring that the maximum item count is not
243      * exceeded.
244      *
245      * @param maximum the maximum.
246      */

247     public void setMaximumItemCount(int maximum) {
248         this.maximumItemCount = maximum;
249         while (this.data.size() > this.maximumItemCount) {
250             this.data.remove(0);
251         }
252     }
253
254     /**
255      * Returns the history count for the series.
256      *
257      * @return The history count.
258      */

259     public int getHistoryCount() {
260         return this.historyCount;
261     }
262
263     /**
264      * Sets the number of time units in the 'history' for the series.
265      * <P>
266      * This provides one mechanism for automatically dropping old data from the
267      * time series. For example, if a series contains daily data, you might set
268      * the history count to 30. Then, when you add a new data item, all data
269      * items more than 30 days older than the latest value are automatically
270      * dropped from the series.
271      *
272      * @param periods the number of time periods.
273      */

274     public void setHistoryCount(int periods) {
275         this.historyCount = periods;
276     }
277
278     /**
279      * Returns the time period class for this series.
280      * <p>
281      * Only one time period class can be used within a single series (enforced).
282      * If you add a data item with a {@link Year} for the time period, then all
283      * subsequent data items must also have a {@link Year} for the time period.
284      *
285      * @return The time period class (never <code>null</code>).
286      */

287     public Class JavaDoc getTimePeriodClass() {
288         return this.timePeriodClass;
289     }
290
291     /**
292      * Returns a data item for the series.
293      *
294      * @param index the item index (zero-based).
295      *
296      * @return The data item.
297      */

298     public TimeSeriesDataItem getDataItem(int index) {
299         return (TimeSeriesDataItem) this.data.get(index);
300     }
301
302     /**
303      * Returns the data item for a specific period.
304      *
305      * @param period the period of interest (<code>null</code> not allowed).
306      *
307      * @return The data item matching the specified period (or
308      * <code>null</code> if there is no match).
309      *
310      */

311     public TimeSeriesDataItem getDataItem(RegularTimePeriod period) {
312
313         // check arguments...
314
if (period == null) {
315             throw new IllegalArgumentException JavaDoc("Null 'period' argument");
316         }
317
318         // fetch the value...
319
TimeSeriesDataItem dummy = new TimeSeriesDataItem(
320             period, Integer.MIN_VALUE
321         );
322         int index = Collections.binarySearch(this.data, dummy);
323         if (index >= 0) {
324             return (TimeSeriesDataItem) this.data.get(index);
325         }
326         else {
327             return null;
328         }
329
330     }
331
332     /**
333      * Returns the time period at the specified index.
334      *
335      * @param index the index of the data item.
336      *
337      * @return The time period.
338      */

339     public RegularTimePeriod getTimePeriod(int index) {
340         return getDataItem(index).getPeriod();
341     }
342
343     /**
344      * Returns a time period that would be the next in sequence on the end of
345      * the time series.
346      *
347      * @return The next time period.
348      */

349     public RegularTimePeriod getNextTimePeriod() {
350         RegularTimePeriod last = getTimePeriod(getItemCount() - 1);
351         return last.next();
352     }
353
354     /**
355      * Returns a collection of all the time periods in the time series.
356      *
357      * @return A collection of all the time periods.
358      */

359     public Collection JavaDoc getTimePeriods() {
360         Collection JavaDoc result = new java.util.ArrayList JavaDoc();
361         for (int i = 0; i < getItemCount(); i++) {
362             result.add(getTimePeriod(i));
363         }
364         return result;
365     }
366
367     /**
368      * Returns a collection of time periods in the specified series, but not in
369      * this series, and therefore unique to the specified series.
370      *
371      * @param series the series to check against this one.
372      *
373      * @return The unique time periods.
374      */

375     public Collection JavaDoc getTimePeriodsUniqueToOtherSeries(TimeSeries series) {
376
377         Collection JavaDoc result = new java.util.ArrayList JavaDoc();
378
379         for (int i = 0; i < series.getItemCount(); i++) {
380             RegularTimePeriod period = series.getTimePeriod(i);
381             int index = getIndex(period);
382             if (index < 0) {
383                 result.add(period);
384             }
385
386         }
387
388         return result;
389
390     }
391
392     /**
393      * Returns the index for the item (if any) that corresponds to a time
394      * period.
395      *
396      * @param period the time period (<code>null</code> not permitted).
397      *
398      * @return The index.
399      */

400     public int getIndex(RegularTimePeriod period) {
401
402         // check argument...
403
if (period == null) {
404             throw new IllegalArgumentException JavaDoc("Null 'period' argument.");
405         }
406         
407         // fetch the value...
408
TimeSeriesDataItem dummy = new TimeSeriesDataItem(
409             period, Integer.MIN_VALUE
410         );
411         int index = Collections.binarySearch(this.data, dummy);
412         return index;
413
414     }
415
416     /**
417      * Returns the value at the specified index.
418      *
419      * @param index index of a value.
420      *
421      * @return The value (possibly <code>null</code>).
422      */

423     public Number JavaDoc getValue(int index) {
424         return getDataItem(index).getValue();
425     }
426
427     /**
428      * Returns the value for a time period. If there is no data item with the
429      * specified period, this method will return <code>null</code>.
430      *
431      * @param period time period (<code>null</code> not permitted).
432      *
433      * @return The value (possibly <code>null</code>).
434      */

435     public Number JavaDoc getValue(RegularTimePeriod period) {
436
437         int index = getIndex(period);
438         if (index >= 0) {
439             return getValue(index);
440         }
441         else {
442             return null;
443         }
444
445     }
446
447     /**
448      * Adds a data item to the series and sends a
449      * {@link org.jfree.data.general.SeriesChangeEvent} to all registered
450      * listeners.
451      *
452      * @param item the (timeperiod, value) pair (<code>null</code> not
453      * permitted).
454      */

455     public void add(TimeSeriesDataItem item) {
456         if (item == null) {
457             throw new IllegalArgumentException JavaDoc("Null 'item' argument.");
458         }
459         if (!item.getPeriod().getClass().equals(this.timePeriodClass)) {
460             StringBuffer JavaDoc b = new StringBuffer JavaDoc();
461             b.append("You are trying to add data where the time period class ");
462             b.append("is ");
463             b.append(item.getPeriod().getClass().getName());
464             b.append(", but the TimeSeries is expecting an instance of ");
465             b.append(this.timePeriodClass.getName());
466             b.append(".");
467             throw new SeriesException(b.toString());
468         }
469
470         // make the change (if it's not a duplicate time period)...
471
boolean added = false;
472         int count = getItemCount();
473         if (count == 0) {
474             this.data.add(item);
475             added = true;
476         }
477         else {
478             RegularTimePeriod last = getTimePeriod(getItemCount() - 1);
479             if (item.getPeriod().compareTo(last) > 0) {
480                 this.data.add(item);
481                 added = true;
482             }
483             else {
484                 int index = Collections.binarySearch(this.data, item);
485                 if (index < 0) {
486                     this.data.add(-index - 1, item);
487                     added = true;
488                 }
489                 else {
490                     StringBuffer JavaDoc b = new StringBuffer JavaDoc();
491                     b.append("You are attempting to add an observation for ");
492                     b.append("the time period ");
493                     b.append(item.getPeriod().toString());
494                     b.append(" but the series already contains an observation");
495                     b.append(" for that time period. Duplicates are not ");
496                     b.append("permitted. Try using the addOrUpdate() method.");
497                     throw new SeriesException(b.toString());
498                 }
499             }
500         }
501         if (added) {
502             // check if this addition will exceed the maximum item count...
503
if (getItemCount() > this.maximumItemCount) {
504                 this.data.remove(0);
505             }
506
507             // check if there are any values earlier than specified by the
508
// history count...
509
ageHistoryCountItems();
510             fireSeriesChanged();
511         }
512
513     }
514
515     /**
516      * Adds a new data item to the series and sends
517      * a {@link org.jfree.data.general.SeriesChangeEvent} to all registered
518      * listeners.
519      *
520      * @param period the time period (<code>null</code> not permitted).
521      * @param value the value.
522      */

523     public void add(RegularTimePeriod period, double value) {
524         // defer argument checking...
525
TimeSeriesDataItem item = new TimeSeriesDataItem(period, value);
526         add(item);
527     }
528
529     /**
530      * Adds a new data item to the series and sends
531      * a {@link org.jfree.data.general.SeriesChangeEvent} to all registered
532      * listeners.
533      *
534      * @param period the time period (<code>null</code> not permitted).
535      * @param value the value (<code>null</code> permitted).
536      */

537     public void add(RegularTimePeriod period, Number JavaDoc value) {
538         // defer argument checking...
539
TimeSeriesDataItem item = new TimeSeriesDataItem(period, value);
540         add(item);
541     }
542
543     /**
544      * Updates (changes) the value for a time period. Throws a
545      * {@link SeriesException} if the period does not exist.
546      *
547      * @param period the period (<code>null</code> not permitted).
548      * @param value the value (<code>null</code> permitted).
549      */

550     public void update(RegularTimePeriod period, Number JavaDoc value) {
551         TimeSeriesDataItem temp = new TimeSeriesDataItem(period, value);
552         int index = Collections.binarySearch(this.data, temp);
553         if (index >= 0) {
554             TimeSeriesDataItem pair = (TimeSeriesDataItem) this.data.get(index);
555             pair.setValue(value);
556             fireSeriesChanged();
557         }
558         else {
559             throw new SeriesException(
560                 "TimeSeries.update(TimePeriod, Number): period does not exist."
561             );
562         }
563
564     }
565
566     /**
567      * Updates (changes) the value of a data item.
568      *
569      * @param index the index of the data item.
570      * @param value the new value (<code>null</code> permitted).
571      */

572     public void update(int index, Number JavaDoc value) {
573         TimeSeriesDataItem item = getDataItem(index);
574         item.setValue(value);
575         fireSeriesChanged();
576     }
577
578     /**
579      * Adds or updates data from one series to another. Returns another series
580      * containing the values that were overwritten.
581      *
582      * @param series the series to merge with this.
583      *
584      * @return A series containing the values that were overwritten.
585      */

586     public TimeSeries addAndOrUpdate(TimeSeries series) {
587         TimeSeries overwritten = new TimeSeries(
588             "Overwritten values from: " + getKey(), series.getTimePeriodClass()
589         );
590         for (int i = 0; i < series.getItemCount(); i++) {
591             TimeSeriesDataItem item = series.getDataItem(i);
592             TimeSeriesDataItem oldItem = addOrUpdate(
593                 item.getPeriod(), item.getValue()
594             );
595             if (oldItem != null) {
596                 overwritten.add(oldItem);
597             }
598         }
599         return overwritten;
600     }
601
602     /**
603      * Adds or updates an item in the times series and sends a
604      * {@link org.jfree.data.general.SeriesChangeEvent} to all registered
605      * listeners.
606      *
607      * @param period the time period to add/update (<code>null</code> not
608      * permitted).
609      * @param value the new value.
610      *
611      * @return A copy of the overwritten data item, or <code>null</code> if no
612      * item was overwritten.
613      */

614     public TimeSeriesDataItem addOrUpdate(RegularTimePeriod period,
615                                           double value) {
616         return this.addOrUpdate(period, new Double JavaDoc(value));
617     }
618     
619     /**
620      * Adds or updates an item in the times series and sends a
621      * {@link org.jfree.data.general.SeriesChangeEvent} to all registered
622      * listeners.
623      *
624      * @param period the time period to add/update (<code>null</code> not
625      * permitted).
626      * @param value the new value (<code>null</code> permitted).
627      *
628      * @return A copy of the overwritten data item, or <code>null</code> if no
629      * item was overwritten.
630      */

631     public TimeSeriesDataItem addOrUpdate(RegularTimePeriod period,
632                                           Number JavaDoc value) {
633
634         if (period == null) {
635             throw new IllegalArgumentException JavaDoc("Null 'period' argument.");
636         }
637         TimeSeriesDataItem overwritten = null;
638
639         TimeSeriesDataItem key = new TimeSeriesDataItem(period, value);
640         int index = Collections.binarySearch(this.data, key);
641         if (index >= 0) {
642             TimeSeriesDataItem existing
643                 = (TimeSeriesDataItem) this.data.get(index);
644             overwritten = (TimeSeriesDataItem) existing.clone();
645             existing.setValue(value);
646             ageHistoryCountItems();
647             fireSeriesChanged();
648         }
649         else {
650             this.data.add(-index - 1, new TimeSeriesDataItem(period, value));
651
652             // check if this addition will exceed the maximum item count...
653
if (getItemCount() > this.maximumItemCount) {
654                 this.data.remove(0);
655             }
656
657             ageHistoryCountItems();
658             fireSeriesChanged();
659         }
660         return overwritten;
661
662     }
663
664     /**
665      * Age items in the series. Ensure that the timespan from the youngest to
666      * the oldest record in the series does not exceed history count. oldest
667      * items will be removed if required.
668      */

669     public void ageHistoryCountItems() {
670         // check if there are any values earlier than specified by the history
671
// count...
672
if ((getItemCount() > 1) && (this.historyCount > 0)) {
673             long latest = getTimePeriod(getItemCount() - 1).getSerialIndex();
674             while ((latest - getTimePeriod(0).getSerialIndex())
675                     >= this.historyCount) {
676                 this.data.remove(0);
677             }
678         }
679     }
680
681     /**
682      * Age items in the series. Ensure that the timespan from the supplied
683      * time to the oldest record in the series does not exceed history count.
684      * oldest items will be removed if required.
685      *
686      * @param latest the time to be compared against when aging data.
687      */

688     public void ageHistoryCountItems(long latest) {
689         // check if there are any values earlier than specified by the history
690
// count...
691
if ((getItemCount() > 1) && (this.historyCount > 0)) {
692             while ((latest - getTimePeriod(0).getSerialIndex())
693                     >= this.historyCount) {
694                 this.data.remove(0);
695             }
696         }
697     }
698
699     /**
700      * Removes all data items from the series and sends
701      * a {@link org.jfree.data.general.SeriesChangeEvent}
702      * to all registered listeners.
703      */

704     public void clear() {
705         if (this.data.size() > 0) {
706             this.data.clear();
707             fireSeriesChanged();
708         }
709     }
710
711     /**
712      * Deletes the data item for the given time period and sends
713      * a {@link org.jfree.data.general.SeriesChangeEvent} to all registered
714      * listeners.
715      *
716      * @param period the period of the item to delete (<code>null</code> not
717      * permitted).
718      */

719     public void delete(RegularTimePeriod period) {
720         int index = getIndex(period);
721         this.data.remove(index);
722         fireSeriesChanged();
723     }
724
725     /**
726      * Deletes data from start until end index (end inclusive).
727      *
728      * @param start the index of the first period to delete.
729      * @param end the index of the last period to delete.
730      */

731     public void delete(int start, int end) {
732         for (int i = 0; i <= (end - start); i++) {
733             this.data.remove(start);
734         }
735         fireSeriesChanged();
736     }
737
738     /**
739      * Returns a clone of the time series.
740      * <P>
741      * Notes:
742      * <ul>
743      * <li>no need to clone the domain and range descriptions, since String
744      * object is immutable;</li>
745      * <li>we pass over to the more general method clone(start, end).</li>
746      * </ul>
747      *
748      * @return A clone of the time series.
749      *
750      * @throws CloneNotSupportedException not thrown by this class, but
751      * subclasses may differ.
752      */

753     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
754         Object JavaDoc clone = createCopy(0, getItemCount() - 1);
755         return clone;
756     }
757
758     /**
759      * Creates a new timeseries by copying a subset of the data in this time
760      * series.
761      *
762      * @param start the index of the first time period to copy.
763      * @param end the index of the last time period to copy.
764      *
765      * @return A series containing a copy of this times series from start until
766      * end.
767      *
768      * @throws CloneNotSupportedException if there is a cloning problem.
769      */

770     public TimeSeries createCopy(int start, int end)
771         throws CloneNotSupportedException JavaDoc {
772
773         TimeSeries copy = (TimeSeries) super.clone();
774
775         copy.data = new java.util.ArrayList JavaDoc();
776         if (this.data.size() > 0) {
777             for (int index = start; index <= end; index++) {
778                 TimeSeriesDataItem item
779                     = (TimeSeriesDataItem) this.data.get(index);
780                 TimeSeriesDataItem clone = (TimeSeriesDataItem) item.clone();
781                 try {
782                     copy.add(clone);
783                 }
784                 catch (SeriesException e) {
785                     System.err.println("Unable to add cloned data item.");
786                 }
787             }
788         }
789
790         return copy;
791
792     }
793
794     /**
795      * Creates a new timeseries by copying a subset of the data in this time
796      * series.
797      *
798      * @param start the first time period to copy.
799      * @param end the last time period to copy.
800      *
801      * @return A time series containing a copy of this time series from start
802      * until end.
803      *
804      * @throws CloneNotSupportedException if there is a cloning problem.
805      */

806     public TimeSeries createCopy(RegularTimePeriod start, RegularTimePeriod end)
807         throws CloneNotSupportedException JavaDoc {
808
809         int startIndex = getIndex(start);
810         if (startIndex < 0) {
811             startIndex = -(startIndex + 1);
812         }
813         int endIndex = getIndex(end);
814         if (endIndex < 0) { // end period is not in original series
815
endIndex = -(endIndex + 1); // this is first item AFTER end period
816
endIndex = endIndex - 1; // so this is last item BEFORE end
817
}
818         
819         TimeSeries result = createCopy(startIndex, endIndex);
820         
821         return result;
822
823     }
824
825     /**
826      * Tests the series for equality with an arbitrary object.
827      *
828      * @param object the object to test against (<code>null</code> permitted).
829      *
830      * @return A boolean.
831      */

832     public boolean equals(Object JavaDoc object) {
833         if (object == this) {
834             return true;
835         }
836         if (!(object instanceof TimeSeries) || !super.equals(object)) {
837             return false;
838         }
839         TimeSeries s = (TimeSeries) object;
840         if (!ObjectUtilities.equal(
841             getDomainDescription(), s.getDomainDescription()
842         )) {
843             return false;
844         }
845
846         if (!ObjectUtilities.equal(
847             getRangeDescription(), s.getRangeDescription()
848         )) {
849             return false;
850         }
851
852         if (!getClass().equals(s.getClass())) {
853             return false;
854         }
855
856         if (getHistoryCount() != s.getHistoryCount()) {
857             return false;
858         }
859
860         if (getMaximumItemCount() != s.getMaximumItemCount()) {
861             return false;
862         }
863
864         int count = getItemCount();
865         if (count != s.getItemCount()) {
866             return false;
867         }
868         for (int i = 0; i < count; i++) {
869             if (!getDataItem(i).equals(s.getDataItem(i))) {
870                 return false;
871             }
872         }
873         return true;
874     }
875
876     /**
877      * Returns a hash code value for the object.
878      *
879      * @return The hashcode
880      */

881     public int hashCode() {
882         int result;
883         result = (this.domain != null ? this.domain.hashCode() : 0);
884         result = 29 * result + (this.range != null ? this.range.hashCode() : 0);
885         result = 29 * result + (this.timePeriodClass != null
886                     ? this.timePeriodClass.hashCode() : 0);
887         result = 29 * result + this.data.hashCode();
888         result = 29 * result + this.maximumItemCount;
889         result = 29 * result + this.historyCount;
890         return result;
891     }
892
893 }
894
Popular Tags