1   package org.djutils.stats.summarizers;
2   
3   import java.util.Calendar;
4   
5   import org.djutils.exceptions.Throw;
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  public class TimestampWeightedTally implements TimestampTallyInterface
20  {
21      
22      private static final long serialVersionUID = 20200228L;
23  
24      
25      private WeightedTally wrappedWeightedTally;
26  
27      
28      private double startTime = Double.NaN;
29  
30      
31      private double elapsedTime = Double.NaN;
32  
33      
34      private double lastTimestamp = Double.NaN;
35  
36      
37      private double lastValue = Double.NaN;
38  
39      
40      private boolean active = false;
41  
42      
43  
44  
45  
46      public TimestampWeightedTally(final String description)
47      {
48          this.wrappedWeightedTally = new WeightedTally(description);
49          initialize();
50      }
51  
52      
53      @Override
54      public void initialize()
55      {
56          synchronized (this.wrappedWeightedTally.semaphore)
57          {
58              this.wrappedWeightedTally.initialize();
59              this.startTime = Double.NaN;
60              this.elapsedTime = 0.0;
61              this.lastTimestamp = Double.NaN;
62              this.lastValue = 0.0;
63              this.active = true;
64          }
65      }
66  
67      
68      @Override
69      public final boolean isActive()
70      {
71          return this.active;
72      }
73  
74      
75      @Override
76      public final void endObservations(final Number timestamp)
77      {
78          ingest(timestamp, this.lastValue);
79          this.active = false;
80      }
81  
82      
83      @Override
84      public void endObservations(final Calendar timestamp)
85      {
86          endObservations(timestamp.getTimeInMillis());
87      }
88  
89      
90  
91  
92  
93      public double getLastValue()
94      {
95          return this.lastValue;
96      }
97  
98      
99  
100 
101 
102 
103 
104     public double ingest(final Calendar timestamp, final double value)
105     {
106         Throw.whenNull(timestamp, "timestamp object may not be null");
107         return ingest(timestamp.getTimeInMillis(), value);
108     }
109 
110     
111 
112 
113 
114 
115 
116     public double ingest(final Number timestamp, final double value)
117     {
118         Throw.whenNull(timestamp, "timestamp object may not be null");
119         Throw.when(Double.isNaN(value), IllegalArgumentException.class, "value may not be NaN");
120         double timestampDouble = timestamp.doubleValue();
121         Throw.when(Double.isNaN(timestampDouble), IllegalArgumentException.class, "timestamp may not be NaN");
122         Throw.when(timestampDouble < (this.elapsedTime + this.startTime), IllegalArgumentException.class,
123                 "times not offered in ascending order. Last time was " + (this.elapsedTime + this.startTime)
124                         + ", new timestamp was " + timestampDouble);
125 
126         synchronized (this.wrappedWeightedTally.semaphore)
127         {
128             
129             if ((Double.isNaN(this.lastTimestamp) || timestampDouble > this.lastTimestamp) && this.active)
130             {
131                 if (Double.isNaN(this.startTime))
132                 {
133                     this.startTime = timestampDouble;
134                     this.elapsedTime = 0.0;
135                 }
136                 else
137                 {
138                     double deltaTime = timestampDouble - this.lastTimestamp;
139                     this.elapsedTime += deltaTime;
140                     this.wrappedWeightedTally.ingest(deltaTime, this.lastValue);
141                 }
142                 this.lastTimestamp = timestampDouble;
143             }
144             this.lastValue = value;
145             return value;
146         }
147     }
148 
149     
150     @Override
151     public final String getDescription()
152     {
153         return this.wrappedWeightedTally.getDescription();
154     }
155 
156     
157     @Override
158     public final long getN()
159     {
160         return this.wrappedWeightedTally.getN();
161     }
162 
163     
164     @Override
165     public final double getMax()
166     {
167         return this.wrappedWeightedTally.getMax();
168     }
169 
170     
171     @Override
172     public final double getMin()
173     {
174         return this.wrappedWeightedTally.getMin();
175     }
176 
177     
178     @Override
179     public final double getWeightedSampleMean()
180     {
181         return this.wrappedWeightedTally.getWeightedSampleMean();
182     }
183 
184     
185     @Override
186     public final double getWeightedSampleStDev()
187     {
188         return this.wrappedWeightedTally.getWeightedSampleStDev();
189     }
190 
191     
192     @Override
193     public final double getWeightedPopulationStDev()
194     {
195         return this.wrappedWeightedTally.getWeightedPopulationStDev();
196     }
197 
198     
199     @Override
200     public final double getWeightedSampleVariance()
201     {
202         return this.wrappedWeightedTally.getWeightedSampleVariance();
203     }
204 
205     
206     @Override
207     public final double getWeightedPopulationVariance()
208     {
209         return this.wrappedWeightedTally.getWeightedPopulationVariance();
210     }
211 
212     
213     @Override
214     public final double getWeightedSum()
215     {
216         return this.wrappedWeightedTally.getWeightedSum();
217     }
218 
219     
220     @Override
221     @SuppressWarnings("checkstyle:designforextension")
222     public String toString()
223     {
224         return this.wrappedWeightedTally.toString();
225     }
226 
227 }