/*
 * Copyright 2000-2011 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.util;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.InvocationTargetException;

/**
 * Allows to execute {@link SequentialTask} under modal progress.
 * 
 * @author Denis Zhdanov
 * @since 9/27/11 2:52 PM
 */
public class SequentialModalProgressTask extends Task.Modal {
  private static final Logger LOG = Logger.getInstance("#" + SequentialModalProgressTask.class.getName());
  
  private static final long DEFAULT_MIN_ITERATION_MIN_TIME = 500;

  /**
   * We want to perform the task by big chunks at EDT. However, there is a possible case that particular task iteration
   * is executed in short amount of time. Hence, we may want to execute more than one chunk during single EDT iteration.
   * This field holds min amount of time (in milliseconds) to spend to performing the task.
   */
  private long myMinIterationTime = DEFAULT_MIN_ITERATION_MIN_TIME;

  private final String myTitle;

  private ProgressIndicator myIndicator;
  private SequentialTask myTask;

  public SequentialModalProgressTask(@Nullable Project project, @NotNull String title) {
    this(project, title, true);
  }

  public SequentialModalProgressTask(@Nullable Project project, @NotNull String title, boolean canBeCancelled) {
    super(project, title, canBeCancelled);
    myTitle = title;
  }

  @Override
  public void run(@NotNull ProgressIndicator indicator) {
    try {
      doRun(indicator);
    }
    catch (Exception e) {
      LOG.info("Unexpected exception occurred during processing sequential task '" + myTitle + "'", e);
    }
    finally {
      indicator.stop();
    }
  }

  public void doRun(@NotNull ProgressIndicator indicator) throws InvocationTargetException, InterruptedException {
    final SequentialTask task = myTask;
    if (task == null) {
      return;
    }
    
    myIndicator = indicator;
    indicator.setIndeterminate(false);
    prepare(task);
    
    // We need to sync background thread and EDT here in order to avoid situation when event queue is full of processing requests.
    while (!task.isDone()) {
      if (indicator.isCanceled()) {
        task.stop();
        break;
      }
      UIUtil.invokeAndWaitIfNeeded(new Runnable() {
        @Override
        public void run() {
          long start = System.currentTimeMillis();
          try {
            while (!task.isDone() && System.currentTimeMillis() - start < myMinIterationTime) {
              task.iteration();
            }
          }
          catch (RuntimeException e) {
            task.stop();
            throw e;
          }
        }
      });
      //if (ApplicationManager.getApplication().isDispatchThread()) {
      //  runnable.run();
      //}
      //else {
      //  ApplicationManagerEx.getApplicationEx().suspendReadAccessAndRunWriteAction(runnable);
      //}
    }
  }

  public void setMinIterationTime(long minIterationTime) {
    myMinIterationTime = minIterationTime;
  }

  public void setTask(@Nullable SequentialTask task) {
    myTask = task;
  }
  
  public ProgressIndicator getIndicator() {
    return myIndicator;
  }

  /**
   * Executes preliminary jobs prior to the target sequential task processing ({@link SequentialTask#prepare()} by default).
   * 
   * @param task  task to be executed
   */
  protected void prepare(@NotNull SequentialTask task) {
    task.prepare();
  }
}

@@ -622,16 +622,76 @@
 .util;%0A%0A
+import com.intellij.openapi.application.ApplicationManager;%0A
 import c
@@ -877,44 +877,8 @@
 ct;%0A
-import com.intellij.util.ui.UIUtil;%0A
 impo
@@ -3051,102 +3051,66 @@
     
-UIUtil.invokeAndWaitIfNeeded(new Runnable() %7B%0A        @Override%0A        public void run()
+ApplicationManager.getApplication().invokeAndWait(() -%3E
  %7B%0A
-  
     
@@ -3162,26 +3162,22 @@
         
-  
 try %7B%0A
-  
         
@@ -3270,26 +3270,24 @@
             
-  
 task.iterati
@@ -3294,38 +3294,34 @@
 on();%0A          
-  %7D%0A  
+%7D%0A
         %7D%0A      
@@ -3322,18 +3322,16 @@
         
-  
 catch (R
@@ -3357,26 +3357,24 @@
 %7B%0A          
-  
 task.stop();
@@ -3384,18 +3384,16 @@
         
- 
- 
 throw e;
@@ -3405,258 +3405,49 @@
     
-  %7D%0A  
+%7D%0A
       %7D
-%0A      %7D);%0A      //if (ApplicationManager.getApplication().isDispatchThread()) %7B%0A      //  runnable.run();%0A      //%7D%0A      //else %7B%0A      //  ApplicationManagerEx.getApplicationEx().suspendReadAccessAndRunWriteAction(runnable);%0A      //%7D
+, indicator.getModalityState());
 %0A   

use invokeLater with progress's modality state