package org.archstudio.bna.utils;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.archstudio.bna.BNAModelEvent;
import org.archstudio.bna.BNAModelEvent.EventType;
import org.archstudio.bna.IBNAModelListener;
import org.archstudio.bna.IBNAView;
import org.archstudio.bna.IBNAWorld;
import org.archstudio.bna.ICoordinate;
import org.archstudio.bna.ICoordinateMapper;
import org.archstudio.bna.IThing;
import org.archstudio.bna.IThingPeer;
import org.archstudio.bna.facets.IHasBackground;
import org.archstudio.bna.facets.peers.IHasInnerViewPeer;
import org.archstudio.bna.ui.IBNAUI;
import org.archstudio.sysutils.FastMap;
import org.archstudio.sysutils.SystemUtils;
import org.eclipse.jdt.annotation.Nullable;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
public class DefaultBNAView implements IBNAView, IBNAModelListener {
public boolean PROFILE = false;
protected static final LoadingCache<Object, AtomicLong> profileStats = CacheBuilder.newBuilder().weakKeys()
.build(new CacheLoader<Object, AtomicLong>() {
@Override
public AtomicLong load(Object input) {
return new AtomicLong();
}
});
protected final IBNAView parentView;
protected final IBNAWorld world;
protected final FastMap<IThing, IThingPeer<?>> peers = new FastMap<>(true);
protected final ICoordinateMapper cm;
protected IBNAUI bnaUI;
public DefaultBNAView(@Nullable IBNAView parentView, IBNAWorld bnaWorld, ICoordinateMapper cm) {
super();
this.parentView = parentView;
this.world = checkNotNull(bnaWorld);
this.cm = checkNotNull(cm);
world.getBNAModel().addBNAModelListener(this);
}
@Override
public void dispose() {
BNAUtils.checkLock();
world.getBNAModel().removeBNAModelListener(this);
disposePeers();
if (PROFILE) {
for (java.util.Map.Entry<Object, AtomicLong> entry : SystemUtils.sortedByValue(profileStats.asMap()
.entrySet())) {
System.err.println(entry.getValue() + "\t" + entry.getKey());
}
}
}
@Override
public void disposePeers() {
BNAUtils.checkLock();
for (Map.Entry<IThing, IThingPeer<?>> entry : peers.entrySet()) {
try {
entry.getValue().dispose();
}
catch (Exception e) {
e.printStackTrace();
}
}
peers.clear();
}
@Override
public IBNAView getParentView() {
BNAUtils.checkLock();
return parentView;
}
@Override
public IBNAUI getBNAUI() {
BNAUtils.checkLock();
return bnaUI;
}
@Override
public void setBNAUI(IBNAUI bnaUI) {
BNAUtils.checkLock();
if (!SystemUtils.nullEquals(this.bnaUI, bnaUI)) {
this.bnaUI = bnaUI;
for (IThing t : getBNAWorld().getBNAModel().getAllThings()) {
IThingPeer<?> tp = getThingPeer(t);
if (tp instanceof IHasInnerViewPeer) {
IBNAView innerView = ((IHasInnerViewPeer<?>) tp).getInnerView();
if (innerView != null) {
innerView.setBNAUI(bnaUI);
}
}
}
}
}
@Override
public IBNAWorld getBNAWorld() {
BNAUtils.checkLock();
return world;
}
@Override
public ICoordinateMapper getCoordinateMapper() {
BNAUtils.checkLock();
return cm;
}
@Override
public List<IThing> getThingsAt(ICoordinate location) {
BNAUtils.checkLock();
location = DefaultCoordinate.forWorld(location.getWorldPoint(), cm);
List<IThing> things = Lists.newArrayList();
for (IThing t : Lists.reverse(getBNAWorld().getBNAModel().getAllThings())) {
if (t.has(IHasBackground.BACKGROUND_KEY, Boolean.TRUE)) {
continue;
}
try {
IThingPeer<?> tp = getThingPeer(t);
long time = System.nanoTime();
boolean isInThing = tp.isInThing(location);
if (PROFILE) {
time = System.nanoTime() - time;
profileStats.get(tp.getClass()).addAndGet(time);
}
if (isInThing) {
things.add(t);
}
}
catch (Throwable th) {
}
}
return things;
}
@Override
@SuppressWarnings("unchecked")
public <T extends IThing> IThingPeer<T> getThingPeer(T thing) {
BNAUtils.checkLock();
Map.Entry<IThing, IThingPeer<?>> peerEntry = peers.createEntry(thing);
if (peerEntry.getValue() == null) {
peerEntry.setValue(thing.createPeer(this, cm));
}
return (IThingPeer<T>) peerEntry.getValue();
}
@Override
public void bnaModelChanged(BNAModelEvent evt) {
BNAUtils.checkLock();
if (evt.getEventType() == EventType.THING_REMOVED) {
IThingPeer<?> peer = peers.remove(evt.getTargetThing());
if (peer != null) {
peer.dispose();
}
}
}
}