/*
 * 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.systemtest;

import enmasse.systemtest.amqp.AmqpClientFactory;
import enmasse.systemtest.mqtt.MqttClientFactory;
import io.vertx.core.http.HttpMethod;
import org.junit.After;
import org.junit.Before;

import java.io.File;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Base class for all tests
 */
public abstract class TestBase {

    protected static final String ADDRESS_SPACE = "testspace";
    protected static final Environment environment = new Environment();
    protected static final OpenShift openShift = new OpenShift(environment, environment.namespace(),
            environment.isMultitenant() ? ADDRESS_SPACE : environment.namespace());
    private static final GlobalLogCollector logCollector = new GlobalLogCollector(openShift,
            new File(environment.testLogDir()));
    private KeycloakClient keycloakApiClient;
    protected AddressApiClient addressApiClient;
    protected String username;
    protected String password;
    protected AmqpClientFactory amqpClientFactory;
    protected MqttClientFactory mqttClientFactory;

    protected boolean createDefaultAddressSpace() {
        return true;
    }

    @Before
    public void setup() throws Exception {
        addressApiClient = new AddressApiClient(openShift.getRestEndpoint(), environment.isMultitenant());
        if (createDefaultAddressSpace()) {
            if (environment.isMultitenant()) {
                Logging.log.info("Test is running in multitenant mode");
                createAddressSpace(ADDRESS_SPACE, environment.defaultAuthService());
                // TODO: Wait another minute so that all services are connected
                Logging.log.info("Waiting for 2 minutes before starting tests");
            }

            if ("standard".equals(environment.defaultAuthService())) {
                this.username = "systemtest";
                this.password = "systemtest";
                getKeycloakClient().createUser(ADDRESS_SPACE, username, password, 1, TimeUnit.MINUTES);
            }
        }
        amqpClientFactory = new AmqpClientFactory(openShift, environment, ADDRESS_SPACE, username, password);
        mqttClientFactory = new MqttClientFactory(openShift, environment, ADDRESS_SPACE, username, password);
    }

    protected void createAddressSpace(String addressSpace, String authService) throws Exception {
        if (!TestUtils.existAddressSpace(addressApiClient, addressSpace)) {
            Logging.log.info("Address space " + addressSpace + "doesn't exist and will be created.");
            addressApiClient.createAddressSpace(addressSpace, authService);
            logCollector.startCollecting(addressSpace);
            TestUtils.waitForAddressSpaceReady(addressApiClient, addressSpace);
            if (addressSpace.equals(ADDRESS_SPACE)) {
                Thread.sleep(120_000);
            }
        }
    }

    protected void deleteAddressSpace(String addressSpace) throws Exception {
        addressApiClient.deleteAddressSpace(addressSpace);
        TestUtils.waitForAddressSpaceDeleted(openShift, addressSpace);
        logCollector.stopCollecting(addressSpace);
    }

    protected KeycloakClient getKeycloakClient() throws InterruptedException {
        if (keycloakApiClient == null) {
            KeycloakCredentials creds = environment.keycloakCredentials();
            if (creds == null) {
                creds = openShift.getKeycloakCredentials();
            }
            keycloakApiClient = new KeycloakClient(openShift.getKeycloakEndpoint(), creds);
        }
        return keycloakApiClient;
    }

    @After
    public void teardown() throws Exception {
        if (mqttClientFactory != null) {
            mqttClientFactory.close();
        }
        if (amqpClientFactory != null) {
            amqpClientFactory.close();
        }
        if (addressApiClient != null) {
            if (createDefaultAddressSpace()) {
                setAddresses();
            }
            addressApiClient.close();
        }
    }

    /**
     * use DELETE html method for delete specific addresses
     *
     * @param destinations
     * @throws Exception
     */
    protected void deleteAddresses(Destination... destinations) throws Exception {
        TestUtils.delete(addressApiClient, ADDRESS_SPACE, destinations);
    }

    /**
     * use POST html method to append addresses to already existing addresses
     *
     * @param destinations
     * @throws Exception
     */
    protected void appendAddresses(Destination... destinations) throws Exception {
        TimeoutBudget budget = new TimeoutBudget(5, TimeUnit.MINUTES);
        TestUtils.deploy(addressApiClient, openShift, budget, ADDRESS_SPACE, HttpMethod.POST, destinations);
    }

    /**
     * use PUT html method to replace all addresses
     *
     * @param destinations
     * @throws Exception
     */
    protected void setAddresses(Destination... destinations) throws Exception {
        setAddresses(ADDRESS_SPACE, destinations);
    }

    protected void setAddresses(String addressSpace, Destination... destinations) throws Exception {
        TimeoutBudget budget = new TimeoutBudget(5, TimeUnit.MINUTES);
        TestUtils.deploy(addressApiClient, openShift, budget, addressSpace, HttpMethod.PUT, destinations);
    }

    /**
     * give you a list of all deployed addresses (or single deployed address)
     *
     * @param addressName name of single address
     * @return list of addresses
     * @throws Exception
     */
    protected Future<List<String>> getAddresses(Optional<String> addressName) throws Exception {
        return TestUtils.getAddresses(addressApiClient, ADDRESS_SPACE, addressName);
    }

    protected void scale(Destination destination, int numReplicas) throws Exception {
        TimeoutBudget budget = new TimeoutBudget(5, TimeUnit.MINUTES);
        TestUtils.setReplicas(openShift, ADDRESS_SPACE, destination, numReplicas, budget);
    }
}

@@ -1054,116 +1054,179 @@
 nal 
-String ADDRESS_SPACE = %22testspace%22;%0A    protected static final Environment environment = new Environment
+Environment environment = new Environment();%0A    protected static final String defaultAddressSpace = environment.isMultitenant() ? %22testspace%22 : environment.namespace
 ();%0A
+%0A
     
@@ -1325,90 +1325,28 @@
 e(),
-%0A            environment.isMultitenant() ? ADDRESS_SPACE : environment.names
+ defaultAddressS
 pace
-()
 );%0A 
@@ -2186,29 +2186,35 @@
 ssSpace(
-ADDRESS_SPACE
+defaultAddressSpace
 , enviro
@@ -2628,29 +2628,35 @@
 ateUser(
-ADDRESS_SPACE
+defaultAddressSpace
 , userna
@@ -2785,37 +2785,43 @@
 nvironment, 
-ADDRESS_SPACE
+defaultAddressSpace
 , username, 
@@ -2905,29 +2905,35 @@
 onment, 
-ADDRESS_SPACE
+defaultAddressSpace
 , userna
@@ -3478,29 +3478,35 @@
 .equals(
-ADDRESS_SPACE
+defaultAddressSpace
 )) %7B%0A   
@@ -4969,29 +4969,35 @@
 Client, 
-ADDRESS_SPACE
+defaultAddressSpace
 , destin
@@ -5381,29 +5381,35 @@
 budget, 
-ADDRESS_SPACE
+defaultAddressSpace
 , HttpMe
@@ -5669,29 +5669,35 @@
 dresses(
-ADDRESS_SPACE
+defaultAddressSpace
 , destin
@@ -6359,29 +6359,35 @@
 Client, 
-ADDRESS_SPACE
+defaultAddressSpace
 , addres
@@ -6603,21 +6603,27 @@
 ft, 
-ADDRESS_SPACE
+defaultAddressSpace
 , de

Allow tests to be run in single tenant mode