1 /*
2 StatCvs - CVS statistics generation
3 Copyright (C) 2002 Lukasz Pekacki <lukasz@pekacki.de>
4 http://statcvs.sf.net/
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 $RCSfile: TimeLine.java,v $
21 $Date: 2008/04/02 11:52:02 $
22 */
23 package net.sf.statcvs.reportmodel;
24
25 import java.util.ArrayList;
26 import java.util.Date;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.TreeMap;
30
31 /**
32 * Contains time line data for an integer value. The semantics is that at
33 * every data point, the time line's value changed from the previous point's
34 * value to the current point's value. Time points may be specified either
35 * by an absolute value using <tt>addTimePoint</tt>, or by a value relative
36 * to the previous time point using {@link #addChange}. If all points are
37 * specified using <tt>addChange</tt>, an initial value must be given
38 * using {@link #setInitialValue}.
39 *
40 * @author Richard Cyganiak <rcyg@gmx.de>
41 * @version $Id: TimeLine.java,v 1.5 2008/04/02 11:52:02 benoitx Exp $
42 */
43 public class TimeLine {
44 private final TreeMap dataPoints = new TreeMap();
45 private Date minimumDate = null;
46 private int initialValue;
47 private boolean hasInitialValue = false;
48 private final String title;
49 private final String rangeLabel;
50
51 /**
52 * Creates a new time line.
53 * @param title the time line's title
54 * @param rangeLabel a range label (axis label) for the values
55 */
56 public TimeLine(final String title, final String rangeLabel) {
57 this.title = title;
58 this.rangeLabel = rangeLabel;
59 }
60
61 /**
62 * Sets the initial value of the time line, that is the value just before
63 * the first data point.
64 * @param initialValue the time line's initial value
65 */
66 public void setInitialValue(final int initialValue) {
67 this.initialValue = initialValue;
68 this.hasInitialValue = true;
69 }
70
71 /**
72 * Adds a data point to the time line. Data points may be added in any
73 * order.
74 * @param date the data point's date
75 * @param value the data point's value
76 */
77 public void addTimePoint(final Date date, final int value) {
78 addTimePoint(HelperTimePoint.createAbsoluteValueTimePoint(date, value));
79 }
80
81 /**
82 * Specifies that the time line's value changed at a given date. Data
83 * points may be added in any order.
84 * @param date the data point's date
85 * @param delta the value change at this time
86 */
87 public void addChange(final Date date, final int delta) {
88 addTimePoint(HelperTimePoint.createDeltaTimePoint(date, delta));
89 }
90
91 /**
92 * Checks if the time series is empty. A series is considered empty if
93 * it has zero or one time points. It takes two distinct time points
94 * to actually make it a series.
95 * @return <tt>true</tt> if the time series is empty
96 */
97 public boolean isEmpty() {
98 return dataPoints.size() <= 1;
99 }
100
101 /**
102 * Returns a <tt>List</tt> of data points, ordered by date.
103 * @return a <tt>List</tt> of {@link TimePoint}s
104 */
105 public List getDataPoints() {
106 List result;
107 int currentValue;
108 if (hasInitialValue && dataPoints.size() > 0) {
109 result = new ArrayList(dataPoints.size() + 1);
110 final Date beforeMinimum = new Date(minimumDate.getTime() - 1);
111 result.add(new TimePoint(beforeMinimum, initialValue, 0));
112 currentValue = initialValue;
113 } else {
114 result = new ArrayList(dataPoints.size());
115 if (dataPoints.size() == 0) {
116 return result;
117 }
118 final HelperTimePoint firstPoint = (HelperTimePoint) dataPoints.get(dataPoints.firstKey());
119 if (!firstPoint.isAbsolute()) {
120 throw new IllegalStateException("The first data point must be absolute, or setInitialValue must be used");
121 }
122 currentValue = firstPoint.getValue();
123 }
124 final Iterator it = dataPoints.values().iterator();
125 while (it.hasNext()) {
126 final HelperTimePoint point = (HelperTimePoint) it.next();
127 if (point.isAbsolute()) {
128 final int delta = point.getValue() - currentValue;
129 result.add(new TimePoint(point.getDate(), point.getValue(), delta));
130 currentValue = point.getValue();
131 } else {
132 currentValue += point.getValue();
133 result.add(new TimePoint(point.getDate(), currentValue, point.getValue()));
134 }
135 }
136 return result;
137 }
138
139 private void addTimePoint(HelperTimePoint newPoint) {
140 final HelperTimePoint oldPoint = (HelperTimePoint) dataPoints.get(newPoint.getDate());
141 if (oldPoint == null) {
142 if (minimumDate == null || newPoint.getDate().before(minimumDate)) {
143 minimumDate = newPoint.getDate();
144 }
145 //oldPoint = newPoint;
146 } else {
147 newPoint = oldPoint.join(newPoint);
148 }
149 dataPoints.put(newPoint.getDate(), newPoint);
150 }
151
152 /**
153 * Returns the range label (axis label) of the values
154 * @return an axis label for the values
155 */
156 public String getRangeLabel() {
157 return rangeLabel;
158 }
159
160 /**
161 * Returns the title of the time line
162 * @return the title
163 */
164 public String getTitle() {
165 return title;
166 }
167 }