/*
 * Copyright 2015 Palantir Technologies, Inc. All rights reserved.
 *
 * 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 com.palantir.remoting.http;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.palantir.remoting.http.errors.SerializableErrorErrorDecoder;
import feign.InputStreamDelegateDecoder;
import feign.InputStreamDelegateEncoder;
import feign.OptionalAwareDecoder;
import feign.TextDelegateDecoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.jaxrs.JAXRSContract;

/**
 * Static factory methods for producing common configurations of {@link FeignClientFactory}, which in turn may be used
 * to create HTTP proxies for HTTP remoting clients. The returned instances serialize server-side exceptions as JSON and
 * decode any 204 response as an {@link Optional#absent} in case the proxied interface is of type {@link Optional}.
 */
public final class FeignClients {

    private FeignClients() {}

    /**
     * Provides a {@link FeignClientFactory} with an {@link ObjectMapper} configured with {@link
     * com.fasterxml.jackson.datatype.guava.GuavaModule} and {@link com.fasterxml.jackson.datatype.jdk7.Jdk7Module}.
     */
    public static FeignClientFactory standard() {
        return FeignClientFactory.of(
                new GuavaOptionalAwareContract(new JAXRSContract()),
                new InputStreamDelegateEncoder(new JacksonEncoder(ObjectMappers.guavaJdk7())),
                new OptionalAwareDecoder(
                        new InputStreamDelegateDecoder(
                                new TextDelegateDecoder(
                                        new JacksonDecoder(ObjectMappers.guavaJdk7())))),
                SerializableErrorErrorDecoder.INSTANCE,
                FeignClientFactory.okHttpClient());
    }

    /**
     * Provides a {@link FeignClientFactory} compatible with jackson 2.4.
     */
    public static FeignClientFactory standardJackson24() {
        return FeignClientFactory.of(
                new GuavaOptionalAwareContract(new JAXRSContract()),
                new InputStreamDelegateEncoder(new Jackson24Encoder(ObjectMappers.guavaJdk7())),
                new OptionalAwareDecoder(
                        new InputStreamDelegateDecoder(
                                new TextDelegateDecoder(
                                        new JacksonDecoder(ObjectMappers.guavaJdk7())))),
                SerializableErrorErrorDecoder.INSTANCE,
                FeignClientFactory.okHttpClient());
    }

    /**
     * Provides a {@link FeignClientFactory} with an unmodified {@link ObjectMapper}.
     */
    public static FeignClientFactory vanilla() {
        return FeignClientFactory.of(
                new GuavaOptionalAwareContract(new JAXRSContract()),
                new InputStreamDelegateEncoder(new JacksonEncoder(ObjectMappers.vanilla())),
                new OptionalAwareDecoder(
                        new InputStreamDelegateDecoder(
                                new TextDelegateDecoder(
                                        new JacksonDecoder(ObjectMappers.vanilla())))),
                SerializableErrorErrorDecoder.INSTANCE,
                FeignClientFactory.okHttpClient());
    }

    /**
     * Provides a {@link FeignClientFactory} with the specified {@link ObjectMapper}.
     */
    public static FeignClientFactory withMapper(ObjectMapper mapper) {
        return FeignClientFactory.of(
                new GuavaOptionalAwareContract(new JAXRSContract()),
                new InputStreamDelegateEncoder(new JacksonEncoder(mapper)),
                new OptionalAwareDecoder(
                        new InputStreamDelegateDecoder(
                                new TextDelegateDecoder(
                                        new JacksonDecoder(mapper)))),
                SerializableErrorErrorDecoder.INSTANCE,
                FeignClientFactory.okHttpClient());
    }
}

@@ -936,32 +936,84 @@
 alAwareDecoder;%0A
+import feign.Request;%0Aimport feign.Request.Options;%0A
 import feign.Tex
@@ -1022,32 +1022,32 @@
 elegateDecoder;%0A
-
 import feign.jac
@@ -1538,16 +1538,99 @@
 ents %7B%0A%0A
+    private static final Options DEFAULT_TIMEOUT_OPTIONS = new Request.Options();%0A%0A
     priv
@@ -1928,24 +1928,391 @@
 tandard() %7B%0A
+        return standard(DEFAULT_TIMEOUT_OPTIONS);%0A    %7D%0A%0A    /**%0A     * Provides a %7B@link FeignClientFactory%7D with an %7B@link ObjectMapper%7D configured with %7B@link%0A     * com.fasterxml.jackson.datatype.guava.GuavaModule%7D and %7B@link com.fasterxml.jackson.datatype.jdk7.Jdk7Module%7D.%0A     */%0A    public static FeignClientFactory standard(Request.Options timeoutOptions) %7B%0A
         retu
@@ -2843,32 +2843,119 @@
 y.okHttpClient()
+,%0A                NeverRetryingBackoffStrategy.INSTANCE,%0A                timeoutOptions
 );%0A    %7D%0A%0A    /*
@@ -3093,24 +3093,260 @@
 ckson24() %7B%0A
+        return standard(DEFAULT_TIMEOUT_OPTIONS);%0A    %7D%0A%0A    /**%0A     * Provides a %7B@link FeignClientFactory%7D compatible with jackson 2.4.%0A     */%0A    public static FeignClientFactory standardJackson24(Request.Options timeoutOptions) %7B%0A
         retu
@@ -3879,32 +3879,119 @@
 y.okHttpClient()
+,%0A                NeverRetryingBackoffStrategy.INSTANCE,%0A                timeoutOptions
 );%0A    %7D%0A%0A    /*
@@ -4131,24 +4131,261 @@
 vanilla() %7B%0A
+        return vanilla(DEFAULT_TIMEOUT_OPTIONS);%0A    %7D%0A%0A    /**%0A     * Provides a %7B@link FeignClientFactory%7D with an unmodified %7B@link ObjectMapper%7D.%0A     */%0A    public static FeignClientFactory vanilla(Request.Options timeoutOptions) %7B%0A
         retu
@@ -4863,32 +4863,32 @@
 coder.INSTANCE,%0A
-
                 
@@ -4912,32 +4912,119 @@
 y.okHttpClient()
+,%0A                NeverRetryingBackoffStrategy.INSTANCE,%0A                timeoutOptions
 );%0A    %7D%0A%0A    /*

allow specifying timeout options