/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.dv8tion.jda.internal.utils.concurrent.task;

import net.dv8tion.jda.api.utils.concurrent.Task;
import net.dv8tion.jda.internal.requests.WebSocketClient;
import net.dv8tion.jda.internal.utils.Checks;

import javax.annotation.Nonnull;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;

public class GatewayTask<T> implements Task<T>
{
    private final Runnable onCancel;
    private final CompletableFuture<T> future;
    private Consumer<? super T> success;
    private Consumer<? super Throwable> failure;

    public GatewayTask(CompletableFuture<T> future, Runnable onCancel)
    {
        this.future = future;
        this.onCancel = onCancel;
    }

    @Override
    public boolean isStarted()
    {
        return true;
    }

    @Nonnull
    @Override
    public Task<T> onError(@Nonnull Consumer<? super Throwable> callback)
    {
        Checks.notNull(callback, "Callback");
        future.exceptionally(error -> {
            callback.accept(error);
            return null;
        });
        return this;
    }

    @Nonnull
    @Override
    public Task<T> onSuccess(@Nonnull Consumer<? super T> callback)
    {
        Checks.notNull(callback, "Callback");
        future.thenAccept(callback);
        return this;
    }

    @Nonnull
    @Override
    public T get()
    {
        if (WebSocketClient.WS_THREAD.get())
            throw new UnsupportedOperationException("Blocking operations are not permitted on the gateway thread");
        return future.join();
    }

    @Override
    public void cancel()
    {
        onCancel.run();
    }
}

@@ -704,16 +704,72 @@
 .task;%0A%0A
+import net.dv8tion.jda.api.exceptions.ContextException;%0A
 import n
@@ -913,16 +913,90 @@
 .Checks;
+%0Aimport net.dv8tion.jda.internal.utils.JDALogger;%0Aimport org.slf4j.Logger;
 %0A%0Aimport
@@ -1155,16 +1155,84 @@
 sk%3CT%3E%0A%7B%0A
+    private static final Logger log = JDALogger.getLog(Task.class);%0A
     priv
@@ -1310,98 +1310,8 @@
 ure;
-%0A    private Consumer%3C? super T%3E success;%0A    private Consumer%3C? super Throwable%3E failure;
 %0A%0A  
@@ -1680,32 +1680,166 @@
 k, %22Callback%22);%0A
+        Consumer%3CThrowable%3E failureHandler = ContextException.here((error) -%3E log.error(%22Task Failure callback threw error%22, error));%0A
         future.e
@@ -1862,16 +1862,50 @@
 or -%3E %7B%0A
+            try%0A            %7B%0A    
         
@@ -1932,16 +1932,201 @@
 error);%0A
+            %7D%0A            catch (Throwable e)%0A            %7B%0A                failureHandler.accept(e);%0A                if (e instanceof Error)%0A                    throw e;%0A            %7D%0A
         
@@ -2341,34 +2341,453 @@
     
-future.thenAccept(callback
+Consumer%3CThrowable%3E failureHandler = ContextException.here((error) -%3E log.error(%22Task Success callback threw error%22, error));%0A        future.thenAccept(result -%3E %7B%0A            try%0A            %7B%0A                callback.accept(result);%0A            %7D%0A            catch (Throwable error)%0A            %7B%0A                failureHandler.accept(error);%0A                if (error instanceof Error)%0A                    throw error;%0A            %7D%0A        %7D
 );%0A 

Add error logging for callbacks in GatewayTask