1   package org.djutils.event.collection;
2   
3   import java.util.Collection;
4   
5   import org.djutils.event.Event;
6   import org.djutils.event.EventListener;
7   import org.djutils.event.EventType;
8   import org.djutils.event.LocalEventProducer;
9   import org.djutils.event.reference.ReferenceType;
10  import org.djutils.exceptions.Throw;
11  import org.djutils.metadata.MetaData;
12  import org.djutils.metadata.ObjectDescriptor;
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  public class EventProducingCollection<T> extends LocalEventProducer implements EventListener, Collection<T>
31  {
32      
33      public static final EventType OBJECT_ADDED_EVENT =
34              new EventType("OBJECT_ADDED_EVENT", new MetaData("Size of the collection after add", "Size of the collection",
35                      new ObjectDescriptor("Size of the collection after add", "Size of the collection", Integer.class)));
36  
37      
38      public static final EventType OBJECT_REMOVED_EVENT =
39              new EventType("OBJECT_REMOVED_EVENT", new MetaData("Size of the collection after remove", "Size of the collection",
40                      new ObjectDescriptor("Size of the collection after remove", "Size of the collection", Integer.class)));
41  
42      
43      public static final EventType OBJECT_CHANGED_EVENT =
44              new EventType("OBJECT_CHANGED_EVENT", new MetaData("Size of the collection after change", "Size of the collection",
45                      new ObjectDescriptor("Size of the collection after change", "Size of the collection", Integer.class)));
46  
47      
48      private final Collection<T> wrappedCollection;
49  
50      
51  
52  
53  
54      public EventProducingCollection(final Collection<T> wrappedCollection)
55      {
56          Throw.whenNull(wrappedCollection, "wrappedCollection cannot be null");
57          this.wrappedCollection = wrappedCollection;
58      }
59  
60      @Override
61      public int size()
62      {
63          return this.wrappedCollection.size();
64      }
65  
66      @Override
67      public boolean isEmpty()
68      {
69          return this.wrappedCollection.isEmpty();
70      }
71  
72      @Override
73      public void clear()
74      {
75          int nr = this.wrappedCollection.size();
76          this.wrappedCollection.clear();
77          if (nr != this.wrappedCollection.size())
78          {
79              fireEvent(OBJECT_REMOVED_EVENT, this.wrappedCollection.size());
80          }
81      }
82  
83      @Override
84      public boolean add(final T o)
85      {
86          boolean changed = this.wrappedCollection.add(o);
87          if (changed)
88          {
89              fireEvent(OBJECT_ADDED_EVENT, this.wrappedCollection.size());
90          }
91          else
92          {
93              fireEvent(OBJECT_CHANGED_EVENT, this.wrappedCollection.size());
94          }
95          return changed;
96      }
97  
98      @Override
99      public boolean addAll(final Collection<? extends T> c)
100     {
101         boolean changed = this.wrappedCollection.addAll(c);
102         if (changed)
103         {
104             fireEvent(OBJECT_ADDED_EVENT, this.wrappedCollection.size());
105         }
106         else
107         {
108             if (!c.isEmpty())
109             {
110                 fireEvent(OBJECT_CHANGED_EVENT, this.wrappedCollection.size());
111             }
112         }
113         return changed;
114     }
115 
116     @Override
117     public boolean contains(final Object o)
118     {
119         return this.wrappedCollection.contains(o);
120     }
121 
122     @Override
123     public boolean containsAll(final Collection<?> c)
124     {
125         return this.wrappedCollection.containsAll(c);
126     }
127 
128     @Override
129     public EventProducingIterator<T> iterator()
130     {
131         EventProducingIterator<T> iterator = new EventProducingIterator<T>(this.wrappedCollection.iterator());
132         
133         iterator.addListener(this, EventProducingIterator.OBJECT_REMOVED_EVENT, ReferenceType.WEAK);
134         return iterator;
135     }
136 
137     @Override
138     public void notify(final Event event)
139     {
140         
141         if (event.getType().equals(EventProducingIterator.OBJECT_REMOVED_EVENT))
142         {
143             fireEvent(OBJECT_REMOVED_EVENT, this.wrappedCollection.size());
144         }
145     }
146 
147     @Override
148     public boolean remove(final Object o)
149     {
150         boolean changed = this.wrappedCollection.remove(o);
151         if (changed)
152         {
153             fireEvent(OBJECT_REMOVED_EVENT, this.wrappedCollection.size());
154         }
155         return changed;
156     }
157 
158     @Override
159     public boolean removeAll(final Collection<?> c)
160     {
161         boolean changed = this.wrappedCollection.removeAll(c);
162         if (changed)
163         {
164             fireEvent(OBJECT_REMOVED_EVENT, this.wrappedCollection.size());
165         }
166         return changed;
167     }
168 
169     @Override
170     public boolean retainAll(final Collection<?> c)
171     {
172         boolean changed = this.wrappedCollection.retainAll(c);
173         if (changed)
174         {
175             fireEvent(OBJECT_REMOVED_EVENT, this.wrappedCollection.size());
176         }
177         return changed;
178     }
179 
180     @Override
181     public Object[] toArray()
182     {
183         return this.wrappedCollection.toArray();
184     }
185 
186     @Override
187     public <E> E[] toArray(final E[] a)
188     {
189         return this.wrappedCollection.toArray(a);
190     }
191 
192 }