package org.archstudio.xadl.bna.logics.mapping;
import static org.archstudio.sysutils.SystemUtils.castOrNull;
import static org.archstudio.sysutils.SystemUtils.firstOrNull;
import java.awt.geom.Point2D;
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.facets.IHasInternalWorldPoint;
import org.archstudio.bna.facets.IHasStickyShape;
import org.archstudio.bna.facets.IHasWorld;
import org.archstudio.bna.keys.IThingKey;
import org.archstudio.bna.keys.IThingMetakey;
import org.archstudio.bna.keys.ThingMetakey;
import org.archstudio.bna.logics.AbstractThingLogic;
import org.archstudio.bna.logics.events.WorldThingInternalEventsLogic;
import org.archstudio.bna.logics.events.WorldThingInternalEventsLogic.IInternalBNAModelListener;
import org.archstudio.bna.logics.tracking.ThingValueTrackingLogic;
import org.archstudio.bna.things.shapes.MappingThing;
import org.archstudio.bna.utils.BNAUtils;
import org.archstudio.xadl.bna.facets.IHasObjRef;
import org.archstudio.xarchadt.ObjRef;
public class MaintainMappingLogic extends AbstractThingLogic implements IBNAModelListener, IInternalBNAModelListener {
public static final IThingMetakey<String, IThingKey<Point2D>, Object> INTERNAL_THING_KEY = ThingMetakey.create(
".&internalThingID", IHasInternalWorldPoint.INTERNAL_POINT_KEY);
public static final IThingMetakey<String, IThingKey<Point2D>, ObjRef> INTERNAL_OBJREF_KEY = ThingMetakey.create(
".internalObjRef", IHasInternalWorldPoint.INTERNAL_POINT_KEY);
protected final ThingValueTrackingLogic valueLogic;
public MaintainMappingLogic(IBNAWorld world) {
super(world);
this.valueLogic = logics.addThingLogic(ThingValueTrackingLogic.class);
logics.addThingLogic(WorldThingInternalEventsLogic.class);
}
@Override
public void bnaModelChanged(BNAModelEvent evt) {
BNAUtils.checkLock();
switch (evt.getEventType()) {
case THING_ADDED: {
IThing t = evt.getTargetThing();
if (t instanceof MappingThing) {
updateThing((MappingThing) t);
}
}
break;
case THING_CHANGED: {
IThing t = evt.getTargetThing();
if (t instanceof MappingThing) {
if (evt.getThingEvent().getPropertyName().equals(INTERNAL_THING_KEY)
|| evt.getThingEvent().getPropertyName().equals(INTERNAL_OBJREF_KEY)
|| evt.getThingEvent().getPropertyName().equals(IHasInternalWorldPoint.INTERNAL_WORLD_KEY)) {
updateThing((MappingThing) t);
}
}
break;
}
default:
// do nothing
}
}
@Override
public void internalBNAModelChanged(IHasWorld src, BNAModelEvent evt) {
BNAUtils.checkLock();
switch (evt.getEventType()) {
case THING_ADDED: {
IThing t = evt.getTargetThing();
updateObjRef(src, t.getID(), null, t.get(IHasObjRef.OBJREF_KEY));
updateEndpoint(src, t);
}
break;
case THING_CHANGED: {
ThingEvent tevt = evt.getThingEvent();
IThing t = evt.getTargetThing();
if (evt.getThingEvent().getPropertyName().equals(IHasObjRef.OBJREF_KEY)) {
updateObjRef(src, t.getID(), (ObjRef) tevt.getOldPropertyValue(), (ObjRef) tevt.getNewPropertyValue());
}
updateEndpoint(src, t);
}
break;
case THING_REMOVED: {
IThing t = evt.getTargetThing();
updateObjRef(src, t.getID(), t.get(IHasObjRef.OBJREF_KEY), null);
}
break;
default:
// do nothing
}
}
private void updateThing(MappingThing t) {
IHasWorld worldThing = t.getInternalWorld(model);
if (worldThing != null) {
IBNAWorld iWorld = worldThing.getWorld();
if (iWorld != null) {
ObjRef objRef = t.get(INTERNAL_OBJREF_KEY);
if (objRef != null) {
ThingValueTrackingLogic iValueLogic = iWorld.getThingLogicManager().addThingLogic(
ThingValueTrackingLogic.class);
IHasStickyShape iThing = castOrNull(
firstOrNull(iValueLogic.getThings(IHasObjRef.OBJREF_KEY, objRef)), IHasStickyShape.class);
if (iThing != null) {
t.set(INTERNAL_THING_KEY, iThing.getID());
t.setInternalPoint(BNAUtils.getCentralPoint(iThing));
}
}
}
}
}
protected void updateObjRef(IHasWorld worldThing, Object innerThingId, ObjRef oldObjRef, ObjRef newObjRef) {
if (oldObjRef != null) {
for (IThing t : valueLogic.getThings(INTERNAL_OBJREF_KEY, oldObjRef,
IHasInternalWorldPoint.INTERNAL_WORLD_KEY, worldThing.getID())) {
t.set(INTERNAL_THING_KEY, null);
}
}
if (newObjRef != null) {
for (IThing t : valueLogic.getThings(INTERNAL_OBJREF_KEY, newObjRef,
IHasInternalWorldPoint.INTERNAL_WORLD_KEY, worldThing.getID())) {
t.set(INTERNAL_THING_KEY, innerThingId);
}
}
}
private void updateEndpoint(IHasWorld worldThing, IThing changedThing) {
if (changedThing instanceof IHasStickyShape) {
Point2D endpoint = BNAUtils.getCentralPoint(changedThing);
for (IThing t : valueLogic.getThings(INTERNAL_THING_KEY, changedThing.getID(),
IHasInternalWorldPoint.INTERNAL_WORLD_KEY, worldThing.getID())) {
t.set(IHasInternalWorldPoint.INTERNAL_POINT_KEY, endpoint);
}
}
}
}