// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.common.util;

import java.util.logging.Level;
import com.hypixel.hytale.logger.HytaleLogger;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CancellationException;
import javax.annotation.Nonnull;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;

public class CompletableFutureUtil
{
    public static final Function<Throwable, ?> fn;
    
    @Nonnull
    public static <T> CompletableFuture<T> whenComplete(@Nonnull final CompletableFuture<T> future, @Nonnull final CompletableFuture<T> callee) {
        return future.whenComplete((result, throwable) -> {
            if (throwable != null) {
                callee.completeExceptionally(throwable);
            }
            else {
                callee.complete(result);
            }
        });
    }
    
    public static boolean isCanceled(final Throwable throwable) {
        return throwable instanceof CancellationException || (throwable instanceof CompletionException && throwable.getCause() != null && throwable.getCause() != throwable && isCanceled(throwable.getCause()));
    }
    
    @Nonnull
    public static <T> CompletableFuture<T> _catch(@Nonnull final CompletableFuture<T> future) {
        return future.exceptionally((Function<Throwable, ? extends T>)CompletableFutureUtil.fn);
    }
    
    @Nonnull
    public static <T> CompletableFuture<T> completionCanceled() {
        final CompletableFuture<T> out = new CompletableFuture<T>();
        out.cancel(false);
        return out;
    }
    
    public static void joinWithProgress(@Nonnull final List<CompletableFuture<?>> list, @Nonnull final ProgressConsumer callback, final int millisSleep, final int millisProgress) throws InterruptedException {
        final CompletableFuture<?> all = CompletableFuture.allOf((CompletableFuture<?>[])list.toArray(CompletableFuture[]::new));
        long last = System.nanoTime();
        final long nanosProgress = TimeUnit.MILLISECONDS.toNanos(millisProgress);
        final int listSize = list.size();
        while (!all.isDone()) {
            Thread.sleep(millisSleep);
            final long now;
            if (last + nanosProgress < (now = System.nanoTime())) {
                last = now;
                int done = 0;
                for (final CompletableFuture c : list) {
                    if (c.isDone()) {
                        ++done;
                    }
                }
                if (done >= listSize) {
                    continue;
                }
                callback.accept(done / (double)listSize, done, listSize);
            }
        }
        callback.accept(1.0, listSize, listSize);
        all.join();
    }
    
    static {
        fn = (throwable -> {
            if (!(throwable instanceof TailedRuntimeException)) {
                HytaleLogger.getLogger().at(Level.SEVERE).withCause(throwable).log("Unhandled exception! " + String.valueOf(Thread.currentThread()));
            }
            throw new TailedRuntimeException(throwable);
        });
    }
    
    static class TailedRuntimeException extends RuntimeException
    {
        public TailedRuntimeException(final Throwable cause) {
            super(cause);
        }
    }
    
    @FunctionalInterface
    public interface ProgressConsumer
    {
        void accept(final double p0, final int p1, final int p2);
    }
}
