package org.archstudio.bna.logics;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Collection;
import java.util.List;
import org.archstudio.bna.BNAModelEvent;
import org.archstudio.bna.IBNAModelListener;
import org.archstudio.bna.IBNAWorld;
import org.archstudio.bna.IThing;
import org.archstudio.bna.ThingEvent;
import org.archstudio.bna.keys.IThingKey;
import org.archstudio.bna.logics.AbstractCoordinatingThingLogic.Updater;
import org.archstudio.bna.utils.BNAUtils;
import org.archstudio.bna.utils.ThingKeyID;
import org.archstudio.sysutils.FastMap;
import com.google.common.collect.Lists;
public abstract class AbstractCoordinatingThingLogic<T extends Updater> extends AbstractThingLogic implements
IBNAModelListener {
public static abstract class Updater {
List<Object> registeredAs = Lists.newArrayListWithCapacity(2);
List<Object> trackingThings = Lists.newArrayListWithCapacity(2);
List<Object> removeWithThings = Lists.newArrayListWithCapacity(2);
public abstract void update(ThingEvent event);
}
private final FastMap<Object, List<T>> registeredUpdaters = new FastMap<>(false);
private final FastMap<Object, List<T>> updatersTrackingThings = new FastMap<>(true);
private final FastMap<Object, List<T>> updatersToRemoveWithThings = new FastMap<>(true);
public AbstractCoordinatingThingLogic(IBNAWorld world) {
super(world);
}
protected void register(T updater, IThing thing) {
checkNotNull(updater);
checkNotNull(thing);
checkArgument(updater.registeredAs.size() == 0, "Updater already registered");
updater.registeredAs.add(thing);
FastMap.createList(registeredUpdaters, thing.getID()).add(updater);
updater.update(null);
}
protected void register(T updater, IThing thing, IThingKey<?> key) {
checkNotNull(updater);
checkNotNull(thing);
checkNotNull(key);
checkArgument(updater.registeredAs.size() == 0, "Updater already registered");
ThingKeyID<?> thingKeyID = ThingKeyID.create(thing, key);
updater.registeredAs.add(thingKeyID);
FastMap.createList(registeredUpdaters, thingKeyID).add(updater);
updater.update(null);
}
protected Collection<T> getRegisteredUpdater(IThing thing) {
return FastMap.getCollection(registeredUpdaters, thing.getID());
}
protected Collection<T> getRegisteredUpdater(IThing thing, IThingKey<?> key) {
return FastMap.getCollection(registeredUpdaters, ThingKeyID.create(thing, key));
}
protected void unregister(IThing thing) {
checkNotNull(thing);
for (T updater : Lists.newArrayList(FastMap.getCollection(registeredUpdaters, thing.getID()))) {
unregister(updater);
}
}
protected void unregister(IThing thing, IThingKey<?> key) {
checkNotNull(thing);
checkNotNull(key);
for (T updater : Lists.newArrayList(FastMap.getCollection(registeredUpdaters, ThingKeyID.create(thing, key)))) {
unregister(updater);
}
}
protected void unregister(T updater) {
if (updater != null) {
for (Object register : updater.registeredAs) {
FastMap.getCollection(registeredUpdaters, register).remove(updater);
}
updater.registeredAs.clear();
for (Object thingID : updater.trackingThings) {
FastMap.getCollection(updatersTrackingThings, thingID).remove(updater);
}
updater.trackingThings.clear();
for (Object thingID : updater.removeWithThings) {
FastMap.getCollection(updatersToRemoveWithThings, thingID).remove(updater);
}
updater.removeWithThings.clear();
}
}
protected void removeWithThing(T updater, IThing... things) {
checkNotNull(updater);
checkNotNull(things);
checkArgument(updater.registeredAs.size() > 0, "Updater not registered");
for (IThing thing : things) {
checkNotNull(thing);
updater.removeWithThings.add(thing.getID());
FastMap.createList(updatersToRemoveWithThings, thing.getID()).add(updater);
}
}
protected void track(T updater, IThing... things) {
checkNotNull(updater);
checkNotNull(things);
checkArgument(updater.registeredAs.size() > 0, "Updater not registered");
for (IThing thing : things) {
checkNotNull(thing);
updater.trackingThings.add(thing.getID());
FastMap.createList(updatersTrackingThings, thing.getID()).add(updater);
}
}
protected void untrack(T updater, IThing... things) {
checkNotNull(updater);
checkNotNull(things);
checkArgument(updater.registeredAs.size() > 0, "Updater not registered");
for (IThing thing : things) {
checkNotNull(thing);
updater.trackingThings.remove(thing.getID());
FastMap.getCollection(updatersTrackingThings, thing.getID()).remove(updater);
}
}
@Override
public void bnaModelChanged(BNAModelEvent evt) {
BNAUtils.checkLock();
switch (evt.getEventType()) {
case THING_CHANGED:
for (T updater : FastMap.getCollection(updatersTrackingThings, evt.getTargetThing().getID())) {
updater.update(evt.getThingEvent());
}
break;
case THING_REMOVED:
unregister(evt.getTargetThing());
for (T updater : FastMap.removeCollection(updatersToRemoveWithThings, evt.getTargetThing().getID())) {
unregister(updater);
}
break;
default:
// do nothing
}
}
protected Collection<T> getUpdatersTrackingThing(Object thingID) {
return FastMap.getCollection(updatersTrackingThings, thingID);
}
}