/**
*
*/
package iamrescue.util;
import iamrescue.agent.ISimulationTimer;
import iamrescue.agent.ITimeStepListener;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javolution.util.FastList;
import javolution.util.FastMap;
import javolution.util.FastSet;
import rescuecore2.standard.entities.StandardPropertyURN;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityListener;
import rescuecore2.worldmodel.Property;
/**
* @author Sebastian
*
*/
public class ConsistentPropertyChangeNotifier implements EntityListener,
ITimeStepListener {
private ISimulationTimer timer;
private int currentTime = -1;
private Entity entity;
private boolean waiting = false;
private Map<String, PropertyUpdate> updates = new FastMap<String, PropertyUpdate>();
private Set<String> relevantProperties;
private Set<IConsistentPropertyListener> listeners = new FastSet<IConsistentPropertyListener>();
public ConsistentPropertyChangeNotifier(Entity entity,
Collection<StandardPropertyURN> relevantProperties,
IConsistentPropertyListener listener, ISimulationTimer timer) {
this.entity = entity;
entity.addEntityListener(this);
this.relevantProperties = new FastSet<String>();
this.timer = timer;
for (StandardPropertyURN standardPropertyURN : relevantProperties) {
this.relevantProperties.add(standardPropertyURN.toString());
}
listeners.add(listener);
}
public void removeListener(IConsistentPropertyListener listener) {
listeners.remove(listener);
if (listeners.size() == 0) {
entity.removeEntityListener(this);
}
}
public void addListener(IConsistentPropertyListener listener) {
if (listeners.size() == 0) {
throw new IllegalArgumentException(
"This listener is no longer being notified, "
+ "as all listeners had previously been removed.");
}
listeners.add(listener);
}
@Override
public void propertyChanged(Entity e, Property p, Object oldValue,
Object newValue) {
if (relevantProperties.contains(p.getURN())) {
int time = timer.getTime();
if (time != currentTime) {
updates.clear();
currentTime = time;
}
entity = e;
String urn = p.getURN();
updates.put(urn, new PropertyUpdate(p, oldValue, newValue));
if (updates.size() == relevantProperties.size() && !waiting) {
// Done - wait for end of time step now
timer.addTimeStepListener(this);
waiting = true;
}
}
}
public static class PropertyUpdate {
private Property property;
private Object oldValue;
private Object newValue;
public PropertyUpdate(Property property, Object oldValue,
Object newValue) {
super();
this.property = property;
this.oldValue = oldValue;
this.newValue = newValue;
}
public Property getProperty() {
return property;
}
public Object getOldValue() {
return oldValue;
}
public Object getNewValue() {
return newValue;
}
}
/*
* (non-Javadoc)
*
* @see iamrescue.agent.ITimeStepListener#notifyTimeStepStarted(int)
*/
@Override
public void notifyTimeStepStarted(int timeStep) {
waiting = false;
timer.removeTimeStepListener(this);
if (timeStep == currentTime
&& relevantProperties.size() == updates.size()) {
fireUpdate();
updates.clear();
}
}
/**
*
*/
private void fireUpdate() {
List<IConsistentPropertyListener> copy = new FastList<IConsistentPropertyListener>(
listeners);
for (IConsistentPropertyListener listener : copy) {
PropertyUpdate[] updates = this.updates.values().toArray(
new PropertyUpdate[this.updates.size()]);
listener.allPropertiesChanged(entity, updates);
}
}
}