/*******************************************************************************
 * Copyright (C) 2017 Push Technology Ltd.
 *
 * 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.pushtechnology.adapters.rest.adapter;

import static com.pushtechnology.adapters.rest.endpoints.EndpointType.from;
import static com.pushtechnology.adapters.rest.endpoints.EndpointType.inferFromContentType;

import java.util.function.Consumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.pushtechnology.adapters.rest.endpoints.EndpointType;
import com.pushtechnology.adapters.rest.model.latest.EndpointConfig;
import com.pushtechnology.adapters.rest.model.latest.ServiceConfig;
import com.pushtechnology.adapters.rest.polling.EndpointClient;
import com.pushtechnology.adapters.rest.polling.EndpointResponse;
import com.pushtechnology.adapters.rest.publication.PublishingClient;
import com.pushtechnology.adapters.rest.services.ServiceSession;
import com.pushtechnology.adapters.rest.topic.management.TopicManagementClient;

/**
 * Initialise the endpoint for a service.
 *
 * @author Push Technology Limited
 */
/*package*/ final class InitialiseEndpoint implements Consumer<EndpointConfig> {
    private static final Logger LOG = LoggerFactory.getLogger(InitialiseEndpoint.class);
    private final EndpointClient endpointClient;
    private final TopicManagementClient topicManagementClient;
    private final PublishingClient publishingClient;
    private final ServiceConfig service;
    private final ServiceSession serviceSession;

    /**
     * Constructor.
     */
    /*package*/ InitialiseEndpoint(
            EndpointClient endpointClient,
            TopicManagementClient topicManagementClient,
            PublishingClient publishingClient,
            ServiceConfig service,
            ServiceSession serviceSession) {

        this.endpointClient = endpointClient;
        this.topicManagementClient = topicManagementClient;
        this.publishingClient = publishingClient;
        this.service = service;
        this.serviceSession = serviceSession;
    }

    @Override
    public void accept(EndpointConfig endpointConfig) {
        endpointClient.request(
            service,
            endpointConfig).thenAccept(result -> {
                final EndpointConfig resolvedConfig = resolveEndpointConfig(endpointConfig, result);
                createTransformingHandler(from(resolvedConfig.getProduces()), resolvedConfig)
                    .accept(new ValidateContentType().apply(result, resolvedConfig), null);
            }).exceptionally(e -> {
                LOG.warn("Endpoint {} not initialised. First request failed.", endpointConfig);
                return null;
            });
    }

    private EndpointConfig resolveEndpointConfig(EndpointConfig endpointConfig, EndpointResponse response) {
        final String produces = endpointConfig.getProduces();
        if ("auto".equals(produces)) {
            return inferEndpointConfig(inferFromContentType(response.getHeader("content-type")), endpointConfig);
        }
        else {
            return endpointConfig;
        }
    }

    private EndpointConfig inferEndpointConfig(EndpointType<?> endpointType, EndpointConfig endpointConfig) {
        return EndpointConfig
            .builder()
            .name(endpointConfig.getName())
            .topicPath(endpointConfig.getTopicPath())
            .url(endpointConfig.getUrl())
            .produces(endpointType.getIdentifier())
            .build();
    }

    private <T> TransformingHandler<EndpointResponse, T> createTransformingHandler(
            EndpointType<T> endpointType,
            EndpointConfig endpointConfig) {
        return new TransformingHandler<>(
            endpointType.getParser(),
            new AddTopicForEndpoint<>(
                topicManagementClient,
                service,
                endpointConfig,
                publishingClient.createUpdateContext(
                    service,
                    endpointConfig,
                    endpointType.getDataType()),
                new AddEndpointToServiceSession(endpointConfig, serviceSession)));
    }
}

@@ -2963,68 +2963,80 @@
     
-createTransformingHandler(from(resolvedConfig.getProduces())
+final EndpointResponse response = new ValidateContentType().apply(result
 , re
@@ -3048,16 +3048,17 @@
 dConfig)
+;
 %0A       
@@ -3070,58 +3070,56 @@
     
-    .accept(new ValidateContentType().apply(result
+createHandler(from(resolvedConfig.getProduces())
 , re
@@ -3135,14 +3135,24 @@
 fig)
-, null
+.accept(response
 );%0A 
@@ -4135,33 +4135,22 @@
 ate %3CT%3E 
-TransformingHandl
+Consum
 er%3CEndpo
@@ -4164,19 +4164,16 @@
 onse
-, T
 %3E create
 Tran
@@ -4168,28 +4168,16 @@
 %3E create
-Transforming
 Handler(
@@ -4283,84 +4283,72 @@
 urn 
-new TransformingHandler%3C%3E(%0A            endpointType.getParser(),%0A           
+response -%3E %7B%0A            final AddTopicForEndpoint%3CT%3E handler =
  new
@@ -4715,17 +4715,233 @@
 ession))
-)
+;%0A%0A            try %7B%0A                handler.accept(endpointType.getParser().transform(response), null);%0A            %7D%0A            catch (Exception e) %7B%0A                handler.accept(null, e);%0A            %7D%0A        %7D
 ;%0A    %7D%0A

Use a Consumer instead of a BiConsumer in InitialiseEndpoint.