1   package org.opentrafficsim.ahfe;
2   
3   import java.util.ArrayList;
4   import java.util.LinkedHashMap;
5   import java.util.List;
6   
7   import org.djunits.value.vdouble.scalar.Duration;
8   import org.djunits.value.vdouble.scalar.Time;
9   import org.djutils.exceptions.Throw;
10  import org.opentrafficsim.base.Identifiable;
11  import org.opentrafficsim.base.TimeStampedObject;
12  import org.opentrafficsim.base.Type;
13  import org.opentrafficsim.base.parameters.ParameterException;
14  import org.opentrafficsim.base.parameters.ParameterTypeDuration;
15  import org.opentrafficsim.base.parameters.Parameters;
16  import org.opentrafficsim.core.gtu.GTUException;
17  import org.opentrafficsim.core.gtu.perception.PerceptionException;
18  import org.opentrafficsim.core.network.LateralDirectionality;
19  import org.opentrafficsim.road.gtu.lane.perception.LanePerception;
20  import org.opentrafficsim.road.gtu.lane.perception.RelativeLane;
21  import org.opentrafficsim.road.gtu.lane.perception.categories.LaneBasedAbstractPerceptionCategory;
22  import org.opentrafficsim.road.gtu.lane.perception.categories.LaneBasedPerceptionCategory;
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  @Deprecated
36  public abstract class AbstractDelayedPerceptionCategory extends LaneBasedAbstractPerceptionCategory
37          implements LaneBasedPerceptionCategory
38  {
39  
40      
41      private static final Duration MARGIN = Duration.instantiateSI(0.001);
42  
43      
44      private static final long serialVersionUID = 20170217L;
45  
46      
47  
48  
49      public AbstractDelayedPerceptionCategory(final LanePerception perception)
50      {
51          super(perception);
52      }
53  
54      
55      private final LinkedHashMap<DelayedInfoType<?>, LinkedHashMap<RelativeLane, List<TimeStampedObject<?>>>> map =
56              new LinkedHashMap<>();
57  
58      
59  
60  
61  
62  
63  
64      public final <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final TimeStampedObject<T> info)
65      {
66          setInfo(delayedInfoType, null, info);
67      }
68  
69      
70  
71  
72  
73  
74  
75  
76      public final <T> void setInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane,
77              final TimeStampedObject<T> info)
78      {
79          Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
80          Throw.whenNull(info, "Info may not be null.");
81          if (!this.map.containsKey(delayedInfoType))
82          {
83              this.map.put(delayedInfoType, new LinkedHashMap<>());
84          }
85          if (!this.map.get(delayedInfoType).containsKey(lane))
86          {
87              this.map.get(delayedInfoType).put(lane, new ArrayList<TimeStampedObject<?>>());
88          }
89          List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
90          if (!list.isEmpty())
91          {
92              Throw.when(!list.isEmpty() && info.getTimestamp().le(list.get(list.size() - 1).getTimestamp()),
93                      RuntimeException.class,
94                      "Setting delayed info for type %s with timestamp %s while info with timestamp %s is already present.",
95                      delayedInfoType, info.getTimestamp(), list.get(list.size() - 1).getTimestamp());
96          }
97  
98          
99          list.add(info);
100     }
101 
102     
103 
104 
105 
106 
107 
108 
109 
110     public final <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType) throws PerceptionException
111     {
112         return getInfo(delayedInfoType, null);
113     }
114 
115     
116 
117 
118 
119 
120 
121 
122 
123 
124     @SuppressWarnings("unchecked")
125     public final <T> TimeStampedObject<T> getInfo(final DelayedInfoType<T> delayedInfoType, final RelativeLane lane)
126             throws PerceptionException
127     {
128         Throw.whenNull(delayedInfoType, "Delayed info type may not be null.");
129         Throw.when(!this.map.containsKey(delayedInfoType), PerceptionException.class,
130                 "Perception does not contain any data for info type %s.", delayedInfoType);
131         Throw.when(!this.map.get(delayedInfoType).containsKey(lane), PerceptionException.class,
132                 "Perception does not contain any data for info type %s for lane %s.", delayedInfoType, lane);
133         List<TimeStampedObject<?>> list = this.map.get(delayedInfoType).get(lane);
134         Throw.when(list.isEmpty(), RuntimeException.class, "Perception does not contain any data for info type %s.",
135                 delayedInfoType);
136 
137         
138         Parameters params;
139         Time now;
140         try
141         {
142             params = getPerception().getGtu().getParameters();
143             now = getPerception().getGtu().getSimulator().getSimulatorTime();
144         }
145         catch (GTUException exception)
146         {
147             throw new RuntimeException("GTU not yet initialized.", exception);
148         }
149         Time delayedTime;
150         try
151         {
152             delayedTime = now.minus(params.getParameter(delayedInfoType.getDelayParameter())).plus(MARGIN);
153         }
154         catch (ParameterException exception)
155         {
156             throw new RuntimeException("Delay parameter not found.", exception);
157         }
158         while (list.size() > 1 && list.get(1).getTimestamp().le(delayedTime))
159         {
160             list.remove(0);
161         }
162 
163         return (TimeStampedObject<T>) list.get(0);
164     }
165 
166     
167 
168 
169 
170 
171     public final void changeLane(final LateralDirectionality dir)
172     {
173         for (DelayedInfoType<?> delayedInfoType : this.map.keySet())
174         {
175             LinkedHashMap<RelativeLane, List<TimeStampedObject<?>>> newMap = new LinkedHashMap<>();
176             for (RelativeLane lane : this.map.get(delayedInfoType).keySet())
177             {
178                 if (lane != null)
179                 {
180                     newMap.put(dir.isLeft() ? lane.getRight() : lane.getLeft(), this.map.get(delayedInfoType).get(lane));
181                 }
182                 else
183                 {
184                     newMap.put(lane, this.map.get(delayedInfoType).get(lane));
185                 }
186             }
187             this.map.put(delayedInfoType, newMap);
188         }
189     }
190 
191     
192 
193 
194 
195 
196 
197 
198 
199 
200 
201 
202 
203 
204     public static class DelayedInfoType<T> extends Type<DelayedInfoType<T>> implements Identifiable
205     {
206 
207         
208         private final String id;
209 
210         
211         private final ParameterTypeDuration delayParameter;
212 
213         
214 
215 
216 
217 
218         public DelayedInfoType(final String id, final ParameterTypeDuration delayParameter)
219         {
220             this.id = id;
221             this.delayParameter = delayParameter;
222         }
223 
224         
225 
226 
227 
228         @Override
229         public final String getId()
230         {
231             return this.getId();
232         }
233 
234         
235 
236 
237 
238         public final ParameterTypeDuration getDelayParameter()
239         {
240             return this.delayParameter;
241         }
242 
243         
244         @Override
245         public final int hashCode()
246         {
247             final int prime = 31;
248             int result = 1;
249             result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
250             return result;
251         }
252 
253         
254         @Override
255         public final boolean equals(final Object obj)
256         {
257             if (this == obj)
258             {
259                 return true;
260             }
261             if (obj == null)
262             {
263                 return false;
264             }
265             if (getClass() != obj.getClass())
266             {
267                 return false;
268             }
269             DelayedInfoType<?> other = (DelayedInfoType<?>) obj;
270             if (this.id == null)
271             {
272                 if (other.id != null)
273                 {
274                     return false;
275                 }
276             }
277             else if (!this.id.equals(other.id))
278             {
279                 return false;
280             }
281             return true;
282         }
283 
284     }
285 
286 }