package jetbrains.mps.baseLanguage.typesystem;

/*Generated by MPS */

import jetbrains.mps.lang.typesystem.runtime.AbstractNonTypesystemRule_Runtime;
import jetbrains.mps.lang.typesystem.runtime.NonTypesystemRule_Runtime;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.mps.typesystem.inference.TypeCheckingContext;
import jetbrains.mps.lang.typesystem.runtime.IsApplicableStatus;
import java.util.List;
import jetbrains.mps.util.Pair;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SConceptOperations;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import jetbrains.mps.baseLanguage.behavior.Classifier__BehaviorDescriptor;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.language.SReferenceLink;

public class check_ClassifierMethodsHierarchy_NonTypesystemRule extends AbstractNonTypesystemRule_Runtime implements NonTypesystemRule_Runtime {
  public check_ClassifierMethodsHierarchy_NonTypesystemRule() {
  }
  public void applyRule(final SNode classifier, final TypeCheckingContext typeCheckingContext, IsApplicableStatus status) {
    // [node to check + node to report to] -- hack to work with enum constant declarations
    // I think that it must be solved if we pull up all the traversing code to IMemberContainer (or smth like this)
    List<Pair<SNode, SNode>> toCheck = ListSequence.fromList(new ArrayList<Pair<SNode, SNode>>());
    if (SNodeOperations.isInstanceOf(classifier, CONCEPTS.EnumClass$Vk) && ListSequence.fromList(SLinkOperations.getChildren(SNodeOperations.cast(classifier, CONCEPTS.EnumClass$Vk), LINKS.enumConstant$qtgW)).isNotEmpty()) {
      ListSequence.fromList(toCheck).addSequence(ListSequence.fromList(SLinkOperations.getChildren(SNodeOperations.cast(classifier, CONCEPTS.EnumClass$Vk), LINKS.enumConstant$qtgW)).select((it) -> {
        SNode dummyAnonymous = SConceptOperations.createNewNode(MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x1107e0cb103L, "jetbrains.mps.baseLanguage.structure.AnonymousClass"));
        SLinkOperations.setTarget(dummyAnonymous, LINKS.classifier$q_Y$, classifier);
        ListSequence.fromList(SLinkOperations.getChildren(dummyAnonymous, LINKS.member$L_2d)).addSequence(ListSequence.fromList(SLinkOperations.getChildren(it, LINKS.method$pGvv)).select(new _FunctionTypes._return_P1_E0<SNode, SNode>() {
          public SNode invoke(SNode it) {
            return SNodeOperations.copyNode(it);
          }
        }));
        return new Pair<SNode, SNode>(dummyAnonymous, it);
      }));
    } else {
      ListSequence.fromList(toCheck).addElement(new Pair(classifier, classifier));
    }
    for (Pair<SNode, SNode> pair : ListSequence.fromList(toCheck)) {
      SNode nodeToCheck = pair.o1;
      SNode nodeToReport = pair.o2;
      for (SNode m : Classifier__BehaviorDescriptor.methods_id4_LVZ3pBKCn.invoke(nodeToCheck)) {
        typeCheckingContext.addDependencyForCurrent(m);
      }
      ClassifierMethodsHierarchyChecker checker = new ClassifierMethodsHierarchyChecker(nodeToCheck, nodeToReport);
      List<ErrorReportingItem> result = checker.check();
      for (ErrorReportingItem item : ListSequence.fromList(result)) {
        item.report(typeCheckingContext);
      }
    }
  }
  public SAbstractConcept getApplicableConcept() {
    return CONCEPTS.Classifier$Ix;
  }
  public IsApplicableStatus isApplicableAndPattern(SNode argument) {
    return new IsApplicableStatus(argument.getConcept().isSubConceptOf(getApplicableConcept()), null);
  }
  public boolean overrides() {
    return false;
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept EnumClass$Vk = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xfc367070a5L, "jetbrains.mps.baseLanguage.structure.EnumClass");
    /*package*/ static final SConcept Classifier$Ix = MetaAdapterFactory.getConcept(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, "jetbrains.mps.baseLanguage.structure.Classifier");
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink enumConstant$qtgW = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xfc367070a5L, 0xfc367503acL, "enumConstant");
    /*package*/ static final SReferenceLink classifier$q_Y$ = MetaAdapterFactory.getReferenceLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x1107e0cb103L, 0x1107e0fd2a0L, "classifier");
    /*package*/ static final SContainmentLink member$L_2d = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0x101d9d3ca30L, 0x4a9a46de59132803L, "member");
    /*package*/ static final SContainmentLink method$pGvv = MetaAdapterFactory.getContainmentLink(0xf3061a5392264cc5L, 0xa443f952ceaf5816L, 0xfc367388b3L, 0x6d60019ab157734L, "method");
  }
}
