// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.wm.impl;

import com.intellij.ProjectTopics;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ex.ToolWindowManagerEx;
import com.intellij.openapi.wm.ext.LibraryDependentToolWindow;
import com.intellij.util.concurrency.SequentialTaskExecutor;
import com.intellij.util.messages.MessageBusConnection;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.Executor;

public class LibraryDependentToolWindowManager implements StartupActivity {

  private static final Executor ourExecutor =
    SequentialTaskExecutor.createSequentialApplicationPoolExecutor("LibraryDependentToolWindowManager");

  @Override
  public void runActivity(@NotNull Project project) {
    final Application application = ApplicationManager.getApplication();
    if (application.isUnitTestMode() ||
        application.isHeadlessEnvironment()) {
      return;
    }

    final ModuleRootListener rootListener = new ModuleRootListener() {
      @Override
      public void rootsChanged(@NotNull ModuleRootEvent event) {
        checkToolWindowStatuses(project);
      }
    };

    checkToolWindowStatuses(project);

    final MessageBusConnection connection = project.getMessageBus().connect();
    connection.subscribe(ProjectTopics.PROJECT_ROOTS, rootListener);
  }

  private static void checkToolWindowStatuses(@NotNull final Project project) {
    final ModalityState currentModalityState = ModalityState.current();

    ourExecutor.execute(() -> doCheckToolWindowStatuses(project, currentModalityState));
  }

  private static void doCheckToolWindowStatuses(@NotNull final Project project,
                                                ModalityState currentModalityState) {
    final DumbService dumbService = ReadAction.compute(() -> project.isDisposed() ? null : DumbService.getInstance(project));
    if (dumbService == null) return;

    for (LibraryDependentToolWindow libraryToolWindow : LibraryDependentToolWindow.EXTENSION_POINT_NAME.getExtensionList()) {
      Ref<Boolean> libraryExists = Ref.create(false);
      Runnable runnable = () -> {
        final Boolean exists = dumbService.runReadActionInSmartMode(() ->
                                                                      !project.isDisposed() &&
                                                                      libraryToolWindow.getLibrarySearchHelper().isLibraryExists(project));
        libraryExists.set(exists);
      };
      while (!project.isDisposed()) {
        boolean finished = ProgressIndicatorUtils.runWithWriteActionPriority(runnable, new ProgressIndicatorBase());
        if (finished) {
          break;
        }
        ProgressIndicatorUtils.yieldToPendingWriteActions();
      }

      ApplicationManager.getApplication().invokeLater(() -> {
        final ToolWindowManagerEx toolWindowManagerEx = ToolWindowManagerEx.getInstanceEx(project);
        ToolWindow toolWindow = toolWindowManagerEx.getToolWindow(libraryToolWindow.id);

        if (libraryExists.get()) {
          if (toolWindow == null) {
            toolWindowManagerEx.initToolWindow(libraryToolWindow);
          }
        }
        else {
          if (toolWindow != null) {
            toolWindowManagerEx.unregisterToolWindow(libraryToolWindow.id);
          }
        }
      }, currentModalityState, project.getDisposed());
    }
  }
}

@@ -432,188 +432,8 @@
 on;%0A
-import com.intellij.openapi.progress.util.ProgressIndicatorBase;%0Aimport com.intellij.openapi.progress.util.ProgressIndicatorUtils;%0Aimport com.intellij.openapi.project.DumbService;%0A
 impo
@@ -635,46 +635,8 @@
 ty;%0A
-import com.intellij.openapi.util.Ref;%0A
 impo
@@ -853,16 +853,67 @@
 ecutor;%0A
+import com.intellij.util.containers.ContainerUtil;%0A
 import c
@@ -999,24 +999,73 @@
 s.NotNull;%0A%0A
+import java.util.HashSet;%0Aimport java.util.List;%0A
 import java.
@@ -1975,31 +1975,24 @@
 %0A%0A  private 
-static 
 void checkTo
@@ -2123,437 +2123,13 @@
     
-ourExecutor.execute(() -%3E doCheckToolWindowStatuses(project, currentModalityState));%0A  %7D%0A%0A  private static void doCheckToolWindowStatuses(@NotNull final Project project,%0A                                                ModalityState currentModalityState) %7B%0A    final DumbService dumbService = ReadAction.compute(() -%3E project.isDisposed() ? null : DumbService.getInstance(project));%0A    if (dumbService == null) return;%0A%0A    for (
+List%3C
 Libr
@@ -2154,28 +2154,22 @@
 ndow
- libraryToolWindow :
+%3E extensions =
  Lib
@@ -2235,355 +2235,108 @@
 st()
-) %7B%0A      Ref%3CBoolean%3E libraryExists = Ref.create(false);%0A      Runnable runnable = () -%3E %7B%0A        final Boolean exists = dumbService.runReadActionInSmartMode(() -%3E%0A                                                                      !project.isDisposed() &&%0A                                                                      libraryToolWindo
+;%0A%0A    ReadAction%0A      .nonBlocking(() -%3E new HashSet%3C%3E(ContainerUtil.findAll(extensions, ltw -%3E lt
 w.ge
@@ -2387,386 +2387,117 @@
 ct))
+)
-;
+)
 %0A      
-  libraryExists.set(exists);%0A      %7D;%0A      while (!project.isDisposed()) %7B%0A        boolean finished = ProgressIndicatorUtils.runWithWriteActionPriority(runnable, new ProgressIndicatorBase());%0A        if (finished) %7B%0A          break;%0A        %7D%0A        ProgressIndicatorUtils.yieldToPendingWriteActions();%0A      %7D%0A%0A      ApplicationManager.getApplication().invokeLater(()
+.inSmartMode(project)%0A      .coalesceBy(this)%0A      .finishOnUiThread(currentModalityState, existing
  -%3E 
@@ -2506,22 +2506,16 @@
         
-final 
 ToolWind
@@ -2588,24 +2588,100 @@
 x(project);%0A
+        for (LibraryDependentToolWindow libraryToolWindow : extensions) %7B%0A  
         Tool
@@ -2757,17 +2757,18 @@
 ow.id);%0A
-%0A
+  
         
@@ -2775,31 +2775,50 @@
 if (
-libraryExists.get(
+existing.contains(libraryToolWindow
 )) %7B%0A
+  
     
@@ -2853,32 +2853,34 @@
 ) %7B%0A            
+ 
+ 
 toolWindowManage
@@ -2920,34 +2920,38 @@
 dow);%0A          
-%7D%0A
+  %7D%0A  
         %7D%0A      
@@ -2956,15 +2956,19 @@
     
+ 
+ 
 else %7B%0A
+  
     
@@ -2991,32 +2991,34 @@
 ndow != null) %7B%0A
+  
             tool
@@ -3079,34 +3079,38 @@
 .id);%0A          
-%7D%0A
+  %7D%0A  
         %7D%0A      
@@ -3113,65 +3113,52 @@
     
-%7D, currentModalityState, project.getDisposed());%0A    %7D%0A  %7D
+  %7D%0A      %7D)%0A      .submit(ourExecutor);%0A  %7D%0A
 %0A%7D%0A

use ReadAction.nonBlocking