package sbt

/**
 * Processes progress events during task execution.
 * All methods are called from the same thread except `started` and `finished`,
 * which is called from the executing task's thread.
 * All methods should return quickly to avoid task execution overhead.
 *
 * This class is experimental and subject to binary and source incompatible changes at any time.
 */
private[sbt] trait ExecuteProgress[A[_]] {
  type S
  def initial: S

  /**
   * Notifies that a `task` has been registered in the system for execution.
   * The dependencies of `task` are `allDeps` and the subset of those dependencies that
   * have not completed are `pendingDeps`.
   */
  def registered(state: S, task: A[_], allDeps: Iterable[A[_]], pendingDeps: Iterable[A[_]]): S

  /**
   * Notifies that all of the dependencies of `task` have completed and `task` is therefore
   * ready to run.  The task has not been scheduled on a thread yet.
   */
  def ready(state: S, task: A[_]): S

  /**
   * Notifies that the work for `task` is starting after this call returns.
   * This is called from the thread the task executes on, unlike most other methods in this callback.
   * It is called immediately before the task's work starts with minimal intervening executor overhead.
   */
  def workStarting(task: A[_]): Unit

  /**
   * Notifies that the work for `task` work has finished.  The task may have computed the next task to
   * run, in which case `result` contains that next task wrapped in Left.  If the task produced a value
   * or terminated abnormally, `result` provides that outcome wrapped in Right.  The ultimate result of
   * a task is provided to the `completed` method.
   * This is called from the thread the task executes on, unlike most other methods in this callback.
   * It is immediately called after the task's work is complete with minimal intervening executor overhead.
   */
  def workFinished[T](task: A[T], result: Either[A[T], Result[T]]): Unit

  /**
   * Notifies that `task` has completed.
   * The task's work is done with a final `result`.
   * Any tasks called by `task` have completed.
   */
  def completed[T](state: S, task: A[T], result: Result[T]): S

  /** All tasks have completed with the final `results` provided. */
  def allCompleted(state: S, results: RMap[A, Result]): S
}

/** This module is experimental and subject to binary and source incompatible changes at any time. */
private[sbt] object ExecuteProgress {
  def empty[A[_]]: ExecuteProgress[A] = new ExecuteProgress[A] {
    type S = Unit
    def initial = ()
    def registered(state: Unit, task: A[_], allDeps: Iterable[A[_]], pendingDeps: Iterable[A[_]]) = ()
    def ready(state: Unit, task: A[_]) = ()
    def workStarting(task: A[_]) = ()
    def workFinished[T](task: A[T], result: Either[A[T], Result[T]]) = ()
    def completed[T](state: Unit, task: A[T], result: Result[T]) = ()
    def allCompleted(state: Unit, results: RMap[A, Result]) = ()
  }
}