import hudson.model.*
import jenkins.model.*
import groovy.json.JsonSlurper
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.security.MessageDigest;

class SlaveStatus {

    private Map slave_info = [:]

    SlaveStatus(String full_name) {
        for (slave in Hudson.instance.slaves) {
            def slaveComputer = slave.getComputer()
            if ("${slaveComputer.getName()}" == full_name) {
                def this_slave = ["name":slaveComputer.getName(),
                                  "host":slave.getLauncher().getHost(),
                                  "object":slaveComputer]
                slave_info[slaveComputer.getName()] = this_slave
            }
        }
    }
    Map get_slave_info() {
        return slave_info
    }
    void disconnect_node(slaveName) {
        if (slaveName in slave_info) {
            slave_info[slaveName]["object"].setTemporarilyOffline(true, null)
            slave_info[slaveName]["object"].disconnect(null)
        }
    }
    void delete_node(slaveName) {
        if (slaveName in slave_info) {
            slave_info[slaveName]["object"].doDoDelete()
        }
    }
}

def get_node_to_create_env(workspace) {
    def Properties conf
    conf = new Properties()
    conf.load(new FileInputStream("${workspace}/NODE_TO_CREATE.env"))
    return conf
}

def get_slave_info(node_name) {
    def Map data = [:]

    def existing_slaves = new SlaveStatus("${node_name}");
    def existing_slaves_info = existing_slaves.get_slave_info()
    existing_slaves_info.each{k, v ->
        if( k != "${node_name}" ) {
            return
        }
        def computer      = v["object"]
        //def user_id       = computer.getNode().getUserId()
        def remoteFS      = computer.getAbsoluteRemoteFs()
        def slave_name    = computer.getName()
        def numExecutors  = computer.getNumExecutors()
        def isAlive       = computer.isAlive()
        def label_string  = computer.getNode().getLabelString()
        def _launcher     = computer.getLauncher()
        assert _launcher instanceof hudson.plugins.sshslaves.SSHLauncher
        def host          = _launcher.getHost()
        def port          = _launcher.getPort()
        def _credentials  = _launcher.getCredentials()
        def user_id       = _credentials.getUsername()
        def credential_id = _credentials.getId()

        data["slave_name"]    = slave_name
        data["user_id"]       = user_id
        data["remoteFS"]      = remoteFS
        data["numExecutors"]  = numExecutors
        data["isalive"]       = isAlive
        data["label_string"]  = label_string
        data["host"]          = host
        data["port"]          = port
        data["credential_id"] = credential_id
    }
    return data
}

def append_backend_selection(workspace, request_file, label_string) {
    // Append created node to trigger env
    File[] files = new File("${workspace}").listFiles()
    for (File file : files) {
        if (file.isFile()) {
            if (file.getName() == "${request_file}.env") {
                def target_file = "${workspace}/${request_file}.env"
                println "Writing ${label_string} to ${target_file}"
                f = new File("${target_file}")
                f.append("\nBACKEND_SELECTION=${label_string}")
            }
        }
    }
}

def create_new_node(project_name, project_name_hash, jenkins_home ) {
    def node_name = "download_${project_name_hash}"
    println "Creating node for ${project_name} to ${node_name}"

    // Load function modules
    e = { filepath ->
        evaluate(new File("${jenkins_home}" + "/init.groovy.d/" + filepath))
    }
    create_slave_node = e("Module_Node")

    def parent_node_info = get_slave_info("download")
    def target_node_info = get_slave_info("${node_name}")
    println "Parent Node:"
    println parent_node_info
    println "Target Node:"
    println target_node_info
    def check_key_list = ["slave_name", "user_id", "remoteFS", "host", "port", "credential_id"]
    check_key_list.each{k ->
        assert parent_node_info.containsKey(k)
    }

    // Jenkins instance
    def instance        = Jenkins.getInstance()

    // Required variables
    def remoteFS        = "${parent_node_info["remoteFS"]}/${node_name}"
    def numExecutors    = 1
    def thisLabelString = "snapshot_${project_name}"
    def labelString     = ""
    if( target_node_info.containsKey("label_string") ) {
        def previous_labels = "${target_node_info["label_string"]}"
        if( "${previous_labels}".split(' ').contains("${thisLabelString}") ) {
            labelString = "${previous_labels}"
        } else {
            labelString = "${thisLabelString} ${previous_labels}"
        }
    } else {
        labelString = "${thisLabelString}"
    }

    def sshHost        = parent_node_info["host"]
    def sshPort        = parent_node_info["port"]
    def sshCredentials = parent_node_info["credential_id"]
    def userId = "jenkins"
    def description = "${node_name}"

    create_slave_node(
        instance,
        node_name,
        remoteFS,
        numExecutors.toString(),
        labelString,
        sshHost,
        sshPort,
        sshCredentials,
        userId,
        description
    )

    // Save configurations
    instance.save()

    return "${thisLabelString}"
}

def __main__() {


    try {

        def buildEnv = build.getEnvironment(listener)

        if (buildEnv["OBS_DISPATCHER_LOAD_BALANCING_ENABLED"] != "1") {
            println "FEATURE NOT ENABLED"
            return
        }

        def project_name = ""
        def project_name_hash = ""
        def request_file = ""
        try {
            def node_env = get_node_to_create_env(buildEnv["WORKSPACE"])
            println node_env
            project_name = node_env["PROJECT_NAME"]
            request_file = node_env["REQUEST_FILE"]
            println project_name
            println request_file
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(project_name.bytes);
            project_name_hash = new BigInteger(1, digest.digest());
            println project_name_hash
            project_name_hash = project_name_hash % 100000000;
            println project_name_hash
        } catch(Exception ex) {
            println "No env file. Skip creating node"
            return
        }

        // Create Jenkins Node
        def thisLabelString = create_new_node("${project_name}", "${project_name_hash}", "${buildEnv["JENKINS_HOME"]}")

        // Append created node to trigger env
        append_backend_selection("${buildEnv["WORKSPACE"]}", "${request_file}", "${thisLabelString}")

    } catch(Exception e) {
        println 'Fail to create new node'
        return
    }

}

__main__()

return 0

