package games.strategy.thread;

import java.util.ArrayDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import games.strategy.util.ThreadUtil;

/**
 * An ExecutorService backed thread pool.
 */
public class ThreadPool {
  private final ExecutorService executorService;
  private final ArrayDeque<Future<?>> futuresStack = new ArrayDeque<>();

  /**
   * Creates a new instance of ThreadPool max is the maximum number of threads the pool can have. The pool may have
   * fewer threads at any given time.
   */
  public ThreadPool(final int max) {
    if (max < 1) {
      throw new IllegalArgumentException("Max must be >= 1, instead its:" + max);
    }
    executorService = Executors.newFixedThreadPool(max);
  }


  /**
   * Run the given task.
   */
  public void runTask(final Runnable task) {
    futuresStack.push(executorService.submit(task));
  }


  /**
   * Returns when all tasks run through the runTask method have finished.
   */
  public void waitForAll() {
    while (!futuresStack.isEmpty()) {
      if (futuresStack.peek().isDone()) {
        futuresStack.pop();
      } else {
        ThreadUtil.sleep(5);
      }
    }
  }

  /**
   * Shutdown the thread pool. Currently running tasks will finish, but new tasks will not start.
   * All threads will shutdown after finishing any tasks they may be currently running.
   * A call to shutDown() followed by waitForAll() will ensure that no threads are running.
   */
  public void shutDown() {
    executorService.shutdown();
  }

}
