package brooklyn.entity.nosql.redis;

import static java.lang.String.format;

import java.util.List;

import brooklyn.entity.basic.AbstractSoftwareProcessSshDriver;
import brooklyn.entity.basic.Entities;
import brooklyn.entity.drivers.downloads.DownloadResolver;
import brooklyn.entity.proxy.nginx.NginxController;
import brooklyn.location.Location;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.ssh.BashCommands;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;

/**
 * Start a {@link RedisStore} in a {@link Location} accessible over ssh.
 */
public class RedisStoreSshDriver extends AbstractSoftwareProcessSshDriver implements RedisStoreDriver {

    private String expandedInstallDir;

    public RedisStoreSshDriver(RedisStoreImpl entity, SshMachineLocation machine) {
        super(entity, machine);
    }

    private String getExpandedInstallDir() {
        if (expandedInstallDir == null) throw new IllegalStateException("expandedInstallDir is null; most likely install was not called");
        return expandedInstallDir;
    }

    @Override
    public void install() {
        DownloadResolver resolver = Entities.newDownloader(this);
        List<String> urls = resolver.getTargets();
        String saveAs = resolver.getFilename();
        expandedInstallDir = getInstallDir()+"/"+resolver.getUnpackedDirectoryName(format("redis-%s", getVersion()));

        MutableMap<String, String> installGccPackageFlags = MutableMap.of(
                "onlyifmissing", "gcc",
                "yum", "gcc",
                "apt", "gcc",
                "port", null);
        MutableMap<String, String> installMakePackageFlags = MutableMap.of(
                "onlyifmissing", "make",
                "yum", "make",
                "apt", "make",
                "port", null);

        List<String> commands = ImmutableList.<String>builder()
                .addAll(BashCommands.commandsToDownloadUrlsAs(urls, saveAs))
                .add(BashCommands.INSTALL_TAR)
                .add(BashCommands.INSTALL_CURL)
                .add(BashCommands.installPackage(installGccPackageFlags, "redis-prerequisites-gcc"))
                .add(BashCommands.installPackage(installMakePackageFlags, "redis-prerequisites-make"))
                .add("tar xzfv " + saveAs)
                .add(format("cd redis-%s", getVersion()))
                .add("make clean && make")
                .build();

        newScript(INSTALLING)
                .failOnNonZeroResultCode()
                .body.append(commands).execute();
    }

    @Override
    public void customize() {
        newScript(MutableMap.of("usePidFile", false), CUSTOMIZING)
                .failOnNonZeroResultCode()
                .body.append(
                        format("cd %s", getExpandedInstallDir()),
                        "make install PREFIX="+getRunDir())
                .execute();

        copyTemplate(getEntity().getConfig(RedisStore.REDIS_CONFIG_TEMPLATE_URL), "redis.conf");
    }

    @Override
    public void launch() {
        // TODO Should we redirect stdout/stderr: format(" >> %s/console 2>&1 </dev/null &", getRunDir())
        newScript(MutableMap.of("usePidFile", false), LAUNCHING)
                .failOnNonZeroResultCode()
                .body.append("./bin/redis-server redis.conf")
                .execute();
    }

    @Override
    public boolean isRunning() {
        return newScript(MutableMap.of("usePidFile", false), CHECK_RUNNING)
                .body.append("./bin/redis-cli -p " + getEntity().getAttribute(RedisStore.REDIS_PORT) + " ping > /dev/null")
                .execute() == 0;
    }

    /**
     * Restarts redis with the current configuration.
     */
    @Override
    public void stop() {
        newScript(MutableMap.of("usePidFile", false), STOPPING)
                .failOnNonZeroResultCode()
                .body.append("./bin/redis-cli -p " + getEntity().getAttribute(RedisStore.REDIS_PORT) + " shutdown")
                .execute();
    }
}

@@ -91,24 +91,131 @@
 util.List;%0A%0A
+import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0Aimport com.google.common.collect.ImmutableList;%0A%0A
 import brook
@@ -261,24 +261,24 @@
 sSshDriver;%0A
-
 import brook
@@ -367,60 +367,8 @@
 er;%0A
-import brooklyn.entity.proxy.nginx.NginxController;%0A
 impo
@@ -538,144 +538,8 @@
 s;%0A%0A
-import com.google.common.collect.ImmutableList;%0Aimport com.google.common.collect.ImmutableMap;%0Aimport com.google.common.collect.Lists;%0A%0A
 /**%0A
@@ -720,16 +720,106 @@
 iver %7B%0A%0A
+    private static final Logger LOG = LoggerFactory.getLogger(RedisStoreSshDriver.class);%0A
     priv
@@ -3873,32 +3873,47 @@
 stop() %7B%0A       
+ int exitCode =
  newScript(Mutab
@@ -3957,51 +3957,8 @@
 NG)%0A
-                .failOnNonZeroResultCode()%0A
     
@@ -4069,16 +4069,16 @@
 tdown%22)%0A
-
         
@@ -4093,20 +4093,252 @@
 .execute();%0A
+        // TODO: Good enough? Will cause warnings when trying to stop a server that is already not running.%0A        if (exitCode != 0) %7B%0A            LOG.warn(%22Unexpected exit code when stopping %7B%7D: %7B%7D%22, entity, exitCode);%0A        %7D%0A
     %7D%0A%7D%0A

Remove failOnNonZeroResultCode from RedisStoreSshDriver