/*
* Copyright 2003-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jetbrains.mps.smodel.presentation;
import jetbrains.mps.kernel.model.SModelUtil;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations;
import jetbrains.mps.smodel.DynamicReference;
import jetbrains.mps.smodel.NodeReadAccessCasterInEditor;
import jetbrains.mps.smodel.SNodeLegacy;
import jetbrains.mps.smodel.SNodeUtil;
import jetbrains.mps.smodel.search.SModelSearchUtil;
import jetbrains.mps.util.Computable;
import jetbrains.mps.util.SNodeOperations;
import org.apache.log4j.LogManager;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SReferenceLink;
import org.apache.log4j.Logger;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SReference;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Igor Alshannikov
* Jan 31, 2008
*/
public class ReferenceConceptUtil {
private static final Logger LOG = LogManager.getLogger(ReferenceConceptUtil.class);
/**
* Purpose of some concepts is only to hold reference on something else.
* In such a concepts, the most important thing is that reference, which is called 'characteristic reference'.
* <p/>
* Concept is considered 'pure reference' if
* - it has alias which matches the pattern 'xxx <{_referent_role_}> yyy' (and declares reference link with this role)
* or
* - it declares declares exactly ONE reference link with cardinality 1
*
* @param concept with is possibly 'pure reference' concept.
* @return characteristic reference or NULL
*/
@Deprecated
public static SNode getCharacteristicReference(final SNode concept) {
return NodeReadAccessCasterInEditor.runReadTransparentAction(new Computable<SNode>() {
@Override
public SNode compute() {
String expectedReferentRole = null;
String alias = SNodeUtil.getConceptAlias(concept);
if (alias != null) {
final SmartAliasHelper smartAliasHelper = new SmartAliasHelper(alias);
expectedReferentRole = smartAliasHelper.getSmartRole();
if (expectedReferentRole == null) {
// trick (why?): has an alias but it doesn't match pattern - no characteristic reference
return null;
}
}
List<SNode> links = SModelSearchUtil.getReferenceLinkDeclarations(concept);
if (expectedReferentRole != null) {
for (SNode link : links) {
if (expectedReferentRole.equals(SModelUtil.getLinkDeclarationRole(link))) {
return link;
}
}
LOG.warn("the '" + alias + "' doesn't match any reference link in " + SNodeOperations.getDebugText(concept));
} else {
// if concept declares exactly ONE REQUIRED reference link...
if (links.size() == 1) {
SNode genuineLinkDeclaration = SModelUtil.getGenuineLinkDeclaration(links.get(0));
if (SNodeUtil.getLinkDeclaration_IsExactlyOneMultiplicity(genuineLinkDeclaration)) {
return links.get(0);
}
}
}
return null;
}
});
}
public static SReferenceLink getCharacteristicReference(final SAbstractConcept concept) {
String expectedReferentRole = null;
String alias = concept.getConceptAlias();
if (!alias.isEmpty()) {
final SmartAliasHelper smartAliasHelper = new SmartAliasHelper(alias);
expectedReferentRole = smartAliasHelper.getSmartRole();
if (expectedReferentRole == null) {
// trick (why?): has an alias but it doesn't match pattern - no characteristic reference
return null;
}
}
Iterable<SReferenceLink> links = concept.getReferenceLinks();
if (expectedReferentRole != null) {
for (SReferenceLink link : links) {
if (expectedReferentRole.equals(link.getName())) {
return link;
}
}
return null;
} else {
// if concept declares exactly ONE REQUIRED reference link...
Iterator<SReferenceLink> iterator = links.iterator();
if (!iterator.hasNext()) {
return null;
}
SReferenceLink result = iterator.next();
if (iterator.hasNext()) {
return null;
}
return result.isOptional() ? null : result;
}
}
@Deprecated
public static boolean hasSmartAlias(SNode concept) {
String conceptAlias = SNodeUtil.getConceptAlias(concept);
// matches pattern 'xxx <{_referent_role_}> yyy' ?
return conceptAlias != null && new SmartAliasHelper(conceptAlias).isSmartAlias();
}
public static boolean hasSmartAlias(SAbstractConcept concept) {
String conceptAlias = concept.getConceptAlias();
// matches pattern 'xxx <{_referent_role_}> yyy' ?
return !conceptAlias.isEmpty() && new SmartAliasHelper(conceptAlias).isSmartAlias();
}
@Deprecated
public static String getPresentationFromSmartAlias(SNode concept, String referentPresentation) {
String conceptAlias = SNodeUtil.getConceptAlias(concept);
if (conceptAlias == null) {
return referentPresentation;
}
return new SmartAliasHelper(conceptAlias).getPresentation(referentPresentation);
}
public static String getPresentationFromSmartAlias(SAbstractConcept concept, String referentPresentation) {
String conceptAlias = concept.getConceptAlias();
return new SmartAliasHelper(conceptAlias).getPresentation(referentPresentation);
}
public static String getPresentation(SNode node) {
SNode nodeConcept = new SNodeLegacy(node).getConceptDeclarationNode();
SNode characteristicReference = getCharacteristicReference(nodeConcept);
if (characteristicReference == null) {
return null;
}
String genuineRole = SModelUtil.getGenuineLinkRole(characteristicReference);
SReference reference = node.getReference(genuineRole);
if (reference instanceof DynamicReference) {
return ((DynamicReference) reference).getResolveInfo();
}
SNode referentNode = node.getReferenceTarget(genuineRole);
final String referentPresentation;
if (referentNode != null) {
SConcept targetConcept = referentNode.getConcept();
if (getCharacteristicReference(targetConcept) != null) {
referentPresentation = referentNode.getConcept().getName();
} else {
referentPresentation = referentNode.toString();
}
} else {
referentPresentation = "<no " + SModelUtil.getLinkDeclarationRole(characteristicReference) + ">";
}
if (hasSmartAlias(nodeConcept)) {
return getPresentationFromSmartAlias(nodeConcept, referentPresentation);
}
return referentPresentation;
}
}