import org.apache.tools.ant.taskdefs.condition.Os

/*
 * This build file was auto generated by running the Gradle 'init' task
 * by 'nathandunn' at '3/14/16 12:08 PM' with Gradle 2.11
 *
 * This generated file contains a commented-out sample Java project to get you started.
 * For more details take a look at the Java Quickstart chapter in the Gradle
 * user guide available at https://docs.gradle.org/2.11/userguide/tutorial_java_projects.html
 */


buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
    }
}

plugins {
}

// In this section you declare where to find the dependencies of your project
repositories {
    // Use 'jcenter' for resolving your dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}


ext {
    npmCommand = Os.isFamily(Os.FAMILY_WINDOWS) ? 'npm.cmd' : 'npm'
    githubURL = "https://github.com/"
    nodeModulesDirectory = "node_modules"
    jbrowseDirectory = "jbrowse"
    pluginsDirectory = "jbrowse/plugins"
    defaultGitMethod = "shell"
}


ant.importBuild 'build.xml'

// Apply the java plugin to add support for Java
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'eclipse'
apply plugin: 'idea'

// In this section you declare the dependencies for your production and test code
dependencies {
}

def jbrowseConfig
def jbrowsePlugins

task evaluateJBrowseConfigs {
    // gradle read in Config.groovy
    def config = new ConfigSlurper().parse(new File("grails-app/conf/Config.groovy").toURI().toURL())
    jbrowseConfig = config.jbrowse
    jbrowsePlugins = jbrowseConfig.plugins
    // if apollo-config.groovy exists, read THAT in and apply it as well
    File testFile = new File("./apollo-config.groovy")
    def revisedConfig
    if (testFile.exists()) {
        revisedConfig = new ConfigSlurper().parse(new File("apollo-config.groovy").toURI().toURL())
    } else {
        try {
            Class scriptClass = getClass().classLoader.loadClass('apollo-config.groovy')
            revisedConfig = new ConfigSlurper().parse(scriptClass)
        } catch (e) {
            logger.error "No log file found in classpath."
        }
    }

    if (revisedConfig) {
        jbrowseConfig = revisedConfig.jbrowse ?: jbrowseConfig
        jbrowsePlugins << revisedConfig.jbrowse.plugins
    }

    logger.quiet "Final JBrowse settings ${jbrowseConfig}"
    logger.quiet "Final plugins ${jbrowsePlugins}"
}


task cloneRepo3(dependsOn: evaluateJBrowseConfigs) {
    doLast {
        println "installing $jbrowseConfig"
        File jbrowseFile = new File("jbrowse")
        if (jbrowseConfig.git) {
            def git = jbrowseConfig.git
            if (jbrowseFile.exists()) {
                if ((git.alwaysRecheck || git.alwaysPull)) {
                    if (!git.hash) {
                        String branchName = (git.branch ?: git.tag) ?: "dev"
                        exec {
                            workingDir 'jbrowse'
                            commandLine 'git', 'pull', 'origin', branchName

                        }
                    }
                }
            } else {
                // always default to dev if nothing found
                String branchName = (git.branch ?: git.tag) ?: "dev"
                println "branchName ${branchName}"
                exec {
                    commandLine = ['git', 'clone', git.url,'--branch', branchName, '--single-branch']
                }
            }
        } else if (jbrowseConfig.url && !jbrowseFile.exists()) {
            if (jbrowseConfig.url.type == "zip") {
                // assume its a zip
                def f = new File("jbrowse-directory" + ".zip")
                new URL(jbrowseConfig.url.url).withInputStream { i -> f.withOutputStream { it << i } }
                File tempFile = File.createTempDir()
                ant.unzip(src: f.absolutePath, dest: tempFile, overwrite: false)
                org.gradle.util.GFileUtils.moveDirectory(new File(tempFile.absolutePath + "/" + jbrowseConfig.url.fileName), jbrowseFile)
                org.gradle.util.GFileUtils.deleteDirectory(new File(jbrowseFile.absolutePath + "/sample_data"))
                tempFile.deleteDir()
                f.delete()
            } else {
                //            new URL(jbrowseConfig.url.url).withInputStream { i -> f.withOutputStream { it << i } }
                logger.error "Must specify JBrowse download type"
                throw new GradleException("Unable to specify JBrowse download type")
            }
        }
    }
}

//task copyResourcesDev(dependsOn: installJBrowse) {
task copyResourcesDev() {
    doLast {
        File jbrowse = new File("web-app/jbrowse")
        logger.quiet "Found JBrowse directory ${jbrowse.file}"
        if (jbrowse.exists()) {
            tasks["copy-resources-dev"].execute()
        } else {
            tasks["copy-resources"].execute()
        }
//		installJBrowseLocal.execute()
    }
}

//    task copyApolloPlugin(dependsOn: installJBrowse, type: Copy) {
task copyApolloPlugin(type: Copy) {
    doLast{
        logger.quiet "Copying apollo plugin"
        from("client/apollo")
        into("jbrowse/plugins/WebApollo")
    }
}

task installJBrowsePlugins2 {
    doLast {
        logger.quiet "Installing JBrowse plugins  ${jbrowsePlugins}"

        for (plugin in jbrowsePlugins) {
            def path = pluginsDirectory + "/" + plugin.key
            logger.quiet "Evaluating plugin ${plugin}"
            def pluginExists = confirmPlugin(path)
            if (plugin.value.included == true) {
                if (pluginExists) {
                    logger.quiet "Plugin ${path} exists and appears valid."
                } else {
                    logger.error "Error: There is a problem with the plugin at ${path}!"
                    throw new GradleException("Included plugin ${path} not found in build")
                }
            } else if (plugin.value.included == false) {
                if (pluginExists) {
                    logger.quiet "Plugin ${path} exists but is not included."
                } else {
                    logger.quiet "Plugin ${path} does not exist but is also not included."
                }
            } else if (plugin.value.git) {
                logger.quiet "Plugin is supplied by git"
                if (pluginExists) {
                    logger.quiet "Plugin ${path} exists and appears valid."
                    if (plugin.value.alwaysRecheck || plugin.value.alwaysPull) {
                        logger.quiet "Checking out branch ${plugin.value.branch}"
                        if (plugin.value.tag) {
                            checkoutBranch(new File(path), "tags/${plugin.value.tag}")
                        } else if (plugin.value.branch) {
                            checkoutBranch(new File(path), plugin.value.branch)
                        }

                        if (plugin.value.alwaysPull) {
                            logger.quiet "Pulling ${plugin.value.git}"
                            gitPull(new File(path))
                        }
                    }
                } else {
                    logger.quiet "Cloning '${plugin.value.git}' into '${path}'"
                    // checking if gitMethod exists, otherwise setting the default to 'shell'
                    //                def gitMethod = plugin.value.gitMethod ? plugin.value.gitMethod : defaultGitMethod
                    // Currently we only support the shell git method.
                    // At a future time (when we install plugins as npm modules in JBrowse), this method can be optional.
                    def gitMethod = defaultGitMethod
                    cloneRepo(plugin.value.git, path, plugin.value.branch, 0, gitMethod)
                    logger.quiet "Cloned from ${plugin.value.git} into ${path}"
                }
            } else if (plugin.value.url == true) {
                // TODO: test
                if (!pluginExists) {
                    logger.quiet "Plugin ${path} exists and appears valid. Downloading..."
                    def f = new File(path)
                    new URL(plugin.value.url).withInputStream { i -> f.withOutputStream { it << i } }
                }
            } else {
                logger.error "Invalid plugin settings"
                throw new GradleException("Invalid plugin settings for path [${path}] and setting [${plugin.value}]")
            }
        }
    }
}


def confirmPlugin(String path) {
    File file = new File(path)
    return file.exists() && file.isDirectory() && file.canRead()
}

def cloneRepo(String url, String directory, String branch, Integer depth = 0, String method = defaultGitMethod) {
    logger.quiet "Cloning ${url} via ${method}"
    switch (method) {
        case "npm":
            cloneRepoNpm(url, directory, branch)
            break
        case "shell":
            cloneRepoShell(url, directory, branch, depth)
            break
        default:
            throw new GradleException("Error in cloneRepo: invalid method ${method}")
            break
    }
}

def cloneRepoShell(String url, String directory, String branch, Integer depth) {
    String depthString = depth != null && depth > 0 ? " --recursive --depth ${depth} " : ""
    def commandToExecute = "git clone ${depthString} ${url} ${directory} "
    logger.quiet "Command to execute [${commandToExecute}]"
    def proc = commandToExecute.execute()
    def outputStream = new StringBuffer();
    def errorStream = new StringBuffer();
    proc.waitForProcessOutput(outputStream, errorStream);
    println outputStream
    println errorStream

    if (!branch) {
        branch = "master"
    } else if (branch.startsWith("tags")) {
        fetchTags(new File(directory))
    }
    checkoutBranch(new File(directory), branch)
//    tasks.installJBrowseScript.execute()
}

def cloneRepoNpm(String url, String directory, String branch) {
    logger.quiet "Cloning repo with ${url},${directory},${branch}"
    String finalUrl = url + (branch ? "#${branch}" : "")
    finalUrl = finalUrl.replaceAll("tags/", "")
    if (finalUrl.startsWith(githubURL)) {
        finalUrl = finalUrl.substring(githubURL.length())
        logger.quiet "Final github URL: ${finalUrl}"
    } else {
        logger.quiet "Final non-github URL: ${finalUrl}"
    }
    exec {
        logger.quiet "Using npm to install: ${finalUrl}"
        commandLine "npm", "install", finalUrl, "--ignore-scripts"
    }
    println "CURRENT DIRECTORY"
    println new File(".").absolutePath
//    commandLine "npm","install",finalUrl,"--ignore-scripts"


    File npmDirectory = new File('node_modules')
    if (finalUrl.contains("#") && (finalUrl.endsWith("jbrowse") || finalUrl.split("#")[0].endsWith("jbrowse"))) {
        logger.quiet "Moving JBrowse into position ${finalUrl}"
        tasks.moveNodeModulesJBrowse.execute()
        tasks.installJBrowseScript.execute()
    } else {
        npmDirectory.eachDir {
            File targetFile = new File(directory)
            logger.quiet "Moving plugin into place: ${npmDirectory.absolutePath} -> ${targetFile}"
            it.renameTo(targetFile)
        }
    }

    // delete on exit
    if (npmDirectory.exists() && npmDirectory.listFiles()?.length == 0) {
        assert npmDirectory.delete()
    }
}

task installJBrowseTools() {
    doLast {
        exec {
            workingDir 'jbrowse'
            commandLine 'node', './utils/jb_setup.js'
        }
    }
}

// Get the path for the locally installed binaries
//task npmBin {
//    doLast {
//        new ByteArrayOutputStream().withStream { os ->
//            exec {
//                executable = npmCommand
//                args = ['bin']
//                standardOutput = os
//            }
//            ext.binPath = os.toString().trim() + File.separator
//        }
//    }
//}
//
//// Install packages from package.json
//task npm(type: Exec) {
//    description = "Grab NodeJS dependencies (from package.json)"
//    commandLine = [npmCommand, "install"]
//    inputs.file "package.json"
//    outputs.dir "node_modules"
//    tasks.npmBin.execute()
//}

task cleanAll(type: Delete) {
    doLast{
        delete 'web-app/WEB-INF/deploy', 'web-app/annotator', 'target'
    }
}

def fetchTags(File file) {
    logger.quiet "Fetching tags"
    if (!isValidGitDirectory(file)) return

    def processBuilder = new ProcessBuilder()
    processBuilder.redirectErrorStream(true)
    processBuilder.directory(file)
    processBuilder.command("git", "fetch", "--tags")
    def proc = processBuilder.start()
    def outputStream = new StringBuffer();
    def errorStream = new StringBuffer();
    proc.waitForProcessOutput(outputStream, errorStream);
    if (outputStream.length() > 0) println outputStream
    if (errorStream.length() > 0) println "Error: " + errorStream
}

Boolean isValidGitDirectory(File file) {
    File gitFile = new File(file.absolutePath + "/.git")
    if (!gitFile.exists() || !gitFile.canRead()) {
        logger.warn "Not a valid git directory so no git operations will run ${file.absolutePath}"
        return false
    }
    return true
}

def checkoutBranch(File file, String branch) {
    logger.quiet "Checkout out branch ${branch}"

    if (!isValidGitDirectory(file)) return

    def processBuilder = new ProcessBuilder()
    processBuilder.redirectErrorStream(true)
    processBuilder.directory(file)
    if (branch.startsWith("tags/")) {
        branch = branch.substring("tags/".length())
    }
    processBuilder.command("git", "checkout", branch)
    def proc = processBuilder.start()
    def outputStream = new StringBuffer();
    def errorStream = new StringBuffer();
    proc.waitForProcessOutput(outputStream, errorStream);
    if (outputStream.length() > 0) println outputStream
    if (errorStream.length() > 0) println "Error: " + errorStream

}

def gitPull(File file) {
    logger.quiet "git pull ${file.absolutePath}"
    if (!isValidGitDirectory(file)) return

    def processBuilder = new ProcessBuilder()
    processBuilder.redirectErrorStream(true)
    processBuilder.directory(file)
    processBuilder.command("git", "pull")
    def proc = processBuilder.start()
    def outputStream = new StringBuffer();
    def errorStream = new StringBuffer();
    proc.waitForProcessOutput(outputStream, errorStream);
    if (outputStream.length() > 0) println outputStream
    if (errorStream.length() > 0) println "Error: " + errorStream
}

task updateRepo2(dependsOn: evaluateJBrowseConfigs) {

    doLast {
        def git = jbrowseConfig.git
        if (!git.hash) {
            String branchName = (git.branch ?: git.tag) ?: "dev"
            exec{
                workingDir = 'jbrowse'
                commandLine = ['git', 'pull', 'origin', branchName]
            }
        }
    }
}

task installJBrowse {
    doLast {
        if (!file('jbrowse').exists()) {
            println "Cloning a new JBrowse"
            tasks.cloneRepo3.execute()
        } else {
            println "JBrowse already exists"
            tasks.updateRepo2.execute()
        }
        exec {
            workingDir 'jbrowse'
            commandLine 'yarn'
        }
        exec {
            workingDir 'jbrowse'
            executable 'rm' args '-rf','plugins/WebApollo'
        }
        exec {
            workingDir 'jbrowse'
            executable 'cp' args '-r', '../client/apollo', 'plugins/WebApollo'
        }
        exec {
            workingDir 'jbrowse/plugins/WebApollo'
            commandLine 'yarn'
        }
        tasks.installJBrowsePlugins2.execute()
        exec {
            workingDir 'jbrowse'
            commandLine './setup.sh'
        }
        tasks.copyJBrowseDirectory.execute()
    }
}

task installJBrowseWebOnly {
    doLast {
        if (!file('jbrowse').exists()) {
            println "Cloning a new JBrowse"
            tasks.cloneRepo3.execute()
        } else {
            println "JBrowse already exists"
            tasks.updateRepo2.execute()
        }
        exec {
            workingDir 'jbrowse'
            commandLine 'yarn'
        }
        exec {
            workingDir 'jbrowse'
            executable 'rm' args '-rf','plugins/WebApollo'
        }
        exec {
            workingDir 'jbrowse'
            executable 'cp' args '-r', '../client/apollo', 'plugins/WebApollo'
        }
        exec {
            workingDir 'jbrowse/plugins/WebApollo'
            commandLine 'yarn'
        }
        tasks.installJBrowsePlugins2.execute()
        exec {
            workingDir 'jbrowse'
            commandLine 'npm', 'run', 'build'
        }
        tasks.copyJBrowseDirectory.execute()
    }
}

task copyJBrowseDirectory(type: Copy) {
    from('jbrowse') {
        exclude "sample_data/**", "node_modules/**", "tests/**"
    }
    into("web-app/jbrowse/")
}

task cleanJBrowse(type: Delete) {
    doLast{
        delete 'jbrowse', 'web-app/jbrowse'
    }
}

