package org.infinispan.remoting.transport.jgroups;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.function.BiConsumer;

import org.infinispan.remoting.responses.Response;
import org.jgroups.SuspectedException;
import org.jgroups.util.Rsp;

/**
 * @author Dan Berindei
 * @since 8.0
 */
public class SingleResponseFuture extends CompletableFuture<Rsp<Response>>
      implements BiConsumer<Response, Throwable>, Callable<Void> {
   private final CompletableFuture<Response> request;
   private volatile Future<?> timeoutFuture = null;

   SingleResponseFuture(CompletableFuture<Response> request) {
      this.request = request;
      request.whenComplete(this);
   }

   private void requestDone(Response response, Throwable throwable) {
      if (throwable == null) {
         complete(new Rsp<>(response));
      } else if (throwable instanceof SuspectedException) {
         Rsp<Response> rsp = new Rsp<>();
         rsp.setSuspected();
         complete(rsp);
      } else {
         complete(new Rsp<>(throwable));
      }
      if (timeoutFuture != null) {
         timeoutFuture.cancel(false);
      }
   }

   public void setTimeoutFuture(Future<?> timeoutFuture) {
      this.timeoutFuture = timeoutFuture;
      if (isDone()) {
         timeoutFuture.cancel(false);
      }
   }

   @Override
   public Void call() throws Exception {
      // The request timed out
      complete(new Rsp<>());
      request.cancel(false);
      return null;
   }

   @Override
   public void accept(Response response, Throwable throwable) {
      requestDone(response, throwable);
   }
}
