package tpnote;
import java.util.Objects;

public class ComputationGroup {
  /**
   * A function that compute a value. The computation can be interrupted,
   * in that case an {@code InterruptedException} will be raised.
   */
  public interface Computation {
    /**
     * Returns the result of the computation.
     * @return the result of the computation.
     * @throws InterruptedException if the computation is interrupted.
     */
    public int result() throws InterruptedException;
  }
  
  static class Worker implements Computation, Runnable {
    private final Computation computation;
    private int result;
    
    Worker(Computation calculation) {
      this.computation = calculation;
    }
    
    @Override
    public int result() throws InterruptedException {
      //TODO
      return result;
    }
    
    @Override
    public void run() {
      //TODO
    }
    
    // TODO
  }
  
  /**
   * Execute the computation in a new thread.
   * @param computation the computation to execute.
   * @return a view of the computation that will block if the
   *   result of the computation taken as parameter is not finished.
   */
  public Computation executeAsync(Computation computation) {
    Objects.requireNonNull(computation);
    Worker worker = new Worker(computation);
    // ... new Thread(...)
    // TODO
    return worker;
  }
  
  /**
   * Stop all computations started using {@link #executeAsync(Computation)}
   * by trying to interrupt them. A computation interrupted by  {@code stopAll}
   * should throw {@code InterruptedException} when {@link Computation#result()}
   * is called.
   */
  public void stopAll() {
    // TODO
  }
  
  public static void main(String[] args) throws InterruptedException {
    ComputationGroup group = new ComputationGroup();
    Computation computation = group.executeAsync(() -> {
      Thread.sleep(5);
      return 42;
    });
    //group.stopAll();
    System.out.println(computation.result());
  }
}
