/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM UrbanCode Deploy
* IBM UrbanCode Release
* IBM AnthillPro
* (c) Copyright IBM Corporation 2002, 2017. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*/
package com.urbancode.air.plugin.websphereliberty;
import com.urbancode.air.CommandHelper;
import com.urbancode.air.AirPluginTool;

public class WebSphereLibertyHelper extends AbstractWebSphereLibertyFileSystemHelper {
   def ch

   public WebSphereLibertyHelper(String wlpHome, String wlpUserDir=null) {
       super(wlpHome, wlpUserDir);
       ch = new CommandHelper(new File(".").canonicalFile);
   }

   // The parameter 'notUsed' is only used to avoid constructor signature collision
   public WebSphereLibertyHelper(String wlpHome, boolean notUsed) {
       super(wlpHome, notUsed);
       ch = new CommandHelper(new File(".").canonicalFile);
   }

   public void deployViaDropins(String serverName, String source) {
       def serverDir = getServerDirectory(serverName);
       def toDir = new File(serverDir, "dropins");
       def ant = new AntBuilder();
       ant.copy(verbose:"true", todir:toDir, overwrite:"true", file: source, failonerror:"true");
   }

   public void uninstallViaDropins(String serverName, String sourceName) {
       System.out.println("Deleting application ${sourceName}");

       def serverDir = getServerDirectory(serverName);
       def dropinsDir = new File(serverDir, "dropins");
       def ant = new AntBuilder();
       ant.delete(verbose:"true", failonerror:"true", includeemptydirs:'true') {
           fileset(dir:dropinsDir.absolutePath, defaultexcludes:'false', followsymlinks: 'true') {
               include(name:"${sourceName}");
           }
       }
   }

   public String createCollective(String serverName, String keystorePassword, String optionalArgs, def isWindows) {
       File configFile = new File(getServerDirectory(serverName), "collectiveCreate_" + getDateTime() + ".xml");

       def options = "${optionalArgs} --keystorePassword=${keystorePassword} --createConfigFile=" + configFile.absolutePath;
       runCollectiveCommand(serverName, isWindows, "create", options, "Creating collective controller configuration for " + serverName);

       return configFile.absolutePath;
   }

   public String joinCollective(String serverName, String controllerHostName, String controllerPort, String adminUser, String adminPassword, String keystorePassword, String optionalArgs, def isWindows) {
       File configFile = new File(getServerDirectory(serverName), "collectiveJoin_" + getDateTime() + ".xml");

       def options = "${optionalArgs} --host=${controllerHostName} --port=${controllerPort} --user=${adminUser} --password=${adminPassword} --keystorePassword=${keystorePassword} --autoAcceptCertificates --createConfigFile=" + configFile.absolutePath;
       runCollectiveCommand(serverName, isWindows, "join", options, "Adding ${serverName} to Collective");

       return configFile.absolutePath;
   }

   public void registerHost(String hostToRegister, String controllerHostName, String controllerPort, String adminUser, String adminPassword, String rpcUser, String rpcUserPassword, String sshPrivateKey, String sshPrivateKeyPassword, String hostJavaHome, String hostReadPath, String hostWritePath, String optionalArgs, def isWindows) {
       def options = new StringBuffer();
       options.append("--host=${controllerHostName} --port=${controllerPort} --user=${adminUser} --password=${adminPassword} ");
       if (rpcUser?.trim()) {
           options.append("--rpcUser=${rpcUser} ");
       }
       if (sshPrivateKey?.trim()) {
           options.append("--sshPrivateKey=${sshPrivateKey} ");
       } else if (rpcUserPassword?.trim()) {
           options.append("--rpcUserPassword=${rpcUserPassword} ");
       } else {
           println("One authentication option(rpcUserPassword or sshPrivateKey) must be given.");
           System.exit(1);
       }
       if (sshPrivateKeyPassword?.trim()) {
           options.append("--sshPrivateKeyPassword=${sshPrivateKeyPassword} ");
       }
       if (hostJavaHome?.trim()) {
           options.append("--hostJavaHome=${hostJavaHome} ");
       }
       if (hostReadPath?.trim()) {
           hostReadPath.eachLine {
               options.append("--hostReadPath=${it} ");
           }
       }
       if (hostWritePath?.trim()) {
           hostWritePath.eachLine {
               options.append("--hostWritePath=${it} ");
           }
       }
       options.append("--autoAcceptCertificates ${optionalArgs}");
       runCollectiveCommand(hostToRegister, isWindows, "registerHost", options.toString(), "Registering ${hostToRegister} with Collective");
   }

   public void unregisterHost(String hostToUnregister, String controllerHostName, String controllerPort, String adminUser, String adminPassword, def isWindows) {
       def options = new StringBuffer();
       options.append("--host=${controllerHostName} --port=${controllerPort} --user=${adminUser} --password=${adminPassword} --autoAcceptCertificates");
       runCollectiveCommand(hostToUnregister, isWindows, "unregisterHost", options.toString(), "Unregistering ${hostToUnregister} from Collective");
   }

   public void updateHost(String hostToUpdate, String controllerHostName, String controllerPort, String adminUser, String adminPassword, String rpcUser, String rpcUserPassword, String sshPrivateKey, String sshPrivateKeyPassword, String hostJavaHome, String hostReadPath, String hostWritePath, String optionalArgs, def isWindows) {
       def options = new StringBuffer();
       options.append("--host=${controllerHostName} --port=${controllerPort} --user=${adminUser} --password=${adminPassword} ");
       if (rpcUser?.trim()) {
           options.append("--rpcUser=${rpcUser} ");
       }
       if (sshPrivateKey?.trim()) {
           options.append("--sshPrivateKey=${sshPrivateKey} ");
       } else if (rpcUserPassword?.trim()) {
           options.append("--rpcUserPassword=${rpcUserPassword} ");
       } else {
           println("One authentication option(rpcUserPassword or sshPrivateKey) must be given.");
           System.exit(1);
       }
       if (sshPrivateKeyPassword?.trim()) {
           options.append("--sshPrivateKeyPassword=${sshPrivateKeyPassword} ");
       }
       if (hostJavaHome?.trim()) {
           options.append("--hostJavaHome=${hostJavaHome} ");
       }
       if (hostReadPath?.trim()) {
           hostReadPath.eachLine {
               options.append("--hostReadPath=${it} ");
           }
       }
       if (hostWritePath?.trim()) {
           hostWritePath.eachLine {
               options.append("--hostWritePath=${it} ");
           }
       }
       options.append("--autoAcceptCertificates ${optionalArgs}");
       runCollectiveCommand(hostToUpdate, isWindows, "updateHost", options.toString(), "Updating ${hostToUpdate} with Collective");
   }

   public void createServer(String serverName, def isWindows) {
       runServerCommand(serverName, isWindows, "create", "Creating new server named " + serverName);
   }

   public void mergePluginConfig(String options, def isWindows) {
       mergePluginConfigCommand(options, isWindows, "merge", "Merging plugin-cfg.xmls... ");
   }

   public int startServer(String serverName, def isWindows) {
       def checkServerStarted = { Process proc ->
           proc.out.close() // close   the stdIn  of the process
           proc.consumeProcessErrorStream(System.out) // forward the stdErr of the process
           proc.consumeProcessOutputStream(System.out) //forward the stdOut of the process
       }
       ch.ignoreExitValue(true)
       return runServerCommand(serverName, isWindows, "start", "Starting server named " + serverName, checkServerStarted)
   }

   public int stopServer(String serverName, def isWindows) {
       ch.ignoreExitValue(true)
       return runServerCommand(serverName, isWindows, "stop", "Stopping server named " + serverName)
   }

   public void deleteServer(String serverName) {
       System.out.println("Deleting server ${serverName}");
       def serverDir = getServerDirectory(serverName);
       def ant = new AntBuilder();
       ant.delete(verbose:"true", failonerror:"true", includeemptydirs:'true') {
           fileset(dir:serverDir.parentFile.absolutePath, defaultexcludes:'false', followsymlinks: 'true') {
               include(name:"${serverName}/**/*");
               include(name:"${serverName}");
           }
       }
   }

   public void installServerArchive(String source, boolean license, def ap1, def ap2) {
       System.out.println("Unzipping server archive in : " + wlpHomeFile.absolutePath);
       String extension = ''
       int dotIndex = source.lastIndexOf('.')
       if (dotIndex >= 0) {
           extension = source.substring(dotIndex + 1)
       }
       if (extension.equals('jar')) {
           String argsval = 'java'
           // on linux need to pick JAVA_HOME set as per agent
           if (System.properties['os.name'].toLowerCase().contains('linux')) {
               argsval = System.getenv('JAVA_HOME') + '/bin/java'
           }
           ArrayList args = [argsval]
           args << '-jar'
           args << source
           if (license) {
               args << '--acceptLicense'
           }
           else {
               println ('[error]  Cannot extract jar file without accepting license.')
               println ('[possible solution]  Please update the step configuration by selecting "Accept License".')
               System.exit(1)
           }
           args << wlpHomeFile.absolutePath
           ch.runCommand('[action] Installing Liberty by extracting a Java archive file...', args)
       }
       else {
           def ant = new AntBuilder();
           ant.unzip(src:source, dest:wlpHomeFile.absolutePath);
           def apTool = new AirPluginTool(ap1, ap2)

           File wlpDir = new File(wlpHomeFile.absolutePath+File.separator+"wlp");
           File binDir = null;
           if(wlpDir.exists() && wlpDir.isDirectory()) {
               binDir = new File(wlpHomeFile.absolutePath+File.separator+"wlp"+File.separator+"bin");
           }
           else {
               binDir = new File(wlpHomeFile.absolutePath+File.separator+"bin");
           }

           boolean setExec=true;
           boolean ownerOnly=false;
           binDir.eachFile() {
               file ->
               if(apTool.isWindows && file.name.endsWith('.bat')) {
                   file.setExecutable(setExec, ownerOnly)
               } else if(!apTool.isWindows && !file.name.endsWith('.bat')) {
                   file.setExecutable(setExec, ownerOnly)
               }
           }
       }

       /*
        * Check if we ended up with the wlp archive contents extracted to a path like /opt/ibm/Liberty/wlp/wlp/...
        * This would happen if the specified wlp directory ended in 'wlp' and the paths in the archive started with 'wlp'.
        */
        if (wlpHomeFile.absolutePath.endsWith(File.separator+"wlp")) {
            File wlpDir = new File(wlpHomeFile.absolutePath+File.separator+"wlp");
            if (wlpDir.exists()) {
                /* Move contents of lower wlp directory up, then remove lower empty wlp directory */
                def destDir = wlpHomeFile.absolutePath;
                def srcDir = wlpDir.absolutePath;
                def ant = new AntBuilder();
                ant.sequential {
                    echo("Moving files from " + srcDir + " to " + destDir)
                    move(todir: destDir) {
                        fileset(dir: srcDir) {
                            include(name: "**/*")
                        }
                    }
                    echo("Move complete")
                }
            }
        }
    }
}


