/*
 * Copyright 2016 Red Hat Inc.
 *
 * 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 enmasse.controller;

import enmasse.controller.api.osb.v2.bind.OSBBindingService;
import enmasse.controller.api.osb.v2.catalog.OSBCatalogService;
import enmasse.controller.api.osb.v2.lastoperation.OSBLastOperationService;
import enmasse.controller.api.osb.v2.provision.OSBProvisioningService;
import enmasse.controller.api.v3.AddressApiHelper;
import enmasse.controller.api.v3.http.AddressingService;
import enmasse.controller.api.v3.http.FlavorsService;
import enmasse.controller.api.v3.http.InstanceService;
import enmasse.controller.api.v3.http.MultiInstanceAddressingService;
import enmasse.controller.common.exceptionmapping.DefaultExceptionMapper;
import enmasse.controller.flavor.FlavorRepository;
import enmasse.controller.instance.api.InstanceApi;
import enmasse.controller.model.InstanceId;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.net.PemKeyCertOptions;
import org.jboss.resteasy.plugins.server.vertx.VertxRequestHandler;
import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
 * HTTP server for deploying address config
 */
public class HTTPServer extends AbstractVerticle {
    public static final int PORT = 8080;
    public static final int SECURE_PORT = 8081;
    private static final Logger log = LoggerFactory.getLogger(HTTPServer.class.getName());
    private final InstanceApi instanceApi;
    private final FlavorRepository flavorRepository;
    private final InstanceId globalInstance;
    private final String certDir;

    private HttpServer httpServer;
    private HttpServer httpsServer;

    public HTTPServer(InstanceId globalInstance, InstanceApi instanceApi, FlavorRepository flavorRepository, String certDir) {
        this.globalInstance = globalInstance;
        this.instanceApi = instanceApi;
        this.flavorRepository = flavorRepository;
        this.certDir = certDir;
    }

    @Override
    public void start() {
        VertxResteasyDeployment deployment = new VertxResteasyDeployment();
        deployment.start();

        deployment.getProviderFactory().registerProvider(DefaultExceptionMapper.class);

        AddressApiHelper addressApi = new AddressApiHelper(instanceApi);
        deployment.getRegistry().addSingletonResource(new AddressingService(globalInstance, addressApi));
        deployment.getRegistry().addSingletonResource(new InstanceService(instanceApi));
        deployment.getRegistry().addSingletonResource(new MultiInstanceAddressingService(addressApi, instanceApi));
        deployment.getRegistry().addSingletonResource(new FlavorsService(flavorRepository));

        deployment.getRegistry().addSingletonResource(new OSBCatalogService(instanceApi, flavorRepository));
        deployment.getRegistry().addSingletonResource(new OSBProvisioningService(instanceApi, flavorRepository));
        deployment.getRegistry().addSingletonResource(new OSBBindingService(instanceApi, flavorRepository));
        deployment.getRegistry().addSingletonResource(new OSBLastOperationService(instanceApi, flavorRepository));


        VertxRequestHandler requestHandler = new VertxRequestHandler(vertx, deployment);
        createSecureServer(requestHandler);
        createOpenServer(requestHandler);
    }

    @Override
    public void stop() {
        if (httpServer != null) {
            httpServer.close();
        }
        if (httpsServer != null) {
            httpsServer.close();
        }
    }

    private void createSecureServer(VertxRequestHandler requestHandler) {
        if (new File(certDir).exists()) {
            HttpServerOptions options = new HttpServerOptions();
            File keyFile = new File(certDir, "tls.key");
            File certFile = new File(certDir, "tls.crt");
            log.info("Loading key from " + keyFile.getAbsolutePath() + ", cert from " + certFile.getAbsolutePath());
            options.setKeyCertOptions(new PemKeyCertOptions()
                    .setKeyPath(keyFile.getAbsolutePath())
                    .setCertPath(certFile.getAbsolutePath()));
            options.setSsl(true);

            httpsServer = vertx.createHttpServer(options)
                    .requestHandler(requestHandler)
                    .listen(SECURE_PORT, ar -> log.info("Started HTTPS server. Listening on port " + SECURE_PORT));
        }
    }


    private void createOpenServer(VertxRequestHandler requestHandler) {
        httpServer = vertx.createHttpServer()
                .requestHandler(requestHandler)
                .listen(PORT, ar -> log.info("Started HTTP server. Listening on port " + PORT));
    }
}

@@ -1783,16 +1783,54 @@
 io.File;
+%0Aimport java.util.concurrent.TimeUnit;
 %0A%0A/**%0A *
@@ -4433,24 +4433,307 @@
 %22tls.key%22);%0A
+            // TODO: Remove once Vert.x supports PKCS#1: https://github.com/eclipse/vert.x/issues/1851%0A            // This also implies that _KEY ROTATION DOES NOT WORK_%0A            File outputFile = new File(certDir, %22/tmp/pkcs8.key%22);%0A            convertKey(keyFile, outputFile);%0A%0A
             
@@ -4774,24 +4774,24 @@
 %22tls.crt%22);%0A
-
             
@@ -4989,19 +4989,22 @@
 KeyPath(
-key
+output
 File.get
@@ -5219,32 +5219,32 @@
 requestHandler)%0A
-
                 
@@ -5360,16 +5360,496 @@
 %0A    %7D%0A%0A
+    private void convertKey(File keyFile, File outputFile) %7B%0A        try %7B%0A            Process p = new ProcessBuilder(%22openssl%22, %22pkcs8%22, %22-topk8%22, %22-inform%22, %22PEM%22,%0A                    %22-outform%22, %22PEM%22, %22-nocrypt%22, %22-in%22, keyFile.getAbsolutePath(), %22-out%22, outputFile.getAbsolutePath())%0A                    .start();%0A            p.waitFor(1, TimeUnit.MINUTES);%0A        %7D catch (Exception e) %7B%0A            log.info(%22Error converting key from PKCS#1 to PKCS#8%22);%0A        %7D%0A    %7D%0A%0A
 %0A    pri

Convert controller certs from pkcs1 to pkcs8