// Path: core/src/main/java/com/github/phantomthief/util/ThrowableConsumer.java
// @FunctionalInterface
// public interface ThrowableConsumer<T, X extends Throwable> {
// 
//     void accept(T t) throws X;
// 
//     default ThrowableConsumer<T, X> andThen(ThrowableConsumer<? super T, X> after) {
//         requireNonNull(after);
//         return t -> {
//             accept(t);
//             after.accept(t);
//         };
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableRunnable.java
// @FunctionalInterface
// public interface ThrowableRunnable<X extends Throwable> {
// 
//     void run() throws X;
// }


import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableRunnable;
import com.google.common.util.concurrent.ForwardingListenableFuture;
import com.google.common.util.concurrent.ListenableFuture;
package com.github.phantomthief.concurrent;






/**
 * @author w.vela
 * Created on 16/5/31.
 */
public class TimeoutListenableFuture<V> extends ForwardingListenableFuture<V> {

    private static final Logger logger = getLogger(TimeoutListenableFuture.class);

    private final ListenableFuture<V> delegate;
    private final List<ThrowableConsumer<TimeoutException, Exception>> timeoutListeners = new ArrayList<>();

    /**
     * better use {@link #timeoutListenableFuture(ListenableFuture)}
     */
    public TimeoutListenableFuture(ListenableFuture<V> delegate) {
        this.delegate = delegate;
    }

    public static <V> TimeoutListenableFuture<V>
            timeoutListenableFuture(ListenableFuture<V> delegate) {
        if (delegate instanceof TimeoutListenableFuture) {
            return (TimeoutListenableFuture<V>) delegate;
        } else {
            return new TimeoutListenableFuture<>(delegate);
        }
    }

    @Override
    protected ListenableFuture<V> delegate() {
        return delegate;
    }

    public TimeoutListenableFuture<V>
            addTimeoutListener(@Nonnull ThrowableRunnable<Exception> listener) {
        checkNotNull(listener);
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableConsumer.java
// @FunctionalInterface
// public interface ThrowableConsumer<T, X extends Throwable> {
// 
//     void accept(T t) throws X;
// 
//     default ThrowableConsumer<T, X> andThen(ThrowableConsumer<? super T, X> after) {
//         requireNonNull(after);
//         return t -> {
//             accept(t);
//             after.accept(t);
//         };
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableRunnable.java
// @FunctionalInterface
// public interface ThrowableRunnable<X extends Throwable> {
// 
//     void run() throws X;
// }


// Path: core/src/main/java/com/github/phantomthief/concurrent/TimeoutListenableFuture.java
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import javax.annotation.Nonnull;
import org.slf4j.Logger;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableRunnable;
import com.google.common.util.concurrent.ForwardingListenableFuture;
import com.google.common.util.concurrent.ListenableFuture;

package com.github.phantomthief.concurrent;






/**
 * @author w.vela
 * Created on 16/5/31.
 */
public class TimeoutListenableFuture<V> extends ForwardingListenableFuture<V> {

    private static final Logger logger = getLogger(TimeoutListenableFuture.class);

    private final ListenableFuture<V> delegate;
    private final List<ThrowableConsumer<TimeoutException, Exception>> timeoutListeners = new ArrayList<>();

    /**
     * better use {@link #timeoutListenableFuture(ListenableFuture)}
     */
    public TimeoutListenableFuture(ListenableFuture<V> delegate) {
        this.delegate = delegate;
    }

    public static <V> TimeoutListenableFuture<V>
            timeoutListenableFuture(ListenableFuture<V> delegate) {
        if (delegate instanceof TimeoutListenableFuture) {
            return (TimeoutListenableFuture<V>) delegate;
        } else {
            return new TimeoutListenableFuture<>(delegate);
        }
    }

    @Override
    protected ListenableFuture<V> delegate() {
        return delegate;
    }

    public TimeoutListenableFuture<V>
            addTimeoutListener(@Nonnull ThrowableRunnable<Exception> listener) {
        checkNotNull(listener);
        return addTimeoutListener(e -> listener.run());