1   package org.opentrafficsim.road.gtu.lane.perception;
2   
3   import java.util.HashMap;
4   import java.util.Iterator;
5   import java.util.Map;
6   import java.util.NoSuchElementException;
7   import java.util.SortedMap;
8   import java.util.TreeMap;
9   
10  import org.djunits.value.vdouble.scalar.Length;
11  import org.opentrafficsim.base.parameters.ParameterException;
12  import org.opentrafficsim.core.gtu.GTUException;
13  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
14  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  public class MultiLanePerceptionIterable<H extends Headway, U> extends AbstractPerceptionReiterable<H, U>
30  {
31  
32      
33      private final Map<RelativeLane, Iterator<PrimaryIteratorEntry>> iterators = new HashMap<>();
34  
35      
36      private final Map<U, RelativeLane> laneMap = new HashMap<>();
37  
38      
39      private final Map<RelativeLane, AbstractPerceptionReiterable<H, U>> iterables = new HashMap<>();
40  
41      
42  
43  
44  
45      public MultiLanePerceptionIterable(final LaneBasedGTU perceivingGtu)
46      {
47          super(perceivingGtu);
48      }
49  
50      
51  
52  
53  
54  
55      public void addIterable(final RelativeLane lane, final AbstractPerceptionReiterable<H, U> iterable)
56      {
57          this.iterators.put(lane, iterable.getPrimaryIterator());
58          this.iterables.put(lane, iterable);
59      }
60  
61      
62      @Override
63      public Iterator<PrimaryIteratorEntry> primaryIterator()
64      {
65          return new MultiLaneIterator();
66      }
67  
68      
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80      private class MultiLaneIterator implements Iterator<PrimaryIteratorEntry>
81      {
82  
83          
84          private SortedMap<PrimaryIteratorEntry, RelativeLane> elements;
85  
86          
87          MultiLaneIterator()
88          {
89              
90          }
91  
92          
93          @Override
94          public boolean hasNext()
95          {
96              assureNext();
97              return !this.elements.isEmpty();
98          }
99  
100         
101         @SuppressWarnings("synthetic-access")
102         @Override
103         public PrimaryIteratorEntry next()
104         {
105             assureNext();
106             if (this.elements.isEmpty())
107             {
108                 throw new NoSuchElementException();
109             }
110 
111             
112             PrimaryIteratorEntry next = this.elements.firstKey();
113             RelativeLane lane = this.elements.get(next);
114             this.elements.remove(next);
115 
116             
117             Iterator<PrimaryIteratorEntry> laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane);
118             if (laneIterator != null)
119             {
120                 if (laneIterator.hasNext())
121                 {
122                     this.elements.put(laneIterator.next(), lane);
123                 }
124                 else
125                 {
126                     
127                     MultiLanePerceptionIterable.this.iterators.remove(lane);
128                 }
129             }
130 
131             MultiLanePerceptionIterable.this.laneMap.put(next.getObject(), lane);
132             return next;
133         }
134 
135         
136 
137 
138         @SuppressWarnings("synthetic-access")
139         public void assureNext()
140         {
141             if (this.elements == null)
142             {
143                 this.elements = new TreeMap<>();
144                 for (RelativeLane lane : MultiLanePerceptionIterable.this.iterators.keySet())
145                 {
146                     Iterator<PrimaryIteratorEntry> laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane);
147                     if (laneIterator.hasNext())
148                     {
149                         this.elements.put(laneIterator.next(), lane);
150                     }
151                 }
152             }
153         }
154 
155     }
156 
157     
158     @Override
159     public H perceive(final LaneBasedGTU perceivingGtu, final U object, final Length distance)
160             throws GTUException, ParameterException
161     {
162         return this.iterables.get(this.laneMap.get(object)).perceive(perceivingGtu, object, distance);
163     }
164 }