1 66 67 package org.jfree.data.time; 68 69 import java.io.Serializable ; 70 import java.util.Collection ; 71 import java.util.Collections ; 72 import java.util.List ; 73 74 import org.jfree.data.general.Series; 75 import org.jfree.data.general.SeriesException; 76 import org.jfree.util.ObjectUtilities; 77 78 81 public class TimeSeries extends Series implements Cloneable , Serializable { 82 83 84 private static final long serialVersionUID = -5032960206869675528L; 85 86 87 protected static final String DEFAULT_DOMAIN_DESCRIPTION = "Time"; 88 89 90 protected static final String DEFAULT_RANGE_DESCRIPTION = "Value"; 91 92 93 private String domain; 94 95 96 private String range; 97 98 99 protected Class timePeriodClass; 100 101 102 protected List data; 103 104 105 private int maximumItemCount; 106 107 108 private int historyCount; 109 110 117 public TimeSeries(String name) { 118 this( 119 name, DEFAULT_DOMAIN_DESCRIPTION, DEFAULT_RANGE_DESCRIPTION, 120 Day.class 121 ); 122 } 123 124 131 public TimeSeries(String name, Class timePeriodClass) { 132 this( 133 name, DEFAULT_DOMAIN_DESCRIPTION, DEFAULT_RANGE_DESCRIPTION, 134 timePeriodClass 135 ); 136 } 137 138 151 public TimeSeries(String name, String domain, String range, 152 Class timePeriodClass) { 153 154 super(name); 155 this.domain = domain; 156 this.range = range; 157 this.timePeriodClass = timePeriodClass; 158 this.data = new java.util.ArrayList (); 159 this.maximumItemCount = Integer.MAX_VALUE; 160 this.historyCount = 0; 161 162 } 163 164 169 public String getDomainDescription() { 170 return this.domain; 171 } 172 173 180 public void setDomainDescription(String description) { 181 String old = this.domain; 182 this.domain = description; 183 firePropertyChange("Domain", old, description); 184 } 185 186 191 public String getRangeDescription() { 192 return this.range; 193 } 194 195 201 public void setRangeDescription(String description) { 202 String old = this.range; 203 this.range = description; 204 firePropertyChange("Range", old, description); 205 } 206 207 212 public int getItemCount() { 213 return this.data.size(); 214 } 215 216 222 public List getItems() { 223 return Collections.unmodifiableList(this.data); 224 } 225 226 233 public int getMaximumItemCount() { 234 return this.maximumItemCount; 235 } 236 237 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 259 public int getHistoryCount() { 260 return this.historyCount; 261 } 262 263 274 public void setHistoryCount(int periods) { 275 this.historyCount = periods; 276 } 277 278 287 public Class getTimePeriodClass() { 288 return this.timePeriodClass; 289 } 290 291 298 public TimeSeriesDataItem getDataItem(int index) { 299 return (TimeSeriesDataItem) this.data.get(index); 300 } 301 302 311 public TimeSeriesDataItem getDataItem(RegularTimePeriod period) { 312 313 if (period == null) { 315 throw new IllegalArgumentException ("Null 'period' argument"); 316 } 317 318 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 339 public RegularTimePeriod getTimePeriod(int index) { 340 return getDataItem(index).getPeriod(); 341 } 342 343 349 public RegularTimePeriod getNextTimePeriod() { 350 RegularTimePeriod last = getTimePeriod(getItemCount() - 1); 351 return last.next(); 352 } 353 354 359 public Collection getTimePeriods() { 360 Collection result = new java.util.ArrayList (); 361 for (int i = 0; i < getItemCount(); i++) { 362 result.add(getTimePeriod(i)); 363 } 364 return result; 365 } 366 367 375 public Collection getTimePeriodsUniqueToOtherSeries(TimeSeries series) { 376 377 Collection result = new java.util.ArrayList (); 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 400 public int getIndex(RegularTimePeriod period) { 401 402 if (period == null) { 404 throw new IllegalArgumentException ("Null 'period' argument."); 405 } 406 407 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 423 public Number getValue(int index) { 424 return getDataItem(index).getValue(); 425 } 426 427 435 public Number 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 455 public void add(TimeSeriesDataItem item) { 456 if (item == null) { 457 throw new IllegalArgumentException ("Null 'item' argument."); 458 } 459 if (!item.getPeriod().getClass().equals(this.timePeriodClass)) { 460 StringBuffer b = new StringBuffer (); 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 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 b = new StringBuffer (); 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 if (getItemCount() > this.maximumItemCount) { 504 this.data.remove(0); 505 } 506 507 ageHistoryCountItems(); 510 fireSeriesChanged(); 511 } 512 513 } 514 515 523 public void add(RegularTimePeriod period, double value) { 524 TimeSeriesDataItem item = new TimeSeriesDataItem(period, value); 526 add(item); 527 } 528 529 537 public void add(RegularTimePeriod period, Number value) { 538 TimeSeriesDataItem item = new TimeSeriesDataItem(period, value); 540 add(item); 541 } 542 543 550 public void update(RegularTimePeriod period, Number 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 572 public void update(int index, Number value) { 573 TimeSeriesDataItem item = getDataItem(index); 574 item.setValue(value); 575 fireSeriesChanged(); 576 } 577 578 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 614 public TimeSeriesDataItem addOrUpdate(RegularTimePeriod period, 615 double value) { 616 return this.addOrUpdate(period, new Double (value)); 617 } 618 619 631 public TimeSeriesDataItem addOrUpdate(RegularTimePeriod period, 632 Number value) { 633 634 if (period == null) { 635 throw new IllegalArgumentException ("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 if (getItemCount() > this.maximumItemCount) { 654 this.data.remove(0); 655 } 656 657 ageHistoryCountItems(); 658 fireSeriesChanged(); 659 } 660 return overwritten; 661 662 } 663 664 669 public void ageHistoryCountItems() { 670 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 688 public void ageHistoryCountItems(long latest) { 689 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 704 public void clear() { 705 if (this.data.size() > 0) { 706 this.data.clear(); 707 fireSeriesChanged(); 708 } 709 } 710 711 719 public void delete(RegularTimePeriod period) { 720 int index = getIndex(period); 721 this.data.remove(index); 722 fireSeriesChanged(); 723 } 724 725 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 753 public Object clone() throws CloneNotSupportedException { 754 Object clone = createCopy(0, getItemCount() - 1); 755 return clone; 756 } 757 758 770 public TimeSeries createCopy(int start, int end) 771 throws CloneNotSupportedException { 772 773 TimeSeries copy = (TimeSeries) super.clone(); 774 775 copy.data = new java.util.ArrayList (); 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 806 public TimeSeries createCopy(RegularTimePeriod start, RegularTimePeriod end) 807 throws CloneNotSupportedException { 808 809 int startIndex = getIndex(start); 810 if (startIndex < 0) { 811 startIndex = -(startIndex + 1); 812 } 813 int endIndex = getIndex(end); 814 if (endIndex < 0) { endIndex = -(endIndex + 1); endIndex = endIndex - 1; } 818 819 TimeSeries result = createCopy(startIndex, endIndex); 820 821 return result; 822 823 } 824 825 832 public boolean equals(Object 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 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 |