/*
 * Copyright 2015-2019 the original author or authors.
 *
 * 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
 *
 *      https://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 org.springframework.cloud.zookeeper.discovery.dependency;

import java.io.IOException;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import feign.Client;
import feign.Request;
import feign.Response;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration;
import org.springframework.cloud.zookeeper.ConditionalOnZookeeperEnabled;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * Configuration for ensuring that headers are set for a given dependency when Feign is
 * used.
 *
 * @author Marcin Grzejszczak
 * @author Olga Maciaszek-Sharma
 * @since 1.0.0
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnDependenciesPassed
@ConditionalOnZookeeperEnabled
@ConditionalOnProperty(value = "spring.cloud.zookeeper.dependency.headers.enabled", matchIfMissing = true)
@ConditionalOnClass({Client.class, FeignBlockingLoadBalancerClient.class})
@ConditionalOnBean(BlockingLoadBalancerClient.class)
@AutoConfigureAfter({FeignLoadBalancerAutoConfiguration.class, BlockingLoadBalancerClientAutoConfiguration.class})
public class DependencyFeignClientAutoConfiguration {

	private final FeignBlockingLoadBalancerClient feignLoadBalancerClient;

	private final ZookeeperDependencies zookeeperDependencies;

	private final BlockingLoadBalancerClient loadBalancerClient;

	public DependencyFeignClientAutoConfiguration(@Autowired(required = false) FeignBlockingLoadBalancerClient feignLoadBalancerClient,
			ZookeeperDependencies zookeeperDependencies, BlockingLoadBalancerClient loadBalancerClient) {
		this.feignLoadBalancerClient = feignLoadBalancerClient;
		this.zookeeperDependencies = zookeeperDependencies;
		this.loadBalancerClient = loadBalancerClient;
	}

	@Bean
	@Primary
	Client dependencyBasedFeignClient() {
		return new FeignBlockingLoadBalancerClient(new Client.Default(null, null),
				loadBalancerClient) {

			@Override
			public Response execute(Request request, Request.Options options)
					throws IOException {
				URI asUri = URI.create(request.url());
				String clientName = asUri.getHost();
				ZookeeperDependency dependencyForAlias = DependencyFeignClientAutoConfiguration.this.zookeeperDependencies
						.getDependencyForAlias(clientName);
				Map<String, Collection<String>> headers = getUpdatedHeadersIfPossible(
						request, dependencyForAlias);
				if (DependencyFeignClientAutoConfiguration.this.feignLoadBalancerClient != null) {
					return DependencyFeignClientAutoConfiguration.this.feignLoadBalancerClient
							.execute(request(request, headers), options);
				}
				return super.execute(request(request, headers), options);
			}

			private Request request(Request request,
					Map<String, Collection<String>> headers) {
				return Request.create(request.httpMethod(), request.url(), headers,
						request.body(), request.charset(), request.requestTemplate());
			}

			private Map<String, Collection<String>> getUpdatedHeadersIfPossible(
					Request request, ZookeeperDependency dependencyForAlias) {
				if (dependencyForAlias != null) {
					return Collections.unmodifiableMap(new HashMap<>(
							dependencyForAlias.getUpdatedHeaders(request.headers())));
				}
				return request.headers();
			}

		};
	}

}

@@ -1266,16 +1266,102 @@
 operty;%0A
+import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;%0A
 import o
@@ -2858,16 +2858,79 @@
 lient;%0A%0A
+%09private final LoadBalancerProperties loadBalancerProperties;%0A%0A
 %09public 
@@ -3143,24 +3143,71 @@
 lancerClient
+, LoadBalancerProperties loadBalancerProperties
 ) %7B%0A%09%09this.f
@@ -3358,16 +3358,72 @@
 Client;%0A
+%09%09this.loadBalancerProperties = loadBalancerProperties;%0A
 %09%7D%0A%0A%09@Be
@@ -3551,16 +3551,16 @@
  null),%0A
-
 %09%09%09%09load
@@ -3573,16 +3573,40 @@
 erClient
+, loadBalancerProperties
 ) %7B%0A%0A%09%09%09

Fix compilation errors related to OpenFeign changes