package org.archstudio.xadl.bna.logics.hints;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.archstudio.bna.IBNAWorld;
import org.archstudio.bna.IThing;
import org.archstudio.bna.logics.hints.EncodedValue;
import org.archstudio.bna.logics.hints.IEncodedValue;
import org.archstudio.bna.logics.hints.IHintRepository;
import org.archstudio.bna.logics.hints.IHintRepositoryChangeListener;
import org.archstudio.bna.logics.hints.IPropertyCoder;
import org.archstudio.bna.logics.hints.MasterPropertyCoder;
import org.archstudio.bna.logics.hints.PropertyDecodeException;
import org.archstudio.bna.utils.Assemblies;
import org.archstudio.sysutils.SystemUtils;
import org.archstudio.xadl.XadlUtils;
import org.archstudio.xadl.bna.facets.IHasObjRef;
import org.archstudio.xadl3.hints_3_0.Hint;
import org.archstudio.xadl3.hints_3_0.HintsExtension;
import org.archstudio.xadl3.hints_3_0.Hints_3_0Package;
import org.archstudio.xadl3.hints_3_0.Value;
import org.archstudio.xarchadt.IXArchADT;
import org.archstudio.xarchadt.IXArchADTModelListener;
import org.archstudio.xarchadt.ObjRef;
import org.archstudio.xarchadt.XArchADTModelEvent;
import org.archstudio.xarchadt.XArchADTProxy;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.annotation.Nullable;
import com.google.common.collect.Maps;
public class XadlHintRepository implements IHintRepository, IXArchADTModelListener {
private static class HintValueImpl implements HintValue {
private final boolean present;
private final Object value;
public HintValueImpl(boolean present, Object value) {
this.present = present;
this.value = value;
}
@Override
public boolean isPresent() {
return present;
}
@Override
public Object getValue() {
return value;
}
}
private final IXArchADT xarch;
private final IPropertyCoder coder;
public XadlHintRepository(IXArchADT xarch) {
this.xarch = xarch;
this.coder = new MasterPropertyCoder();
}
@Override
public @Nullable
Object getContextForThing(IBNAWorld world, IThing thing) {
IThing t = thing;
ObjRef objRef = null;
do {
objRef = t.get(IHasObjRef.OBJREF_KEY);
if (objRef != null) {
break;
}
t = Assemblies.getRootWithPart(world.getBNAModel(), t);
} while (t != null);
if (objRef != null && t != null) {
return objRef;
}
return null;
}
private @Nullable
Hint getHint(HintsExtension hints, String name) {
for (Hint hint : hints.getHint()) {
if (name.equals(hint.getName())) {
return hint;
}
}
return null;
}
private Hint createHint(HintsExtension hints, String name) {
Hint hint = getHint(hints, name);
if (hint == null) {
hint = XArchADTProxy.create(xarch, Hints_3_0Package.Literals.HINT);
hint.setName(name);
hints.getHint().add(hint);
}
return hint;
}
@Override
public boolean storeHint(Object context, String hintName, @Nullable Serializable hintValue) {
HintsExtension hints = XArchADTProxy.proxy(xarch, XadlUtils.createExt(xarch, (ObjRef) context,
Hints_3_0Package.eNS_URI, Hints_3_0Package.Literals.HINTS_EXTENSION.getName()));
return encode(createHint(hints, hintName), hintValue);
}
@Override
public boolean removeHint(Object context, String hintName) {
HintsExtension hints = XArchADTProxy.proxy(xarch, XadlUtils.getExt(xarch, (ObjRef) context,
Hints_3_0Package.eNS_URI, Hints_3_0Package.Literals.HINTS_EXTENSION.getName()));
if (hints != null) {
for (Hint hint : hints.getHint()) {
if (hintName.equals(hint.getName())) {
hints.getHint().remove(hint);
return true;
}
}
}
return false;
}
@Override
public @Nullable
HintValue getHint(Object context, String hintName) throws PropertyDecodeException {
HintsExtension hints = XArchADTProxy.proxy(xarch, XadlUtils.getExt(xarch, (ObjRef) context,
Hints_3_0Package.eNS_URI, Hints_3_0Package.Literals.HINTS_EXTENSION.getName()));
if (hints != null) {
Hint hint = getHint(hints, hintName);
if (hint != null) {
return new HintValueImpl(true, decode(hint));
}
}
return new HintValueImpl(false, null);
}
@Override
public Map<String, HintValue> getHints(Object context) {
HintsExtension hints = XArchADTProxy.proxy(xarch, XadlUtils.getExt(xarch, (ObjRef) context,
Hints_3_0Package.eNS_URI, Hints_3_0Package.Literals.HINTS_EXTENSION.getName()));
Map<String, HintValue> hintValues = Maps.newHashMap();
if (hints != null) {
for (Hint hint : hints.getHint()) {
try {
hintValues.put(hint.getName(), new HintValueImpl(true, decode(hint)));
}
catch (PropertyDecodeException e) {
e.printStackTrace();
}
}
}
return hintValues;
}
private boolean encode(Hint hint, @Nullable Serializable hintValue) {
String newValue = null;
if (hintValue != null) {
IEncodedValue encodedValue = coder.encode(coder, hintValue);
newValue = encodedValue.getType() + ":" + encodedValue.getData();
}
String oldValue = hint.getHint();
if (!SystemUtils.nullEquals(oldValue, newValue)) {
hint.setHint(newValue);
return true;
}
return false;
}
private @Nullable
Serializable decode(@Nullable Hint hint) throws PropertyDecodeException {
if (hint != null) {
String value = hint.getHint();
if (value == null) {
Value deprecatedValue = hint.getValue();
if (deprecatedValue != null) {
value = deprecatedValue.getType() + ":" + deprecatedValue.getData();
hint.setHint(value);
hint.setValue(null);
}
}
if (value != null) {
String[] hintParts = value.split(":", 2);
return (Serializable) coder.decode(coder, new EncodedValue(hintParts[0], hintParts[1]));
}
}
return null;
}
CopyOnWriteArrayList<IHintRepositoryChangeListener> changeListeners = new CopyOnWriteArrayList<IHintRepositoryChangeListener>();
@Override
public void addHintRepositoryChangeListener(IHintRepositoryChangeListener l) {
changeListeners.add(l);
}
@Override
public void removeHintRepositoryChangeListener(IHintRepositoryChangeListener l) {
changeListeners.remove(l);
}
protected void fireHintRepositoryChangeEvent(Object context, String name) {
for (IHintRepositoryChangeListener l : changeListeners) {
l.hintRepositoryChanged(this, context, name);
}
}
@Override
public void handleXArchADTModelEvent(XArchADTModelEvent evt) {
EObject src = XArchADTProxy.proxy(xarch, evt.getSource());
if (src instanceof Hint) {
Hint hint = (Hint) src;
if (hint.eContainer() != null && hint.eContainer().eContainer() != null) {
fireHintRepositoryChangeEvent(XArchADTProxy.unproxy(hint.eContainer().eContainer()), hint.getName());
}
}
}
}