/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.openapi.progress;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayDeque;
import java.util.Queue;

@SomeQueue
public class ProgressManagerQueue {
  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.progress.AbstractTaskQueue");

  private final ProgressManager myProgressManager;
  private final Task.Backgroundable myQueuePollTask;
  private final Object myLock;
  private final Queue<Runnable> myQueue;
  private final Runnable myQueueWorker;
  private volatile boolean myIsStarted;
  private boolean myActive;

  public ProgressManagerQueue(@NotNull Project project, @NotNull String title) {
    myLock = new Object();
    myQueue = new ArrayDeque<Runnable>();
    myActive = false;
    myQueueWorker = new MyWorker();
    myProgressManager = ProgressManager.getInstance();
    myQueuePollTask = new Task.Backgroundable(project, title) {
      @Override
      public void run(@NotNull ProgressIndicator indicator) {
        myQueueWorker.run();
      }
    };
  }

  public void start() {
    myIsStarted = true;
    runMe();
  }

  /**
   * !!! done under lock! (to allow single failures when putting into the execution queue)
   * Should run {@link #myQueueWorker}
   */
  protected void runMe() {
    if (!myIsStarted) return;
    if (ApplicationManager.getApplication().isDispatchThread()) {
      if (!myQueuePollTask.myProject.isDisposed()) {
        myProgressManager.run(myQueuePollTask);
      }
    }
    else {
      ApplicationManager.getApplication().invokeLater(new Runnable() {
        @Override
        public void run() {
          if (!myQueuePollTask.myProject.isDisposed()) {
            myProgressManager.run(myQueuePollTask);
          }
        }
      });
    }
  }

  protected void runStuff(final Runnable stuff) {
    try {
      stuff.run();
    }
    catch (ProcessCanceledException e) {
      //
    }
  }

  public void run(@NotNull final Runnable stuff) {
    if (ApplicationManager.getApplication().isUnitTestMode()) {
      runStuff(stuff);
      return;
    }
    synchronized (myLock) {
      try {
        myQueue.add(stuff);
        if (!myActive) {
          runMe();
        }
      }
      catch (Throwable t) {
        LOG.info(t);
        throw t instanceof RuntimeException ? ((RuntimeException)t) : new RuntimeException(t);
      }
      finally {
        myActive = true;
      }
    }
  }

  public boolean isEmpty() {
    synchronized (myLock) {
      if (myQueue.isEmpty()) {
        myActive = false;
        return true;
      }
    }
    return false;
  }

  private class MyWorker implements Runnable {
    @Override
    public void run() {
      while (true) {
        try {
          final Runnable stuff;
          synchronized (myLock) {
            stuff = myQueue.poll();
          }
          if (stuff != null) {
            // each task is executed only once, once it has been taken from the queue..
            runStuff(stuff);
          }
        }
        catch (Throwable t) {
          LOG.info(t);
        }
        finally {
          if (isEmpty()) return;
        }
      }
    }
  }
}

@@ -1986,31 +1986,29 @@
 %7D%0A   */%0A  pr
-otec
+iva
 te
-d
  void runMe(
@@ -2510,15 +2510,20 @@
   pr
-otected
+ivate static
  voi
@@ -3157,180 +3157,8 @@
  %7D%0A%0A
-  public boolean isEmpty() %7B%0A    synchronized (myLock) %7B%0A      if (myQueue.isEmpty()) %7B%0A        myActive = false;%0A        return true;%0A      %7D%0A    %7D%0A    return false;%0A  %7D%0A%0A
   pr
@@ -3630,32 +3630,68 @@
       finally %7B%0A
+          synchronized (myLock) %7B%0A  
           if (is
@@ -3688,16 +3688,24 @@
     if (
+myQueue.
 isEmpty(
@@ -3707,23 +3707,97 @@
 mpty()) 
-return;
+%7B%0A              myActive = false;%0A              return;%0A            %7D%0A          %7D
 %0A       

make private methods private, inline a confusing method