/**
 * Copyright 2015 Palantir Technologies
 *
 * Licensed under the BSD-3 License (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://opensource.org/licenses/BSD-3-Clause
 *
 * 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.atlasdb.http;

import java.util.Collection;
import java.util.List;

import javax.net.ssl.SSLSocketFactory;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;

import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Target;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.jaxrs.JAXRSContract;
import feign.okhttp.OkHttpClient;

public class AtlasDbHttpClients {
    
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final Contract contract = new JAXRSContract();
    private static final Encoder encoder = new JacksonEncoder(mapper);
    private static final Decoder decoder = new TextDelegateDecoder(new JacksonDecoder(mapper));
    
    /**
     * Constructs a dynamic proxy for the specified type, using the supplied SSL factory if is present, and feign {@link
     * feign.Client.Default} HTTP client.
     */
    public static <T> T createProxy(Optional<SSLSocketFactory> sslSocketFactory, String uri, Class<T> type) {
        return Feign.builder()
                .contract(contract)
                .encoder(encoder)
                .decoder(decoder)
                .client(newOkHttpClient(sslSocketFactory))
                .target(type, uri);
    }

    /**
     * Constructs a dynamic proxy for the specified target, using the provided client.
     */
    public static <T> T createProxy(Client client, Target<T> target) {
        return Feign.builder().contract(contract).encoder(encoder).decoder(decoder).client(client).target(target);
    }

    /**
     * Constructs a list, corresponding to the iteration order of the supplied endpoints, of dynamic proxies for the
     * specified type, using the supplied SSL factory if it is present.
     */
    public static <T> List<T> createProxies(
            Optional<SSLSocketFactory> sslSocketFactory, Collection<String> endpointUris, Class<T> type) {
        List<T> ret = Lists.newArrayListWithCapacity(endpointUris.size());
        for (String uri : endpointUris) {
            ret.add(createProxy(sslSocketFactory, uri, type));
        }
        return ret;
    }
    
    /**
     * Constructs an HTTP-invoking dynamic proxy for the specified type that will cycle through the list of supplied
     * endpoints after encountering an exception or connection failure, using the supplied SSL factory if it is
     * present.
     * <p>
     * Failover will continue to cycle through the supplied endpoint list indefinitely.
     */
    public static <T> T createProxyWithFailover(
            Optional<SSLSocketFactory> sslSocketFactory, Collection<String> endpointUris, Class<T> type) {
        FailoverFeignTarget<T> failoverFeignTarget = new FailoverFeignTarget<>(endpointUris, type);
        Client client = failoverFeignTarget.wrapClient(newOkHttpClient(sslSocketFactory));
        return createProxy(client, failoverFeignTarget);
    }
    
    /**
     * Returns a feign {@link Client} wrapping a {@link com.squareup.okhttp.OkHttpClient} client with optionally
     * specified {@link SSLSocketFactory}.
     */
    private static Client newOkHttpClient(Optional<SSLSocketFactory> sslSocketFactory) {
        com.squareup.okhttp.OkHttpClient client = new com.squareup.okhttp.OkHttpClient();
        client.setSslSocketFactory(sslSocketFactory.orNull());
        return new OkHttpClient(client);
    }
    
}

@@ -912,29 +912,8 @@
 gn;%0A
-import feign.Target;%0A
 impo
@@ -928,32 +928,32 @@
 .codec.Decoder;%0A
+
 import feign.cod
@@ -1141,21 +1141,17 @@
 ients %7B%0A
-    
 %0A
+
     priv
@@ -1442,21 +1442,17 @@
 pper));%0A
-    
 %0A
+
     /**%0A
@@ -1973,304 +1973,8 @@
  %7D%0A%0A
-    /**%0A     * Constructs a dynamic proxy for the specified target, using the provided client.%0A     */%0A    public static %3CT%3E T createProxy(Client client, Target%3CT%3E target) %7B%0A        return Feign.builder().contract(contract).encoder(encoder).decoder(decoder).client(client).target(target);%0A    %7D%0A%0A
     
@@ -2534,37 +2534,33 @@
 turn ret;%0A    %7D%0A
-    
 %0A
+
     /**%0A     * C
@@ -3269,28 +3269,230 @@
 urn 
-createProxy(client, 
+Feign.builder()%0A                .contract(contract)%0A                .encoder(encoder)%0A                .decoder(decoder)%0A                .client(client)%0A                .retryer(failoverFeignTarget)%0A                .target(
 fail
@@ -3515,21 +3515,17 @@
 ;%0A    %7D%0A
-    
 %0A
+
     /**%0A
@@ -3977,15 +3977,11 @@
 ;%0A    %7D%0A
-    
 %0A%7D%0A

Add back missing retryer configuration