package jetbrains.mps.ide.editor.util;

/*Generated by MPS */

import jetbrains.mps.annotations.GeneratedClass;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.ui.components.JBList;
import jetbrains.mps.ide.navigation.NodeNavigatable;
import com.intellij.ui.SortedListModel;
import com.intellij.util.Alarm;
import com.intellij.openapi.util.Ref;
import java.util.Set;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import java.util.LinkedHashSet;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.progress.ProgressIndicator;
import jetbrains.mps.ide.findusages.model.SearchResult;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import com.intellij.openapi.application.ModalityState;
import java.util.List;
import java.util.ArrayList;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.ui.MessageType;

@GeneratedClass(node = "r:4e6037e6-9135-44f8-9403-04d79fc40f4a(jetbrains.mps.ide.editor.util)/5343046100067132614", model = "r:4e6037e6-9135-44f8-9403-04d79fc40f4a(jetbrains.mps.ide.editor.util)")
public class BackgroundSearchWithPopupTask extends BackgroundSearchTask {
  private final JBPopup myPopup;
  private final PopupSettingsBuilder mySettings;
  private final JBList<NodeNavigatable> myList;
  private final SortedListModel<NodeNavigatable> myListModel;
  private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
  private final Ref<Boolean> myShown = new Ref<Boolean>(false);
  private final Object LOCK = new Object();
  private final Set<NodeNavigatable> myCurrentResults = SetSequence.fromSet(new LinkedHashSet<NodeNavigatable>());
  private volatile boolean myFinished = false;

  public BackgroundSearchWithPopupTask(@NotNull PopupSettingsBuilder settings) {
    super(settings.myProject, settings.query, settings.finders, "Searching...");
    mySettings = settings;
    final GoToContextMenuHelperBase.ContextMenuComposite<NodeNavigatable> contextMenuComposite = new GoToContextMenuHelper(settings.myProject, settings.captionFun, settings.renderer, settings.comparator, settings.nameFilter).buildPopup();
    myPopup = contextMenuComposite.myPopup;
    myList = contextMenuComposite.myJBList;
    myListModel = contextMenuComposite.myListModel;
  }

  @Override
  public void run(@NotNull final ProgressIndicator indicator) {
    myList.setPaintBusy(true);
    super.run(indicator);
  }

  @Override
  public boolean isCancelled() {
    return super.isCancelled() || myPopup.isDisposed();
  }

  @Override
  public void onUsageFound(@NotNull SearchResult<?> result) {
    if (myPopup.isDisposed()) {
      return;
    }
    Object object = result.getObject();
    if (object instanceof SNode) {
      synchronized (LOCK) {
        SNodeReference pointer = ((SNode) object).getReference();
        NodeNavigatable newNavigatable = new NodeNavigatable(mySettings.myProject, pointer);
        if (SetSequence.fromSet(myCurrentResults).addElement(newNavigatable) != null) {
          myAlarm.addRequest(new Runnable() {
            @Override
            public void run() {
              myAlarm.cancelAllRequests();
              refresh();
            }
          }, 200, ModalityState.stateForComponent(myPopup.getContent()));
        }
      }
    }
  }

  private void refresh() {
    if (isCancelled()) {
      return;
    }
    if (myPopup.isDisposed()) {
      return;
    }
    final List<NodeNavigatable> newData;
    synchronized (LOCK) {
      newData = new ArrayList<NodeNavigatable>(myCurrentResults);
    }
    List<NodeNavigatable> showingItems = myListModel.getItems();
    newData.removeAll(showingItems);
    // fix comparator needs read, could transfer the name into a NamedNodeNavigatable composite instead
    mySettings.myProject.getModelAccess().runReadAction(new Runnable() {
      public void run() {
        Object selected = myList.getSelectedValue();
        myListModel.addAll(newData);
        myList.setSelectedValue(selected, true);
      }
    });
    String newCaption = mySettings.captionFun.caption(SetSequence.fromSet(myCurrentResults).count(), myFinished);
    myPopup.setCaption(newCaption);
    myPopup.pack(true, true);
    if (!(myShown.get())) {
      myShown.set(true);
      myPopup.show(mySettings.point);
    }
  }

  @Override
  public void onFinished() {
    ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
    if (progress != null) {
      progress.cancel();
    }
    if (isCancelled()) {
      return;
    }
    if (myPopup.isDisposed()) {
      return;
    }
    myFinished = true;
    if (SetSequence.fromSet(myCurrentResults).isEmpty()) {
      ToolWindowManager.getInstance(myProject).notifyByBalloon("Usages", MessageType.INFO, "No usages found in the global scope");
    } else if (SetSequence.fromSet(myCurrentResults).count() == 1) {
      myPopup.cancel();
      NodeNavigatable navigatable = SetSequence.fromSet(myCurrentResults).first();
      navigatable.navigate(true);
    } else {
      refresh();
      myList.setPaintBusy(false);
    }
  }
}
