package jetbrains.mps.lang.behavior.findUsages;

/*Generated by MPS */

import jetbrains.mps.ide.findusages.findalgorithm.finders.GeneratedFinder;
import jetbrains.mps.logging.Logger;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SearchScope;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import jetbrains.mps.ide.findusages.model.scopes.ModelsScope;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.ide.findusages.findalgorithm.finders.IFinder;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.lang.behavior.behavior.ConceptMethodDeclaration__BehaviorDescriptor;
import jetbrains.mps.ide.findusages.view.FindUtils;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import org.jetbrains.mps.openapi.model.SModel;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModuleOperations;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.lang.structure.behavior.AbstractConceptDeclaration__BehaviorDescriptor;
import java.util.List;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.ide.findusages.model.SearchQuery;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.language.SConcept;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;
import org.jetbrains.mps.openapi.language.SContainmentLink;

public class OverriddenMethods_Finder extends GeneratedFinder {
  private static final Logger LOG = Logger.getLogger(OverriddenMethods_Finder.class);
  public OverriddenMethods_Finder() {
  }
  public boolean isVisible(SNode node, SearchScope scope) {
    return SNodeOperations.isInstanceOf(SNodeOperations.getParent(node), CONCEPTS.ConceptBehavior$2);
  }
  @Override
  public boolean isVisible(SNode node) {
    return isVisible(node, new ModelsScope(node.getModel()));
  }
  @Override
  public String getDescription() {
    return "Overridden Methods";
  }
  @Override
  public String getLongDescription() {
    return "";
  }
  @Override
  public SAbstractConcept getSConcept() {
    return CONCEPTS.ConceptMethodDeclaration$N0;
  }
  @Override
  public boolean isApplicable(SNode node) {
    return SNodeOperations.isInstanceOf(SNodeOperations.getParent(node), CONCEPTS.ConceptBehavior$2);
  }

  @Override
  protected void doFind0(@NotNull SNode node, SearchScope scope, final IFinder.FindCallback callback, final ProgressMonitor monitor) {
    monitor.start(getDescription(), 1);
    try {
      // top-most ancestor by the lang.behavior
      final SNode topMostOverriddenMethod = ConceptMethodDeclaration__BehaviorDescriptor.getOverridenMethod_idhP3pnNO.invoke(node);
      FindUtils.searchForResults(monitor.subTask(1), (searchResult) -> {
        SNode nodeParam = (SNode) searchResult.getObject();
        ((_FunctionTypes._void_P1_E0<SNode>) (SNode ancestorConcept) -> {
          if (ancestorConcept == ConceptMethodDeclaration__BehaviorDescriptor.getContainingConcept_idi3POAMX.invoke(node)) {
            return;
          }
          SModel cncptModel = SNodeOperations.getModel(ancestorConcept);
          if (cncptModel == null) {
            if (LOG.isErrorLevel()) {
              LOG.error("Could not found the ancestorConcept model while looking for the ancestors for the concept '" + SNodeOperations.present(ancestorConcept) + "'");
            }
            return;

          }
          SModel aspectModel = SModuleOperations.getAspect(cncptModel.getModule(), "behavior");
          if (aspectModel == null) {
            if (LOG.isErrorLevel()) {
              LOG.error("Could not found the aspect behavior model while looking for the ancestors for the concept '" + SNodeOperations.present(ancestorConcept) + "'");
            }
            return;
          }
          if (monitor.isCanceled()) {
            return;
          }
          SNode ancestorBehavior = SNodeOperations.cast(Sequence.fromIterable(AbstractConceptDeclaration__BehaviorDescriptor.findConceptAspects_id4G9PD8$NvPM.invoke(SNodeOperations.cast(ancestorConcept, CONCEPTS.AbstractConceptDeclaration$KA), aspectModel)).where((it) -> SNodeOperations.isInstanceOf(it, CONCEPTS.ConceptBehavior$2)).first(), CONCEPTS.ConceptBehavior$2);
          List<SNode> candidateMethodsInAncestor = ListSequence.fromList(SLinkOperations.getChildren(ancestorBehavior, LINKS.method$w_in)).where((it) -> ConceptMethodDeclaration__BehaviorDescriptor.getOverridenMethod_idhP3pnNO.invoke(it) == topMostOverriddenMethod).toList();
          // supposedly there are no more than one method
          for (SNode candidateMethod : ListSequence.fromList(candidateMethodsInAncestor)) {
            callback.onUsageFound(createSingleResult(candidateMethod));
          }
        }).invoke(nodeParam);
      }, new SearchQuery(ConceptMethodDeclaration__BehaviorDescriptor.getContainingConcept_idi3POAMX.invoke(node), scope), FindUtils.getFinder("jetbrains.mps.lang.structure.findUsages.ConceptAncestors_Finder"));
    } finally {
      monitor.done();
    }
  }


  @Nullable
  @Override
  public SNodeReference getDeclarationNode() {
    return buildNodePointer(FindUsagesDescriptor.DECLARING_MODEL, "7335624801804187873");
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept ConceptBehavior$2 = MetaAdapterFactory.getConcept(0xaf65afd8f0dd4942L, 0x87d963a55f2a9db1L, 0x11d43447b1aL, "jetbrains.mps.lang.behavior.structure.ConceptBehavior");
    /*package*/ static final SConcept ConceptMethodDeclaration$N0 = MetaAdapterFactory.getConcept(0xaf65afd8f0dd4942L, 0x87d963a55f2a9db1L, 0x11d4348057eL, "jetbrains.mps.lang.behavior.structure.ConceptMethodDeclaration");
    /*package*/ static final SConcept AbstractConceptDeclaration$KA = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, "jetbrains.mps.lang.structure.structure.AbstractConceptDeclaration");
  }

  private static final class LINKS {
    /*package*/ static final SContainmentLink method$w_in = MetaAdapterFactory.getContainmentLink(0xaf65afd8f0dd4942L, 0x87d963a55f2a9db1L, 0x11d43447b1aL, 0x11d43447b25L, "method");
  }
}
