package jetbrains.mps.ide.findusages.findalgorithm.finders;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.model.SModelReference;
import jetbrains.mps.smodel.SNodePointer;
import org.jetbrains.mps.openapi.persistence.PersistenceFacade;
import org.jetbrains.mps.openapi.module.SearchScope;
import org.jetbrains.mps.annotations.Mutable;
import java.util.List;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import jetbrains.mps.ide.findusages.model.SearchResults;
import jetbrains.mps.ide.findusages.model.SearchResult;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import jetbrains.mps.ide.findusages.model.SearchQuery;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import jetbrains.mps.logging.Logger;

@GeneratedClass(node = "r:1a2b3027-99d2-4946-917b-f185130ac75d(jetbrains.mps.ide.findusages.findalgorithm.finders)/8267733531687412365", model = "r:1a2b3027-99d2-4946-917b-f185130ac75d(jetbrains.mps.ide.findusages.findalgorithm.finders)")
public abstract class GeneratedFinder implements IInterfacedFinder {

  public GeneratedFinder() {
  }

  @Override
  public boolean isApplicable(SNode node) {
    return true;
  }

  @Override
  public boolean isVisible(SNode node) {
    return true;
  }

  @Override
  public boolean isUsedByDefault(SNode node) {
    return false;
  }

  @Override
  public String getLongDescription() {
    return "";
  }

  @Nullable
  public SNodeReference getDeclarationNode() {
    return null;
  }

  protected SNodeReference buildNodePointer(SModelReference modelRef, String nodeId) {
    // auxiliary method to help generated code deal with string node id values
    return new SNodePointer(modelRef, PersistenceFacade.getInstance().createNodeId(nodeId));
  }

  @Override
  public boolean canNavigate() {
    return true;
  }

  /**
   * both methods are to become abstract
   */
  @Deprecated
  protected void doFind(SNode node, SearchScope scope, @Mutable List<SNode> _results, ProgressMonitor monitor) {
    CollectingCallback callback = new CollectingCallback();
    doFind0(node, scope, callback, monitor);
    SearchResults<?> results = callback.getResults();
    for (SearchResult<?> res : ListSequence.fromList(results.getNotNullResults())) {
      _results.add((SNode) res);
    }
  }

  protected void doFind0(@NotNull SNode node, @NotNull SearchScope scope, @NotNull IFinder.FindCallback callback, @NotNull ProgressMonitor monitor) {
    // abstract
    List<SNode> result = new ArrayList<SNode>();
    doFind(node, scope, result, monitor);
    for (SNode res : result) {
      callback.onUsageFound(createSingleResult(res));
    }
  }

  /**
   * I suggest #getXXX method to return smth instead of this
   * @deprecated
   * 
   * @deprecated 
   */
  @Deprecated(since = "2018.3", forRemoval = true)
  public void getSearchedNodes(SNode node, SearchScope scope, List<SNode> _results) {
    _results.add(node);
  }

  @NotNull
  public List<SNode> getElementsToLookFor(@NotNull SNode toSearch, @NotNull SearchScope scope) {
    // default implementation for all generated finders with an empty section
    List<SNode> res = new ArrayList<SNode>();
    getSearchedNodes(toSearch, scope, res);
    return Collections.unmodifiableList(res);
    // return Collections.singletonList(toSearch);
  }

  public String getNodeCategory(SNode node) {
    return "Uncategorized";
  }

  @NotNull
  protected SearchResult<SNode> createSingleResult(@NotNull SNode usage) {
    return new SearchResult<SNode>(usage, getNodeCategory(usage));
  }

  @Override
  public void find(@NotNull SearchQuery query, @NotNull IFinder.FindCallback callback, @NotNull ProgressMonitor monitor) {
    Object value = query.getObjectHolder().getObject();
    SNode node = null;
    if (value instanceof SNodeReference) {
      node = query.getSearchObjectResolver().resolve((SNodeReference) value);
    } else
    if (value instanceof SNode) {
      node = (SNode) value;
    }
    if (node == null) {
      return;
    }
    SAbstractConcept concept = getSConcept();
    if (node.getConcept().isSubConceptOf(concept) && isApplicable(node)) {
      callback.onSearchedObjectsCalculated(new SearchedObjects(getElementsToLookFor(node, query.getScope())));
      doFind0(node, query.getScope(), callback, monitor);
    } else {
      String m = "Trying to use finder that is not applicable to the concept. Returning empty results.[finder: '%s'; concept: %s";
      Logger.getLogger(GeneratedFinder.class).debug(String.format(m, getDescription(), node.getConcept()));
    }
  }
}
