package jetbrains.mps.ide.editor.util;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import com.intellij.pom.Navigatable;
import jetbrains.mps.project.Project;
import java.util.Comparator;
import com.intellij.util.Function;
import jetbrains.mps.ide.editor.util.renderer.BaseRenderer;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.project.MPSProject;
import com.intellij.ui.awt.RelativePoint;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import jetbrains.mps.nodeEditor.EditorComponent;
import java.awt.Point;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.ui.components.JBList;
import com.intellij.ui.SortedListModel;
import java.util.Collections;
import java.util.List;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import javax.swing.ListSelectionModel;
import java.util.function.Consumer;
import jetbrains.mps.classloading.ModuleClassLoader;

@GeneratedClass(node = "r:4e6037e6-9135-44f8-9403-04d79fc40f4a(jetbrains.mps.ide.editor.util)/4819045807160363825", model = "r:4e6037e6-9135-44f8-9403-04d79fc40f4a(jetbrains.mps.ide.editor.util)")
public class GoToContextMenuHelperBase<T extends Navigatable> {
  protected final Project myProject;
  protected final CaptionFunction myCaptionFun;
  protected final Comparator<T> myComparator;
  protected final Function<T, String> myNamerForFiltering;
  protected final BaseRenderer<T> myRenderer;

  public GoToContextMenuHelperBase(@NotNull MPSProject project, @NotNull CaptionFunction captionFun, @NotNull BaseRenderer<T> renderer, @NotNull Comparator<T> comparator, @NotNull Function<T, String> namer) {
    myProject = project;
    myCaptionFun = captionFun;
    myRenderer = renderer;
    myComparator = comparator;
    myNamerForFiltering = namer;
  }

  public static RelativePoint getRelativePoint(EditorCell selectedCell, InputEvent inputEvent) {
    if (inputEvent instanceof MouseEvent) {
      return new RelativePoint(((MouseEvent) inputEvent));
    }
    return new RelativePoint((EditorComponent) selectedCell.getEditorComponent(), new Point(selectedCell.getX(), selectedCell.getY()));
  }

  public static final class ContextMenuComposite<T extends Navigatable> {
    public final JBPopup myPopup;
    public final JBList<T> myJBList;
    public final SortedListModel<T> myListModel;

    public ContextMenuComposite(@NotNull JBPopup popup, @NotNull JBList<T> jbList, @NotNull SortedListModel<T> listModel) {
      myPopup = popup;
      myJBList = jbList;
      myListModel = listModel;
    }
  }

  @NotNull
  public ContextMenuComposite<T> buildPopup() {
    return buildPopup(Collections.<T>emptyList());
  }

  @NotNull
  public ContextMenuComposite<T> buildPopup(@NotNull List<T> foundUsages) {
    checkClassLoader();
    SortedListModel<T> listModel = new SortedListModel(myComparator);
    for (T usage : ListSequence.fromList(foundUsages)) {
      listModel.add(usage);
    }
    final JBList<T> list = new JBList<T>(listModel);
    String startingCaption = myCaptionFun.caption(0, false);
    JBPopup popup = new PopupChooserBuilder<T>(list).setTitle(startingCaption).setMovable(true).setItemChoosenCallback(new Runnable() {
      @Override
      public void run() {
        int[] ids = list.getSelectedIndices();
        if (ids == null || ids.length == 0) {
          return;
        }
        for (T selected : list.getSelectedValuesList()) {
          selected.navigate(true);
        }
      }
    }).setRequestFocus(true).setRenderer(myRenderer).setSelectionMode(ListSelectionModel.SINGLE_SELECTION).setNamerForFiltering(myNamerForFiltering).setAutoselectOnMouseMove(true).createPopup();
    return new ContextMenuComposite(popup, list, listModel);
  }

  @NotNull
  public ContextMenuComposite<T> showMenu(@NotNull List<T> nodes, @NotNull RelativePoint point) {
    final SortedListModel<T> model = new SortedListModel<T>(myComparator);
    nodes.stream().distinct().forEach(new Consumer<T>() {
      @Override
      public void accept(T item) {
        model.add(item);
      }
    });
    ContextMenuComposite<T> menu = buildPopup();
    menu.myJBList.setModel(model);
    menu.myPopup.show(point);
    return menu;
  }

  private static void checkClassLoader() {
    assert !(GoToContextMenuHelperBase.class.getClassLoader() instanceof ModuleClassLoader) : "if this class is loaded by a reloadable classloader, this will cause memleaks. See MPS-13481";
  }

}
