package org.ddd4j.infrastructure.scheduler;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiFunction;

import org.ddd4j.Require;
import org.ddd4j.Throwing.TFunction;
import org.ddd4j.infrastructure.Promise;

public class Task<T, R> implements Future<R>, Promise<R> {

	private final Executor executor;
	private final TFunction<? super T, ? extends R> action;
	private final CompletableFuture<R> future;

	public Task(Executor executor, TFunction<? super T, ? extends R> action) {
		this.executor = Require.nonNull(executor);
		this.action = Require.nonNull(action);
		this.future = new CompletableFuture<>();
	}

	@Override
	public <X> X apply(BiFunction<Executor, CompletionStage<R>, X> fn) {
		return fn.apply(executor, future);
	}

	@Override
	public boolean cancel(boolean mayInterruptIfRunning) {
		return future.cancel(mayInterruptIfRunning);
	}

	public boolean executeWith(T state) {
		if (future.isCancelled()) {
			return false;
		}
		try {
			R result = action.applyChecked(state);
			return future.complete(result);
		} catch (Throwable e) {
			return future.completeExceptionally(e);
		}
	}

	@Override
	public R get() throws InterruptedException, ExecutionException {
		return future.get();
	}

	@Override
	public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
		return future.get(timeout, unit);
	}

	@Override
	public boolean isCancelled() {
		return future.isCancelled();
	}

	@Override
	public boolean isDone() {
		return future.isDone();
	}

	@Override
	public CompletionStage<R> toCompletionStage() {
		return future;
	}
}
@@ -908,17 +908,26 @@
 lic %3CX%3E 
-X
+Promise%3CX%3E
  apply(B
@@ -970,25 +970,63 @@
 R%3E, 
-X%3E fn) %7B%0A%09%09return
+CompletionStage%3CX%3E%3E fn) %7B%0A%09%09return Promise.of(executor,
  fn.
@@ -1048,16 +1048,17 @@
  future)
+)
 ;%0A%09%7D%0A%0A%09@

fix task