package jetbrains.mps.ide.findusages.view;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import jetbrains.mps.logging.Logger;
import jetbrains.mps.ide.findusages.model.SearchResults;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.util.ProgressMonitor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SearchScope;
import java.util.List;
import jetbrains.mps.ide.findusages.findalgorithm.finders.IInterfacedFinder;
import java.util.ArrayList;
import jetbrains.mps.ide.findusages.FindersManager;
import jetbrains.mps.ide.findusages.model.scopes.ModulesScope;
import jetbrains.mps.ide.findusages.model.SearchQuery;
import jetbrains.mps.ide.findusages.findalgorithm.finders.IFinder;
import jetbrains.mps.ide.findusages.model.IResultProvider;
import jetbrains.mps.ide.findusages.model.SearchResult;
import java.util.Collection;
import jetbrains.mps.ide.findusages.findalgorithm.resultproviders.treenodes.UnionNode;
import jetbrains.mps.ide.findusages.findalgorithm.resultproviders.treenodes.FinderNode;
import jetbrains.mps.ide.findusages.findalgorithm.finders.GeneratedFinder;
import jetbrains.mps.ide.findusages.findalgorithm.finders.ReloadableFinder;
import java.util.Arrays;

@GeneratedClass(node = "r:3cb1700d-933a-4e99-ae78-290ebea08948(jetbrains.mps.ide.findusages.view)/8568892084424436823", model = "r:3cb1700d-933a-4e99-ae78-290ebea08948(jetbrains.mps.ide.findusages.view)")
public class FindUtils {
  private static final Logger LOG = Logger.getLogger(FindUtils.class);
  @Deprecated
  public static SearchResults getSearchResults(@Nullable final ProgressMonitor monitor, @NotNull final SNode node, @Nullable SearchScope scope, final String... finderClassNames) {
    List<IInterfacedFinder> finders = new ArrayList<IInterfacedFinder>(finderClassNames.length);
    for (String finderClassName : finderClassNames) {
      IInterfacedFinder finder = FindersManager.getInstance().getFinder(finderClassName);
      if (finder != null) {
        finders.add(finder);
      }
    }
    if (scope == null) {
      scope = new ModulesScope(node.getModel().getRepository().getModules());
    }
    return getSearchResults(monitor, new SearchQuery(node, scope), finders.toArray(new IInterfacedFinder[0]));
  }

  public static void searchForResults(@Nullable final ProgressMonitor monitor, @NotNull IFinder.FindCallback callback, @NotNull final SearchQuery query, final IFinder... finders) {
    searchForResults(monitor, callback, query, makeProvider(finders));
  }

  public static SearchResults getSearchResults(@Nullable final ProgressMonitor monitor, final SearchQuery query, final IFinder... finders) {
    return getSearchResults(monitor, query, makeProvider(finders));
  }

  public static SearchResults getSearchResults(@Nullable final ProgressMonitor monitor, final SearchQuery query, final IResultProvider provider) {
    return provider.getResults(query, monitor);
  }

  public static void searchForResults(@Nullable final ProgressMonitor monitor, IFinder.FindCallback callback, final SearchQuery query, final IResultProvider provider) {
    provider.findResults(query, callback, monitor);
  }

  @Deprecated
  public static List<SNode> executeFinder(String className, SNode node, SearchScope scope, ProgressMonitor monitor) {
    List<SNode> result = new ArrayList<SNode>();
    IInterfacedFinder finder = FindersManager.getInstance().getFinder(className);
    if (finder == null) {
      return result;
    }
    SearchResults<?> searchResults = finder.find(new SearchQuery(node, scope), monitor);
    for (SearchResult<?> searchResult : searchResults.getSearchResults()) {
      if (searchResult.getObject() instanceof SNode) {
        result.add((SNode) searchResult.getObject());
      }
    }
    return result;
  }

  /**
   * There would be another {@code getFinder(FinderIdentity}) later (perhaps, with distinct FinderIdentity implementations, one to take string, another
   * takes SLanguage + int token + optional? String mangledName)
   */
  public static IInterfacedFinder getFinder(String finderIdentity) {
    IInterfacedFinder intFinder = FindersManager.getInstance().getFinder(finderIdentity);
    if (intFinder == null) {
      if (LOG.isWarningLevel()) {
        LOG.warning("No finder is discovered with the name " + finderIdentity);
      }
    }
    return intFinder;
  }

  public static IResultProvider makeProvider(Collection<? extends IFinder> finders) {
    UnionNode unionNode = new UnionNode();
    for (IFinder finder : finders) {
      if (finder == null) {
        continue;
      }
      final FinderNode fn;
      if (finder instanceof GeneratedFinder) {
        // just in case IResultProvider get serialized later, we give it an indication this one could get reloaded
        // XXX OTOH, it mught be IResultProvider itself to care about GeneratedFinder on write as it does on read for ReloadableFinders (so that RF
        // knowledge stays in a single place)?
        fn = new FinderNode(new ReloadableFinder((GeneratedFinder) finder));
      } else {
        fn = new FinderNode(finder);
      }
      unionNode.addChild(fn);
    }
    return unionNode;
  }

  public static IResultProvider makeProvider(IFinder... finders) {
    return makeProvider(Arrays.asList(finders));
  }

  /**
   * @param finderIdentity at the moment, we use finder implementation class fqn to identify it
   */
  public static IResultProvider makeProvider(@NotNull String... finderIdentity) {
    ArrayList<IFinder> finders = new ArrayList(finderIdentity.length);
    for (String fi : finderIdentity) {
      IInterfacedFinder f = FindersManager.getInstance().getFinder(fi);
      if (f != null) {
        finders.add(f);
      }
    }
    return makeProvider(finders);
  }
}
