package org.archstudio.bna.utils;
import java.util.Collection;
import java.util.List;
import org.archstudio.bna.BNAModelEvent;
import org.archstudio.bna.BNAModelEvent.EventType;
import org.archstudio.bna.IBNAModel;
import org.archstudio.bna.IBNAModelListener;
import org.archstudio.bna.IThing;
import org.archstudio.bna.IThingListener;
import org.archstudio.bna.ThingEvent;
import org.archstudio.sysutils.Finally;
import org.eclipse.jdt.annotation.Nullable;
import com.google.common.collect.Lists;
public class DefaultBNAModel implements IBNAModel, IThingListener {
private final ThingTree thingTree = new ThingTree();
private final List<IBNAModelListener> listeners = Lists.newCopyOnWriteArrayList();
private int bulkChangeCount = 0;
private boolean firedBulkChange = false;
public DefaultBNAModel() {
}
private void _fire(BNAModelEvent event) {
for (IBNAModelListener l : listeners) {
try {
l.bnaModelChanged(event);
}
catch (Throwable t) {
t.printStackTrace();
}
}
}
private void fire(BNAModelEvent event) {
if (bulkChangeCount > 0 && !firedBulkChange) {
firedBulkChange = true;
_fire(BNAModelEvent.create(DefaultBNAModel.this, EventType.BULK_CHANGE_BEGIN));
}
_fire(event);
}
@Override
public void dispose() {
}
@Override
public void addBNAModelListener(IBNAModelListener l) {
BNAUtils.checkLock();
listeners.add(l);
}
@Override
public void removeBNAModelListener(IBNAModelListener l) {
BNAUtils.checkLock();
listeners.remove(l);
}
@Override
public void fireStreamNotificationEvent(Object streamNotificationEvent) {
BNAUtils.checkLock();
fire(BNAModelEvent.create(this, EventType.STREAM_NOTIFICATION_EVENT, streamNotificationEvent));
}
private final Finally END_BULK_CHANGE = new Finally() {
@Override
public void close() {
BNAUtils.checkLock();
if (--bulkChangeCount == 0) {
if (firedBulkChange) {
firedBulkChange = false;
_fire(BNAModelEvent.create(DefaultBNAModel.this, EventType.BULK_CHANGE_END));
}
}
}
};
@Override
public Finally beginBulkChange() {
BNAUtils.checkLock();
bulkChangeCount++;
return END_BULK_CHANGE;
}
@Override
public void thingChanged(ThingEvent thingEvent) {
BNAUtils.checkLock();
fire(BNAModelEvent.create(this, EventType.THING_CHANGED, thingEvent));
}
@Override
public <T extends IThing> T addThing(T thing) {
return addThing(thing, null);
}
@Override
public <T extends IThing> T addThing(T thing, @Nullable IThing parentThing) {
BNAUtils.checkLock();
thingTree.add(thing, parentThing);
thing.addThingListener(this);
fire(BNAModelEvent.create(this, EventType.THING_ADDED, thing));
return thing;
}
@Override
public <T extends IThing> T insertThing(T thing, IThing beforeThing) {
BNAUtils.checkLock();
thingTree.insert(thing, beforeThing);
thing.addThingListener(this);
fire(BNAModelEvent.create(this, EventType.THING_ADDED, thing));
return thing;
}
@Override
public void removeThing(IThing t) {
BNAUtils.checkLock();
t.removeThingListener(this);
thingTree.remove(t);
fire(BNAModelEvent.create(this, EventType.THING_REMOVED, t));
}
@Override
public void removeThingAndChildren(IThing thing) {
BNAUtils.checkLock();
for (IThing childThing : getChildThings(thing)) {
removeThingAndChildren(childThing);
}
removeThing(thing);
}
@Override
public void bringToFront(IThing thing) {
BNAUtils.checkLock();
thingTree.bringToFront(thing);
fire(BNAModelEvent.create(this, EventType.THING_RESTACKED, thing));
}
@Override
public void sendToBack(IThing thing) {
BNAUtils.checkLock();
thingTree.sendToBack(thing);
fire(BNAModelEvent.create(this, EventType.THING_RESTACKED, thing));
}
@Override
public void moveAfter(IThing thing, IThing afterThing) {
BNAUtils.checkLock();
thingTree.moveAfter(thing, afterThing);
fire(BNAModelEvent.create(this, EventType.THING_RESTACKED, thing));
}
@Override
public void moveBefore(IThing thing, IThing beforeThing) {
BNAUtils.checkLock();
thingTree.moveBefore(thing, beforeThing);
fire(BNAModelEvent.create(this, EventType.THING_RESTACKED, thing));
}
@Override
public void reparent(IThing newParentThing, IThing thing) {
BNAUtils.checkLock();
thingTree.reparent(newParentThing, thing);
fire(BNAModelEvent.create(this, EventType.THING_RESTACKED, thing));
}
@Override
public @Nullable
IThing getThing(@Nullable Object id) {
BNAUtils.checkLock();
return thingTree.getThing(id);
}
@Override
public List<IThing> getThingsByID(Collection<Object> thingIDs) {
BNAUtils.checkLock();
List<IThing> things = Lists.newArrayListWithExpectedSize(thingIDs.size());
for (Object id : thingIDs) {
IThing thing = getThing(id);
if (thing != null) {
things.add(thing);
}
}
return things;
}
@Override
public List<IThing> getAllThings() {
BNAUtils.checkLock();
return thingTree.getAllThings();
}
@Override
public int getNumThings() {
BNAUtils.checkLock();
return thingTree.size();
}
@Override
public IThing getParentThing(IThing thing) {
BNAUtils.checkLock();
return thingTree.getParent(thing);
}
@Override
public List<IThing> getChildThings(IThing thing) {
BNAUtils.checkLock();
return thingTree.getChildThings(thing);
}
@Override
public List<IThing> getAncestorThings(IThing thing) {
BNAUtils.checkLock();
return thingTree.getAncestorThings(thing);
}
@Override
public List<IThing> getDescendantThings(IThing thing) {
BNAUtils.checkLock();
return thingTree.getAllDescendantThings(thing);
}
}