/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.brooklyn.qa.brooklynnode;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.core.entity.Attributes;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.EntityAsserts;
import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic;
import org.apache.brooklyn.core.objs.BrooklynObjectInternal.ConfigurationSupportInternal;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.core.test.entity.TestApplication;
import org.apache.brooklyn.entity.brooklynnode.BrooklynEntityMirror;
import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
import org.apache.brooklyn.entity.brooklynnode.BrooklynNode.DeployBlueprintEffector;
import org.apache.brooklyn.entity.machine.MachineEntity;
import org.apache.brooklyn.launcher.BrooklynLauncher;
import org.apache.brooklyn.location.jclouds.JcloudsLocationConfig;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.collections.MutableMap;
import org.apache.brooklyn.util.core.BrooklynMavenArtifacts;
import org.apache.brooklyn.util.maven.MavenRetriever;
import org.apache.brooklyn.util.text.Identifiers;
import org.apache.brooklyn.util.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import com.google.common.base.Joiner;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;

/**
 * Tests obtaining a machine with a private IP only. For the machine to be
 * accessible we should have a gateway machine already running in the same
 * network.
 *
 * Starts a BrooklynNode with a public IP and on it starts two machines -
 * one with public and one with private only IP.
 *
 * The test lives here so it has access to the dist archive.
 */
public class SoftlayerObtainPrivateLiveTest {

    // Expects that the location is already configured in brooklyn.properties
    private static final String LOCATION_SPEC = "jclouds:aws-ec2";


    private static final Logger log = LoggerFactory.getLogger(SoftlayerObtainPrivateLiveTest.class);

    private static final ImmutableMap<String, Duration> TIMEOUT = ImmutableMap.of("timeout", Duration.ONE_HOUR);
    // Should this be a black list instead?
    private Set<String> LOCATION_CONFIG_WHITE_LIST = ImmutableSet.of(
            JcloudsLocationConfig.CLOUD_REGION_ID.getName(),
            JcloudsLocationConfig.ACCESS_IDENTITY.getName(),
            JcloudsLocationConfig.ACCESS_CREDENTIAL.getName(),
            JcloudsLocationConfig.IMAGE_ID.getName(),
            JcloudsLocationConfig.HARDWARE_ID.getName(),
            JcloudsLocationConfig.TEMPLATE_OPTIONS.getName());

    private static final String NAMED_LOCATION_PREFIX = "brooklyn.location.named.";
    private static final String TEST_LOCATION = "test-location";
    private static final String TEST_LOCATION_PRIVATE = TEST_LOCATION + "-private";
    private static final String TEST_LOCATION_PUBLIC = TEST_LOCATION + "-public";

    private BrooklynLauncher launcher;
    private ManagementContext mgmt;
    private TestApplication app;
    private Location loc;

    @BeforeMethod(alwaysRun=true)
    public void setUp() {
        mgmt = LocalManagementContextForTests.builder(true)
                .useDefaultProperties()
                .build();
        launcher = BrooklynLauncher
                .newInstance()
                .managementContext(mgmt)
                .start();
        app = mgmt.getEntityManager().createEntity(EntitySpec.create(TestApplication.class));
        mgmt.getEntityManager().manage(app);
        loc = createLocation();
    }

    @AfterMethod(alwaysRun=true)
    public void tearDown() {
        Entities.destroyAll(mgmt);
        launcher.terminate();
    }

    private Location createLocation() {
        return mgmt.getLocationRegistry().getLocationManaged(LOCATION_SPEC);
    }

    @Test(groups="Live")
    public void testObtain() {
        String localUrl = MavenRetriever.localUrl(BrooklynMavenArtifacts.artifact("", "brooklyn-dist", "tar.gz", "dist"));
        String userName = "admin";
        String userPassword = Identifiers.makeRandomPassword(6);
        String remoteConfig = Joiner.on('\n').join(MutableList.of(
                "brooklyn.webconsole.security.users=" + userName,
                "brooklyn.webconsole.security.user.admin.password=" + userPassword)
                .appendAll(getLocationConfig())
                .append("\n"));

        log.info("Using distribution {}", localUrl);
        log.info("Remote credentials are {}:{}", userName, userPassword);
        log.info("Remote config \n{}", remoteConfig);

        EntitySpec<BrooklynNode> nodeSpec = EntitySpec.create(BrooklynNode.class)
                .configure(BrooklynNode.DISTRO_UPLOAD_URL, localUrl)
                .configure(BrooklynNode.MANAGEMENT_USER, userName)
                .configure(BrooklynNode.MANAGEMENT_PASSWORD, userPassword)
                .configure(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_CONTENTS, remoteConfig);

        BrooklynNode node = app.createAndManageChild(nodeSpec);
        app.start(ImmutableList.of(loc));
        try {
            // TODO Assumes that the second-level machines will be in the same private network as the BrooklynNode machine.
            //      The private network id can be set explicitly in templateOptions.primaryBackendNetworkComponentNetworkVlanId.
            BrooklynEntityMirror publicApp = deployTestApp(node, true);
            BrooklynEntityMirror privateApp = deployTestApp(node, false);

            EntityAsserts.assertAttributeEventually(TIMEOUT, publicApp, ServiceStateLogic.SERVICE_STATE_ACTUAL,
                    Predicates.in(ImmutableList.of(Lifecycle.RUNNING, Lifecycle.ON_FIRE)));
            EntityAsserts.assertAttributeEventually(TIMEOUT, privateApp, ServiceStateLogic.SERVICE_STATE_ACTUAL,
                    Predicates.in(ImmutableList.of(Lifecycle.RUNNING, Lifecycle.ON_FIRE)));

            EntityAsserts.assertAttributeEquals(publicApp, ServiceStateLogic.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
            EntityAsserts.assertAttributeEquals(privateApp, ServiceStateLogic.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);

            EntityAsserts.assertAttributeEqualsEventually(publicApp, Attributes.SERVICE_UP, Boolean.TRUE);
            EntityAsserts.assertAttributeEqualsEventually(privateApp, Attributes.SERVICE_UP, Boolean.TRUE);
        } finally {
            node.invoke(BrooklynNode.STOP_NODE_AND_KILL_APPS, ImmutableMap.<String, String>of()).getUnchecked();
        }
    }

    private BrooklynEntityMirror deployTestApp(BrooklynNode node, boolean hasPublicNetwork) {
        String entityId = node.invoke(BrooklynNode.DEPLOY_BLUEPRINT, ImmutableMap.of(DeployBlueprintEffector.BLUEPRINT_CAMP_PLAN.getName(), getBlueprintPlan(hasPublicNetwork))).getUnchecked();
        return node.addChild(EntitySpec.create(BrooklynEntityMirror.class)
                .configure(BrooklynEntityMirror.MIRRORED_ENTITY_ID, entityId)
                .configure(BrooklynEntityMirror.MIRRORED_ENTITY_URL, node.getAttribute(BrooklynNode.WEB_CONSOLE_URI).toString() + "/v1/applications/"+entityId+"/entities/"+entityId));
    }

    private Collection<String> getLocationConfig() {
        Map<String, Object> config = MutableMap.copyOf(((ConfigurationSupportInternal)loc.config()).getBag().getAllConfig());
        config.putAll(customizeSharedLocation());
        return MutableList.<String>of()
                .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION, (String)config.get("spec.original"), config))
                .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION_PUBLIC, "named:" + TEST_LOCATION, customizePublicLocation()))
                .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION_PRIVATE, "named:" + TEST_LOCATION, customizePrivateLocation()));
    }

    private Collection<String> createLocationConfig(String prefix, String parent, Map<String, ?> config) {
        return MutableList.<String>of()
                .append(prefix + "=" + parent)
                .appendAll(locationConfigToProperties(prefix, config));
    }

    protected Collection<String> locationConfigToProperties(String prefix, Map<String, ?> config) {
        Collection<String> loc = new ArrayList<String>();
        for (String key : config.keySet()) {
            if (LOCATION_CONFIG_WHITE_LIST.contains(key)) {
                loc.add(prefix + "." + key + "=" + config.get(key));
            }
        }
        return loc;
    }

    protected Map<String, String> customizeSharedLocation() {
        return ImmutableMap.of();
    }

    protected Map<String, String> customizePublicLocation() {
        return ImmutableMap.of();
    }

    protected Map<String, String> customizePrivateLocation() {
        return ImmutableMap.<String, String>of(
                "templateOptions", "{privateNetworkOnlyFlag: true}");
    }

    protected String getBlueprintPlan(boolean hasPublicNetwork) {
        return Joiner.on('\n').join(ImmutableList.of(
                "location: " + getTestLocation(hasPublicNetwork),
                "services:",
                "- type: "+MachineEntity.class.getName(),
                "  name: " + (hasPublicNetwork ? "Public" : "Private")
                ));
    }

    private static String getTestLocation(boolean hasPublicNetwork) {
        return hasPublicNetwork ? TEST_LOCATION_PUBLIC : TEST_LOCATION_PRIVATE;
    }

}
