package jetbrains.mps.console.base.util;

/*Generated by MPS */

import jetbrains.mps.scope.Scope;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.smodel.language.LanguageRegistry;
import java.util.Collection;
import org.jetbrains.mps.openapi.language.SLanguage;
import jetbrains.mps.smodel.SLanguageHierarchy;
import jetbrains.mps.smodel.ModelDependencyResolver;
import jetbrains.mps.internal.collections.runtime.CollectionSequence;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModuleOperations;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SModelOperations;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.lang.structure.behavior.AbstractConceptDeclaration__BehaviorDescriptor;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import org.jetbrains.mps.openapi.language.SConcept;
import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory;

public abstract class SubconceptsScope extends Scope {

  protected SNode concept;
  protected SModel model;

  public SubconceptsScope(SNode concept, SModel model) {
    this.concept = concept;
    this.model = model;
  }

  public abstract String getName(SNode child);
  public Iterable<SNode> getAvailableElements(@Nullable final String prefix) {
    SRepository repository = model.getRepository();
    LanguageRegistry languageRegistry = LanguageRegistry.getInstance(repository);
    Collection<SLanguage> usedLanguages = new SLanguageHierarchy(languageRegistry, new ModelDependencyResolver(languageRegistry, repository).usedLanguages(model)).getExtended();
    Iterable<SNode> allConcepts = CollectionSequence.fromCollection(usedLanguages).select((it) -> it.getSourceModule()).select((it) -> SModuleOperations.getAspect(it, "structure")).translate((it) -> SModelOperations.roots(it, CONCEPTS.AbstractConceptDeclaration$KA));
    Iterable<SNode> subConcepts = Sequence.fromIterable(allConcepts).where((it) -> (boolean) AbstractConceptDeclaration__BehaviorDescriptor.isSubconceptOf_id73yVtVlWOga.invoke(it, concept));
    if (prefix == null || prefix.isEmpty()) {
      return subConcepts;
    }
    return Sequence.fromIterable(subConcepts).where((it) -> {
      String name = getName(it);
      return name != null && name.startsWith(prefix);
    });
  }
  @Nullable
  public SNode resolve(SNode contextNode, @NotNull String refText) {
    SNode result = null;
    for (SNode n : Sequence.fromIterable(getAvailableElements(null))) {
      String name = getName(n);
      if (refText.equals(name)) {
        if (result == null) {
          result = n;
        } else {
          return null;
        }
      }
    }
    return result;
  }
  @Nullable
  public String getReferenceText(SNode contextNode, @NotNull SNode node) {
    if (!(SNodeOperations.isInstanceOf(node, CONCEPTS.AbstractConceptDeclaration$KA)) || !((boolean) AbstractConceptDeclaration__BehaviorDescriptor.isSubconceptOf_id73yVtVlWOga.invoke(SNodeOperations.cast(node, CONCEPTS.AbstractConceptDeclaration$KA), concept))) {
      return null;
    }
    String result = getName(SNodeOperations.cast(node, CONCEPTS.AbstractConceptDeclaration$KA));
    for (SNode n : Sequence.fromIterable(getAvailableElements(null))) {
      if (n == node) {
        continue;
      }
      String name = getName(n);
      if (name.equals(result)) {
        // ambiguity
        return null;
      }
    }
    return result;
  }

  private static final class CONCEPTS {
    /*package*/ static final SConcept AbstractConceptDeclaration$KA = MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0x1103553c5ffL, "jetbrains.mps.lang.structure.structure.AbstractConceptDeclaration");
  }
}
