import com.urbancode.air.AirPluginTool;
import java.util.UUID;
import com.urbancode.ud.client.AgentClient;
import com.urbancode.air.agent.install.ssh.AgentInstallPropertiesWriter;
import com.urbancode.air.agent.install.ssh.AgentInstallProperties;


def apTool = new AirPluginTool(this.args[0], this.args[1])
def globalWorkDir = new File(".");

def props = apTool.getStepProperties();

def agentName = props['agentName']
def installDirectory = props['installDirectory']
def javaHome = props['javaHome']
def tempDirectory = props['tempDirectory']
def serverHost = props['serverHost']
def serverPort = props['serverPort']
def proxyHost = props['proxyHost']
def proxyPort = props['proxyPort']
def agentHost = props['agentHost']
def username = props['username']
def password = props['password']
def serverUrl = props['serverUrl']
def mutualAuth = props['mutualAuth']
def installService = Boolean.valueOf(props['installService'])
def serviceName= props['serviceName']
def serviceLogin = props['serviceLogin']
def servicePassword = props['servicePassword']
def autoStartService = Boolean.valueOf(props['autoStartService']);
this.agentHost = props['agentHost']
this.username = props['username']
this.password = props['password']

def runCommand(String message, String command, boolean ignoreExitValue) {
        println()
        if (message) {
            println(message)
        }
        println("command: ${command}")
        def proc = command.execute()

        def hook = {
           proc.destroy();
        }

        addShutdownHook(hook);
        proc.out.close() // close stdin
        def out = new PrintStream(System.out, true)
        try {
            proc.waitForProcessOutput(out, out) // forward stdout and stderr to autoflushing output stream
        }
        finally {
            out.flush();
        }
        proc.waitFor()
        Runtime.getRuntime().removeShutdownHook(hook as Thread);
        if (!ignoreExitValue && proc.exitValue()) {
            throw new Exception("Command failed with exit code: " + proc.exitValue())
        }
        return proc.exitValue();
}


void runWinRSCommand(def commandArgsList, String workDir, Closure exitCodeHandler) {
    def args = ['winrs', "-r:${agentHost}", "-u:${username}", "-p:${password}"];
    if (workDir != null) {
        args << "-d:${workDir}";
    }
    args.addAll(commandArgsList);
    if (exitCodeHandler == null) {
        runCommand("Running remote command", args.join(" "), false);
    }
    else {
        def exitCode = runCommand("Running remote commmand", args.join(" "), true);
        exitCodeHandler(exitCode);
    }
}

void runWinRSCommand(def commandArgsList) {
    runWinRSCommand(commandArgsList, null);
}

void runWinRSCommand(def commandArgsList, String workDir) {
    runWinRSCommand(commandArgsList, workDir, null);
}

def dlAgentInstaller = { agentZipLoc ->
    def client = new AgentClient(new URI(serverUrl), apTool.getAuthTokenUsername(), apTool.getAuthToken());
    client.getAgentInstallPackage(agentZipLoc);
}

def unzipAgentZipFile = { agentZipFile ->
    def directory = agentZipFile.getParentFile().absolutePath;
    def ant = new AntBuilder();
    ant.unzip([src:"${agentZipFile.getAbsolutePath()}", dest:"${directory}"]);
}

def writeAgentInstallProperties = { agentInstallPropsFile ->
   def installProps = new AgentInstallProperties();
   installProps.setInstallDir(installDirectory);
   installProps.setJavaHome(javaHome);
   installProps.setAgentName(agentName);
   installProps.setJmsHost(serverHost);
   installProps.setJmsPort(Integer.valueOf(serverPort));
   installProps.setProxyHost(proxyHost);
   installProps.setProperty("server.url", serverUrl);
   if (proxyPort) {
       installProps.setProxyPort(Integer.valueOf(proxyPort));
   }
   installProps.setUsingMutualAuth(Boolean.valueOf(mutualAuth));
   if (installService) {
       installProps.setProperty("locked/agent.service", "true");
       if (serviceName) {
           installProps.setProperty("locked/agent.service.name", serviceName);
       }
       if (serviceLogin) {
           installProps.setProperty("locked/agent.service.login", serviceLogin);
       }
       else {
           installProps.setProperty("locked/agent.service.login",'.\\localsystem');
       }
       if (servicePassword) {
           installProps.setProperty("locked/agent.service.password", servicePassword);
       }
       else {
           installProps.setProperty("locked/agent.service.password","nopass");
       }
       if (autoStartService) {
           installProps.setProperty("locked/agent.service.autostart","true");
       }
       else {
           installProps.setProperty("locked/agent.service.autostart","false");
       }
   }
   def writer = new AgentInstallPropertiesWriter();
   writer.writeToPropertiesFile(installProps, agentInstallPropsFile);
}





def shared = false;
def mounted = false;

def randUUID = UUID.randomUUID().toString();
def shareName = "agent-${randUUID}";
def tempWorkDir = File.createTempFile("dir","");
tempWorkDir.delete();
tempWorkDir.mkdirs();
try {
    File agentZipFile = new File(tempWorkDir, "ibm-ucd-agent.zip");
    File unzipInstallerDir = new File(tempWorkDir, "ibm-ucd-agent-install");
    File installPropsFile = new File(unzipInstallerDir, "cust-install.properties");

    dlAgentInstaller(agentZipFile);
    unzipAgentZipFile(agentZipFile);
    writeAgentInstallProperties(installPropsFile);
    File exeFile = new File(unzipInstallerDir, "env-install-from-properties.bat");
    PrintStream fostream = new PrintStream(exeFile);
    fostream.println("set JAVA_HOME=${javaHome}");
    fostream.println("set ANT_OPTS=-Xmx256m -Xms50m");
    fostream.println("set JAVA_OPTS=-Xmx256m -Xms50m");
    fostream.println("install-agent-from-file.bat cust-install.properties");
    fostream.flush();
    fostream.close();

    def mkdirCmds = ["mkdir", "\"${tempDirectory}\""];
    runWinRSCommand(mkdirCmds, null) { exitCode ->
        //nooneCares
    };

    def mkagentDirCommand =["mkdir", "\"${tempDirectory}\\agentInstall\""]
    runWinRSCommand(mkagentDirCommand, null) { exitCode ->
        //noonecares
    };

    def shareArgs = ["net", "share", "\"${shareName}=${tempDirectory}\\agentInstall\"", "\"/GRANT:Everyone,FULL\""]
    runWinRSCommand(shareArgs, null) { exitCode ->
        if (exitCode != 0) {
            shared = false;
            throw new Exception("Exception sharing drive");
        }
        else {
            shared = true;
        }
    };

    def netUseCmd = ["net", "use", "Q:", "\"\\\\${agentHost}\\${shareName}\"",
            "/user:${username}", "${password}"];
    mounted = (runCommand("Mapping Q:", netUseCmd.join(" "), true) == 0)
    if (!mounted) {
        throw new Exception("Failed mounting drive");
    }

    def cpCmd = ["xcopy", "/Y", "/E", "\"${unzipInstallerDir.absolutePath}\"", "\"Q:\""];
    runCommand("Copying agent installer", cpCmd.join(" "), false);


    try {
        def netUseDeleteCmd = ["net", "use", "Q:", "/delete"];
        runCommand("Unmounting drive", netUseDeleteCmd.join(" "), false);
        mounted=false;
    }
    catch (Exception e) {
        System.out.println("Failed to delete network mount!");
        System.out.println("Manually delete the mount!");
    }

    try {
        def cmdDelArgs = ["net", "share", "\"${shareName}\"", "/DELETE"]
        runWinRSCommand(cmdDelArgs, null) { exitCode ->
            if (exitCode == 0) {
                shared = false;
            }
        }
    }
    catch (Throwable t) {
        //swallow
    }

    def installCmd = ["\"${tempDirectory}\\agentInstall\\${exeFile.name}\""]
    runWinRSCommand(installCmd, "${tempDirectory}\\agentInstall");
}
finally {
    if (mounted) {
        try {
            def netUseCmd = ["net", "use", "Q:", "/delete"];
            runCommand("Unmounting drive", netUseCmd.join(" "), false);
        }
        catch (Exception e) {
            System.out.println("Failed to delete network mount!");
            System.out.println("Manually delete the mount!");
        }
    }
    if (shared) {
        try {
            def cmdArgs = ["net", "share", "\"${shareName}\"", "/DELETE"]
            runWinRSCommand(cmdArgs);
        }
        catch (Exception e) {
            e.printStackTrace();
            System.out.println("Failed to unshare ${shareName} on jump agent.");
            System.out.println("Manually unshare the network share");
        }
    }

    try {
        //cleanup time
        def rmdirCmd = ["rmdir", "/Q", "/S", "\"${tempDirectory}\\agentInstall\""]
        runWinRSCommand(rmdirCmd);
    }
    catch (Exception e) {
        System.out.println("Failed to delete working directory on jump agent ${tempDirectory}\\agentInstall");
        System.out.println("Manually delete the directory");
    }

    def ant = new AntBuilder();
    try {
        ant.delete([includeemptydirs:"true"]) {
            ant.fileset([dir:"${tempWorkDir.getAbsolutePath()}", defaultexcludes:"false"]) {
                ant.include([name:"**/*"]);
                ant.include([name:"*"]);
            }
        };
        tempWorkDir.delete();
    }
    catch (Exception e) {
       System.out.println("Failed cleaning up temp directory.");
       System.out.println("Manually clean up " + tempWorkDir.getAbsolutePath());
    }
}

