/*
 * Knot.x - Reactive microservice assembler - Templating Engine Verticle
 *
 * Copyright (C) 2016 Cognifide Limited
 *
 * 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.cognifide.knotx.engine.service;

import com.cognifide.knotx.engine.TemplateEngineConfiguration;

import java.util.Collections;
import java.util.Map;

import io.vertx.core.http.HttpMethod;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.rxjava.core.MultiMap;
import io.vertx.rxjava.core.Vertx;
import io.vertx.rxjava.core.buffer.Buffer;
import io.vertx.rxjava.core.http.HttpClientRequest;
import io.vertx.rxjava.core.http.HttpClientResponse;
import rx.Observable;

public class ServiceEngine {

    private static final Logger LOGGER = LoggerFactory.getLogger(ServiceEngine.class);

    private TemplateEngineConfiguration configuration;

    private Vertx vertx;

    public ServiceEngine(Vertx vertx, TemplateEngineConfiguration serviceConfiguration) {
        this.vertx = vertx;
        this.configuration = serviceConfiguration;
    }

    public Observable<Map<String, Object>> doServiceCall(ServiceEntry serviceEntry, MultiMap headers, HttpMethod httpMethod) {
        Observable<HttpClientResponse> serviceResponse =
                Observable.create((subscriber) -> {
                    HttpClientRequest req = vertx.createHttpClient().request(httpMethod, serviceEntry.getPort(), serviceEntry.getDomain(), serviceEntry.getServiceUri());
                    req.headers().addAll(headers);
                    Observable resp = req.toObservable();
                    resp.subscribe(subscriber);
                    req.end();
                });
        return serviceResponse.flatMap(response -> Observable.just(Buffer.buffer())
                .mergeWith(response.toObservable())
                .reduce(Buffer::appendBuffer)
                .flatMap(buffer -> Observable.just(buffer.toJsonObject().getMap()))
                .map(results -> collectBuffers(results, response)));
    }

    private Map<String, Object> collectBuffers(Map<String, Object> results, HttpClientResponse response) {
        results.put("_response", Collections.singletonMap("statusCode", response.statusCode()));
        traceServiceCall(results);
        return results;
    }

    public Observable<ServiceEntry> findServiceLocation(final ServiceEntry serviceEntry) {
        return Observable.from(configuration.getServices())
                .filter(service -> serviceEntry.getServiceUri().matches(service.getPath()))
                .first()
                .map(metadata -> serviceEntry.setServiceMetadata(metadata));
    }

    private void traceServiceCall(Map<String, Object> results) {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Service call returned <{}>", results.toString());
        }
    }
}

@@ -2233,19 +2233,142 @@
 Map(
-response -%3E
+this::collectBuffers);%0A    %7D%0A%0A    private Observable%3CMap%3CString, Object%3E%3E collectBuffers(HttpClientResponse response) %7B%0A        return
  Obs
@@ -2615,159 +2615,22 @@
  -%3E 
-collectBuffers(results, response)));
+%7B
 %0A    
-%7D%0A%0A
     
-private Map%3CString, Object%3E collectBuffers(Map%3CString, Object%3E results, HttpClientResponse response) %7B%0A
+    
     
@@ -2718,24 +2718,36 @@
 usCode()));%0A
+            
         trac
@@ -2765,24 +2765,36 @@
 l(results);%0A
+            
         retu
@@ -2805,16 +2805,36 @@
 esults;%0A
+                %7D);%0A
     %7D%0A%0A 

put service response status code to buffer