package brooklyn.entity.webapp;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.File;
import java.util.List;

import brooklyn.entity.basic.Attributes;
import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
import brooklyn.location.basic.SshMachineLocation;

public abstract class JavaWebAppSshDriver extends JavaSoftwareProcessSshDriver implements JavaWebAppDriver {

    public JavaWebAppSshDriver(JavaWebAppSoftwareProcessImpl entity, SshMachineLocation machine) {
        super(entity, machine);
    }

    public JavaWebAppSoftwareProcessImpl getEntity() {
        return (JavaWebAppSoftwareProcessImpl) super.getEntity();
    }

    protected boolean isProtocolEnabled(String protocol) {
        List<String> protocols = getEnabledProtocols();
        for (String contender : protocols) {
            if (protocol.equalsIgnoreCase(contender)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public List<String> getEnabledProtocols() {
        return entity.getAttribute(JavaWebAppSoftwareProcessImpl.ENABLED_PROTOCOLS);
    }
    
    @Override
    public Integer getHttpPort() {
        return entity.getAttribute(Attributes.HTTP_PORT);
    }

    @Override
    public Integer getHttpsPort() {
        return entity.getAttribute(Attributes.HTTPS_PORT);
    }

    @Override
    public HttpsSslConfig getHttpsSslConfig() {
        return entity.getAttribute(WebAppServiceConstants.HTTPS_SSL_CONFIG);
    }

    protected String getSslKeystoreUrl() {
        HttpsSslConfig ssl = getHttpsSslConfig();
        return (ssl == null) ? null : ssl.getKeystoreUrl();
    }
    
    protected String getSslKeystorePassword() {
        HttpsSslConfig ssl = getHttpsSslConfig();
        return (ssl == null) ? null : ssl.getKeystorePassword();
    }
    
    protected String getSslKeyAlias() {
        HttpsSslConfig ssl = getHttpsSslConfig();
        return (ssl == null) ? null : ssl.getKeyAlias();
    }

    protected String inferRootUrl() {
        if (isProtocolEnabled("https")) {
            int port = getHttpsPort();
            checkNotNull(port, "HTTPS_PORT sensors not set; is an acceptable port available?");
            return String.format("https://%s:%s/", getHostname(), port);
        } else if (isProtocolEnabled("http")) {
            int port = getHttpPort();
            checkNotNull(port, "HTTP_PORT sensors not set; is an acceptable port available?");
            return String.format("http://%s:%s/", getHostname(), port);
        } else {
            throw new IllegalStateException("HTTP and HTTPS protocols not enabled for "+entity+"; enabled protocols are "+getEnabledProtocols());
        }
    }
    
    @Override
    public void postLaunch() {
        String rootUrl = inferRootUrl();
        entity.setAttribute(WebAppService.ROOT_URL, rootUrl);
    }

    /** 
     * if files should be placed on the server for deployment,
     * override this to be the sub-directory of the runDir where they should be stored
     * (or override getDeployDir() if they should be copied somewhere else,
     * and set this null);
     * if files are not copied to the server, but injected (e.g. JMX or uploaded)
     * then override {@link #deploy(String, String)} as appropriate,
     * using getContextFromDeploymentTargetName(targetName)
     * and override this to return null
     */
    protected abstract String getDeploySubdir();
    
    protected String getDeployDir() {
        if (getDeploySubdir()==null)
            throw new IllegalStateException("no deployment directory available for "+this);
        return getRunDir() + "/" + getDeploySubdir();
    }

    @Override
    public void deploy(File file) {
        deploy(file, null);
    }

    @Override
    public void deploy(File f, String targetName) {
        if (targetName == null) {
            targetName = f.getName();
        }
        deploy("file://"+f.getAbsolutePath(), targetName);
    }

    /**
     * Deploys a URL as a webapp at the appserver.
     *
     * Returns a token which can be used as an argument to undeploy,
     * typically the web context with leading slash where the app can be reached (just "/" for ROOT)
     *
     * @see JavaWebAppSoftwareProcess#deploy(String, String) for details of how input filenames are handled
     */
    @Override
    public String deploy(String url, String targetName) {
        String canonicalTargetName = getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName);
        String dest = getDeployDir() + "/" + canonicalTargetName;
        log.info("{} deploying {} to {}:{}", new Object[]{entity, url, getHostname(), dest});
        // create a backup
        getMachine().run(String.format("mv -f %s %s.bak > /dev/null 2>&1", dest, dest)); //back up old file/directory
        int result = -1;
        // TODO allow s3://bucket/file URIs for AWS S3 resources
        if (url.startsWith("http")) {
            result = getMachine().run(String.format("wget --no-check-certificate %s -O %s", url, dest)); // try resolving http resources remotely
        } else {
	        result = getMachine().copyTo(getResource(url), dest);
        }
        log.debug("{} deployed {} to {}:{}: result {}", new Object[]{entity, url, getHostname(), dest, result});
        if (result!=0) log.warn("Problem deploying {} to {}:{} for {}: result {}", new Object[]{url, getHostname(), dest, entity, result}); 
        return getFilenameContextMapper().convertDeploymentTargetNameToContext(canonicalTargetName);
    }
    
    @Override
    public void undeploy(String targetName) {
        String dest = getDeployDir() + "/" + getFilenameContextMapper().convertDeploymentTargetNameToFilename(targetName);
        log.info("{} undeploying {}:{}", new Object[]{entity, getHostname(), dest});
        int result = getMachine().run(String.format("rm -f %s", dest));
        log.debug("{} undeployed {}:{}: result {}", new Object[]{entity, getHostname(), dest, result});
    }
    
    @Override
    public FilenameToWebContextMapper getFilenameContextMapper() {
        return new FilenameToWebContextMapper();
    }
}

@@ -178,16 +178,71 @@
 ibutes;%0A
+import brooklyn.entity.basic.lifecycle.CommonCommands;%0A
 import b
@@ -343,16 +343,65 @@
 ation;%0A%0A
+import com.google.common.collect.ImmutableList;%0A%0A
 public a
@@ -5027,32 +5027,110 @@
     
-if (url.startsWith
+// TODO use PAX-URL style URIs for maven artifacts%0A        if (url.toLowerCase().matches
 (%22
+%5E
 http
+s?://.*
 %22)) 
@@ -5147,156 +5147,422 @@
     
-result = getMachine().run(String.format(%22wget --no-check-certificate %25s -O %25s%22, url, dest)); // try resolving http resources remotely%0A        %7D else
+// try resolving http resources remotely using wget%0A            result = getMachine().execCommands(%22download%22,%0A                    ImmutableList.of(%0A                            CommonCommands.INSTALL_WGET,%0A                            String.format(%22wget --no-check-certificate %25s -O %25s %3E /dev/null 2%3E&1%22, url, dest)));%0A        %7D%0A        // if unsuccessful, retrieve locally and copy across%0A        if (result != 0)
  %7B%0A%09

handle files beginning with the string http and uppercased protocols, and check wget is installed first