package com.sap.ide.cts.parser.incremental;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import com.sap.furcas.metamodel.FURCAS.TCS.ContextTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.InjectorAction;
import com.sap.furcas.metamodel.FURCAS.TCS.PrimitivePropertyInit;
import com.sap.furcas.metamodel.FURCAS.textblocks.AbstractToken;
import com.sap.furcas.metamodel.FURCAS.textblocks.LexedToken;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.metamodel.FURCAS.textblocks.Version;
import com.sap.furcas.runtime.common.exceptions.ModelAdapterException;
import com.sap.furcas.runtime.common.interfaces.IModelElementProxy;
import com.sap.furcas.runtime.parser.impl.DelayedReference;
import com.sap.furcas.runtime.parser.impl.ModelElementProxy;
import com.sap.furcas.runtime.parser.impl.ObservableInjectingParser;
import com.sap.furcas.runtime.parser.textblocks.ITextBlocksTokenStream;
import com.sap.furcas.runtime.parser.textblocks.observer.TextBlockProxy;
import com.sap.furcas.runtime.tcs.TcsUtil;
import com.sap.furcas.runtime.textblocks.TbUtil;
import com.sap.furcas.runtime.textblocks.modifcation.TbVersionUtil;
import com.sap.ide.cts.parser.Activator;
public class ReferenceHandlerImpl implements ReferenceHandler {
protected final ObservableInjectingParser batchParser;
private final ITextBlocksTokenStream tbtokenStream;
private final Collection<AbstractToken> tokensForReferenceResolving = new ArrayList<AbstractToken>();
private final Collection<DelayedReference> newlyResolvableReferences = new ArrayList<DelayedReference>();
public ReferenceHandlerImpl(ObservableInjectingParser batchParser, ITextBlocksTokenStream tbtokenStream) {
super();
this.batchParser = batchParser;
this.tbtokenStream = tbtokenStream;
}
@Override
public Object getFeatureValue(EObject modelElement, String featureName) {
try {
return batchParser.getInjector().getModelAdapter().get(modelElement, featureName);
} catch (ModelAdapterException e) {
// TODO really log this error?
Activator.logError(e);
return null;
}
}
@Override
public void addNewlyResolvableReferences(DelayedReference delayedRef) {
newlyResolvableReferences.add(delayedRef);
}
/**
* Registers tokens that might have an impact on the resolving of references.
*/
@Override
public void registerTokenForReferenceResolving(AbstractToken subNode) {
tokensForReferenceResolving.add(subNode);
}
@Override
public void reset() {
tokensForReferenceResolving.clear();
newlyResolvableReferences.clear();
}
@Override
public void setNewFeature(SetNewFeatureBean newFeatureBean, boolean assignToPartition) {
IncrementalParsingUtil.setNewFeature(newFeatureBean, batchParser.getInjector(), assignToPartition);
}
@Override
public void unsetFeature(SetNewFeatureBean featureBean) {
batchParser.getInjector().unset(featureBean.parentRefObject, featureBean.property, featureBean.value);
}
@Override
public void setNewPrimitiveFeature(TextBlockProxy newVersion, TextBlock oldVersion, AbstractToken subNode) {
IncrementalParsingUtil.setNewPrimitiveFeature(newVersion, oldVersion, subNode, batchParser.getInjector());
}
@Override
public void unsetPrimitiveFeature(TextBlock oldVersion, LexedToken lt) {
IncrementalParsingUtil.unsetPrimitiveFeature(oldVersion, lt, batchParser.getInjector());
}
@Override
public void unsetFeature(TextBlock oldVersion, TextBlock tb) {
IncrementalParsingUtil.unsetFeature(oldVersion, tb, batchParser.getInjector());
}
@Override
public void reEvaluatePropertyInits(TextBlock oldVersion, TextBlockProxy newVersion) {
if (oldVersion.getCorrespondingModelElements().isEmpty()) {
return;
}
if (newVersion.getCorrespondingModelElementProxies().isEmpty()) {
return;
}
EObject modelElement = oldVersion.getCorrespondingModelElements().iterator().next();
ModelElementProxy proxy = (ModelElementProxy) newVersion.getCorrespondingModelElementProxies().iterator().next();
Collection<PrimitivePropertyInit> actions = TcsUtil.getElementsOfType(newVersion.getTemplate(),
PrimitivePropertyInit.class);
for (InjectorAction injectorAction : actions) {
if (!TcsUtil.wasExecuted((ContextTemplate) newVersion.getTemplate(), newVersion.getAlternativeChoices(),
injectorAction.getInjectorActionsBlock())) {
continue;
}
PrimitivePropertyInit init = (PrimitivePropertyInit) injectorAction;
EStructuralFeature feat = init.getPropertyReference().getStrucfeature();
List<Object> value = proxy.getAttributeMap().get(feat.getName());
if (value != null && value.size() > 0) {
batchParser.getInjector().set(modelElement, feat.getName(), value.iterator().next());
} else {
batchParser.getInjector().unset(modelElement, feat.getName(), null);
}
}
}
/**
* Only resolve those references that were affected by this parse run. This may either by because they are contained in a new
* text block or the token that contains the value that was used to do the initial resolving changed.
*/
@Override
public void resolveRemainingReferences() {
for (DelayedReference ref : new ArrayList<DelayedReference>(batchParser.getUnresolvedReferences())) {
AbstractToken refToken = tbtokenStream.getTokenModelElementForParserToken(ref.getToken());
ref.setTextBlock(refToken.getParent());
boolean resolveNewlyFromToken = tokensForReferenceResolving.contains(tbtokenStream
.getTokenModelElementForParserToken(ref.getToken()));
boolean newlyResolve = newlyResolvableReferences.contains(ref);
if (ref.getType() == DelayedReference.ReferenceType.TYPE_FOREACH_PREDICATE && refToken != null) {
if (TbVersionUtil.getOtherVersion(tbtokenStream.getTokenModelElementForParserToken(ref.getToken()).getParent(),
Version.REFERENCE) != null) {
batchParser.removeUnresolvedReference(ref);
}
} else if (!newlyResolve && !resolveNewlyFromToken) {
batchParser.removeUnresolvedReference(ref);
} else {
if (ref.getModelElement() instanceof IModelElementProxy) {
IModelElementProxy proxy = (IModelElementProxy) ref.getModelElement();
if (proxy.getRealObject() == null) {
// proxy not resolved yet, this means that
// only the reference changed and not the containing
// model element
// therefore re-use the old element from the textblock
EObject existingElement = TbUtil.getCreatedElement(refToken.getParent());
((ModelElementProxy) proxy).setRealObject(existingElement);
}
}
if (resolveNewlyFromToken) {
// delete old reference first
// TODO use reflective call on association proxy instead
EObject modelElement = null;
if (ref.getModelElement() instanceof IModelElementProxy) {
modelElement = (EObject) ((IModelElementProxy) ref.getModelElement()).getRealObject();
} else {
modelElement = (EObject) ref.getModelElement();
}
if (ref.getLookIn() != null) {
// a lookIn means that the result was added to the
// parent textblock.
// TODO this should now be handled by the token updater
// boolean propertyIsAssocEnd = false;
// EStructuralFeature feature = modelElement.eClass().getEStructuralFeature(ref.getPropertyName());
// for (EObject actualValue : refToken
// .getParent()
// .getReferencedElements()) {
// try {
// if (feature.getEType().isInstance(actualValue)) {
// batchParser.getInjector().unset(
// modelElement,
// ref.getPropertyName(),
// actualValue);
// }
// } catch (Exception ex) {
// // TODO find out which corresponding
// // element was the correct one
// // instead of trying this here
// }
// }
// if (propertyIsAssocEnd) {
// TODO check for hiddenOpposite?
// try to find the association end and check there
// if the correspondingmodelelement
// is the correct one.
// }
} else {
if (refToken instanceof LexedToken && ((LexedToken) refToken).getReferencedElements().size() > 0) {
for (EObject value : ((LexedToken) refToken).getReferencedElements()) {
try {
batchParser.getInjector().unset(modelElement, ref.getPropertyName(), value);
} catch (Exception ex) {
// TODO find out which corresponding
// element was the correct one
// instead of trying this here
}
}
}
}
}
}
}
List<DelayedReference> tmpUnresovedReferences = new ArrayList<DelayedReference>(batchParser.getUnresolvedReferences());
batchParser.setDelayedReferencesAfterParsing();
Iterator<DelayedReference> newRefIt = tmpUnresovedReferences.iterator();
while (newRefIt.hasNext()) {
DelayedReference ref = newRefIt.next();
if (ref.getType() == DelayedReference.ReferenceType.TYPE_FOREACH_PREDICATE && ref.getRealValue() != null
&& ref.getRealValue() instanceof EObject) {
((LexedToken) tbtokenStream.getTokenModelElementForParserToken(ref.getToken())).getParent()
.getCorrespondingModelElements().add((EObject) ref.getRealValue());
}
}
// for (DelayedReference ref : batchParser.getUnresolvedReferences()) {
// GlobalDelayedReferenceResolver.getInstance()
// .registerReferenceForIncrementalEvaluation(
// ref,
// (LexedToken) tbtokenStream
// .getTokenModelElementForParserToken(ref
// .getToken()), connection);
// }
// now all that is left to do is to resolve the proxy of the reference
// to the previously
// existing element!!!!
// if(!batchParser.setDelayedReferencesAfterParsing()){
// for (DelayedReference ref : batchParser.getUnresolvedReferences()) {
// //
// GlobalDelayedReferenceResolver.getInstance().registerUnresolvedReference(ref,
// (LexedToken) tbtokenStream
// // .getTokenModelElementForParserToken(ref.getToken()), true);
// }
// }
}
}