package jetbrains.mps.lang.structure.behavior;

/*Generated by MPS */

import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.lang.smodel.behavior.AttributeAccess__BehaviorDescriptor;
import jetbrains.mps.scope.Scope;
import jetbrains.mps.lang.structure.constraints.Scopes;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import java.util.Objects;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SPropertyOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor;
import jetbrains.mps.smodel.SNodePointer;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.LinkedHashSet;
import org.jetbrains.mps.openapi.language.SReferenceLink;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SProperty;

public class AttributeDesignTimeOperations {
  public static Iterable<SNode> getApplicableAttributes(SNode accessNode, final SNodeReference attributeType) {
    // todo: should be node<ACD>
    final SNode nodeConcept = SLinkOperations.getTarget(AttributeAccess__BehaviorDescriptor.getAttributeContainerType_id62qhzb6UOqI.invoke(accessNode), LINKS.concept$OMgE);
    if ((nodeConcept == null)) {
      return null;
    }
    Scope conceptsScope = Scopes.forConcepts(accessNode, CONCEPTS.ConceptDeclaration$gH);
    return Sequence.fromIterable(conceptsScope.getAvailableElements(null)).select((it) -> SNodeOperations.cast(it, CONCEPTS.ConceptDeclaration$gH)).where((it) -> {
      return SetSequence.fromSet(getSuperConcepts(it)).any(new _FunctionTypes._return_P1_E0<Boolean, SNode>() {
        public Boolean invoke(SNode it) {
          return Objects.equals(SNodeOperations.getPointer(it), attributeType);
        }
      });
    }).where((it) -> {
      // todo: why not getAttributeRole?
      return isNotEmptyString(SPropertyOperations.getString(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(it), PROPS.role$vUyK)) && Sequence.fromIterable(getApplicableConcepts(it)).any(new _FunctionTypes._return_P1_E0<Boolean, SNode>() {
        public Boolean invoke(SNode it) {
          return (boolean) AbstractConceptDeclaration__BehaviorDescriptor.isSubconceptOf_id73yVtVlWOga.invoke(nodeConcept, it);
        }
      });
    });
  }
  public static boolean isAttributeDeclaration(SNode conceptDeclaration) {
    return SetSequence.fromSet(getSuperConcepts(conceptDeclaration)).any((it) -> SNodeOperations.is(it, new SNodePointer("r:00000000-0000-4000-0000-011c89590288(jetbrains.mps.lang.core.structure)", "5169995583184591161")));
  }
  public static boolean isMultipleAttribute(SNode attributeDeclaration) {
    if (!(isAttributeDeclaration(attributeDeclaration))) {
      return false;
    }
    return SPropertyOperations.getBoolean(SLinkOperations.getTarget(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(SetSequence.fromSet(getSuperConcepts(attributeDeclaration)).findFirst((it) -> (SLinkOperations.getTarget(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(it), LINKS.multiple$eysG) != null))), LINKS.multiple$eysG), PROPS.value$JccR);
  }
  @Nullable
  public static String getAttributeRole(SNode attributeDeclaration) {
    if (!(isAttributeDeclaration(attributeDeclaration))) {
      return null;
    }
    return SPropertyOperations.getString(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(SetSequence.fromSet(getSuperConcepts(attributeDeclaration)).findFirst((it) -> isNotEmptyString(SPropertyOperations.getString(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(it), PROPS.role$vUyK)))), PROPS.role$vUyK);
  }

  @Nullable
  public static String getAttributeRoleSafe(SNode attributeDeclaration) {
    try {
      String role = AttributeDesignTimeOperations.getAttributeRole(attributeDeclaration);
      if (role != null) {
        return role;
      }
    } catch (Exception ex) {
      // ignore
    }
    return SPropertyOperations.getString(attributeDeclaration, PROPS.name$MnvL);
  }

  public static Iterable<SNode> getApplicableConcepts(SNode attributeDeclaration) {
    if (!(isAttributeDeclaration(attributeDeclaration))) {
      return null;
    }
    return SetSequence.fromSet(getSuperConcepts(attributeDeclaration)).translate((it) -> SLinkOperations.collect(SLinkOperations.getChildren(new IAttributeDescriptor.NodeAttribute(CONCEPTS.AttributeInfo$hg).get(it), LINKS.attributed$sGW5), LINKS.concept$sRY2)).distinct().where((it) -> (it != null));
  }

  private static Set<SNode> getSuperConcepts(SNode conceptDeclaration) {
    Set<SNode> concepts = SetSequence.fromSet(new LinkedHashSet<SNode>());
    while ((conceptDeclaration != null) && !(SetSequence.fromSet(concepts).contains(conceptDeclaration))) {
      SetSequence.fromSet(concepts).addElement(conceptDeclaration);
      conceptDeclaration = SLinkOperations.getTarget(conceptDeclaration, LINKS.extends$_Isg);
    }
    return concepts;
  }
  private static boolean isNotEmptyString(String str) {
    return str != null && str.length() > 0;
  }

  private static final class LINKS {
    /*package*/ static final SReferenceLink concept$OMgE = MetaAdapterFactory.getReferenceLink(0x7866978ea0f04cc7L, 0x81bc4d213d9375e1L, 0x108f968b3caL, 0x1090e46ca51L, "concept");
    /*package*/ static final SContainmentLink multiple$eysG = MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x29889a701b928195L, 0x694f83d1440affeaL, "multiple");
    /*package*/ static final SContainmentLink attributed$sGW5 = MetaAdapterFactory.getContainmentLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x29889a701b928195L, 0x694f83d143972c0eL, "attributed");
    /*package*/ static final SReferenceLink concept$sRY2 = MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x5405fd03496acb49L, 0x5405fd03496acc99L, "concept");
    /*package*/ static final SReferenceLink extends$_Isg = MetaAdapterFactory.getReferenceLink(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, 0xf979be93cfL, "extends");
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept ConceptDeclaration$gH = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979ba0450L, "jetbrains.mps.lang.structure.structure.ConceptDeclaration");
    /*package*/ static final SConcept AttributeInfo$hg = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x29889a701b928195L, "jetbrains.mps.lang.structure.structure.AttributeInfo");
  }

  private static final class PROPS {
    /*package*/ static final SProperty role$vUyK = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x29889a701b928195L, 0x694f83d1440b01c7L, "role");
    /*package*/ static final SProperty value$JccR = MetaAdapterFactory.getProperty(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x5405fd034959f7dcL, 0x5405fd03495a2dceL, "value");
    /*package*/ static final SProperty name$MnvL = MetaAdapterFactory.getProperty(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, 0x110396ec041L, "name");
  }
}
