/*
 * Copyright (c) 2015 Spotify AB.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 com.spotify.heroic.common;

import com.spotify.heroic.ws.InternalErrorMessage;
import eu.toolchain.async.AsyncFuture;
import eu.toolchain.async.FutureDone;
import lombok.extern.slf4j.Slf4j;

import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.CompletionCallback;
import javax.ws.rs.container.ConnectionCallback;
import javax.ws.rs.container.TimeoutHandler;
import javax.ws.rs.core.Response;

@Slf4j
public final class CoreJavaxRestFramework implements JavaxRestFramework {
    @Override
    public <T> void bind(final AsyncResponse response, final AsyncFuture<T> callback) {
        this.<T, T>bind(response, callback, this.<T>passthrough());
    }

    /**
     * Helper function to correctly wire up async response management.
     *
     * @param response The async response object.
     * @param callback Callback for the pending request.
     * @param resume The resume implementation.
     */
    @Override
    public <T, R> void bind(
        final AsyncResponse response, final AsyncFuture<T> callback, final Resume<T, R> resume
    ) {
        callback.onDone(new FutureDone<T>() {
            @Override
            public void failed(Throwable e) throws Exception {
                log.error("Request failed", e);
                response.resume(Response
                    .status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(new InternalErrorMessage(e.getMessage(),
                        Response.Status.INTERNAL_SERVER_ERROR))
                    .build());
            }

            @Override
            public void resolved(T result) throws Exception {
                if (response.isDone()) {
                    return;
                }

                response.resume(
                    Response.status(Response.Status.OK).entity(resume.resume(result)).build());
            }

            @Override
            public void cancelled() throws Exception {
                log.error("Request cancelled");
                response.resume(Response
                    .status(Response.Status.INTERNAL_SERVER_ERROR)
                    .entity(new InternalErrorMessage("request cancelled",
                        Response.Status.INTERNAL_SERVER_ERROR))
                    .build());
            }
        });

        doBind(response, callback);
    }

    void doBind(final AsyncResponse response, final AsyncFuture<?> callback) {
        response.setTimeoutHandler(new TimeoutHandler() {
            @Override
            public void handleTimeout(AsyncResponse asyncResponse) {
                log.warn("Client timed out");
                callback.cancel();
            }
        });

        response.register(new CompletionCallback() {
            @Override
            public void onComplete(Throwable throwable) {
                log.warn("Client completed");
                callback.cancel();
            }
        });

        response.register(new ConnectionCallback() {
            @Override
            public void onDisconnect(AsyncResponse disconnected) {
                log.warn("Client disconnected");
                callback.cancel();
            }
        });
    }

    static final Resume<? extends Object, ? extends Object> PASSTHROUGH =
        new Resume<Object, Object>() {
            @Override
            public Object resume(Object value) throws Exception {
                return value;
            }
        };

    @Override
    @SuppressWarnings("unchecked")
    public <T> Resume<T, T> passthrough() {
        return (Resume<T, T>) PASSTHROUGH;
    }
}

@@ -1007,43 +1007,8 @@
 ne;%0A
-import lombok.extern.slf4j.Slf4j;%0A%0A
 impo
@@ -1170,64 +1170,53 @@
 s.co
-ntainer.TimeoutHandler;%0Aimport javax.ws.rs.core.Response
+re.Response;%0Aimport lombok.extern.slf4j.Slf4j
 ;%0A%0A@
@@ -3239,126 +3239,27 @@
 ler(
-new TimeoutHandler() %7B%0A            @Override%0A            public void handleTimeout(AsyncResponse asyncResponse) %7B%0A    
+asyncResponse -%3E %7B%0A
     
@@ -3266,31 +3266,32 @@
         log.
-warn(%22C
+debug(%22c
 lient timed 
@@ -3293,28 +3293,24 @@
 imed out%22);%0A
-    
             
@@ -3324,38 +3324,24 @@
 k.cancel();%0A
-            %7D%0A
         %7D);%0A
@@ -3367,20 +3367,17 @@
 egister(
-new 
+(
 Completi
@@ -3390,97 +3390,25 @@
 back
-(
 ) 
-%7B%0A            @Override%0A            public void onComplete(Throwable throwable) %7B%0A    
+throwable -%3E %7B%0A
     
@@ -3415,31 +3415,32 @@
         log.
-warn(%22C
+debug(%22c
 lient comple
@@ -3442,28 +3442,24 @@
 ompleted%22);%0A
-    
             
@@ -3473,38 +3473,24 @@
 k.cancel();%0A
-            %7D%0A
         %7D);%0A
@@ -3516,20 +3516,17 @@
 egister(
-new 
+(
 Connecti
@@ -3539,99 +3539,25 @@
 back
-(
 ) 
-%7B%0A            @Override%0A            public void onDisconnect(AsyncResponse disconnected)
+disconnected -%3E
  %7B%0A 
@@ -3571,23 +3571,20 @@
     
-    
 log.
-warn(%22C
+debug(%22c
 lien
@@ -3605,36 +3605,32 @@
 %22);%0A            
-    
 callback.cancel(
@@ -3632,30 +3632,16 @@
 ncel();%0A
-            %7D%0A
         
@@ -3733,20 +3733,17 @@
         
-new 
+(
 Resume%3CO
@@ -3760,154 +3760,24 @@
 ect%3E
-(
 ) 
-%7B%0A            @Override%0A            public Object resume(Object value) throws Exception %7B%0A                return value;%0A            %7D%0A        %7D
+value -%3E value
 ;%0A%0A 

disable warn logging for client states