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

import java.io.File

import org.gradle.api.Plugin
import org.gradle.api.tasks.Exec
import org.gradle.util.VersionNumber

import org.gradle.api.Project

/**
 * Project extension to configure Python build environment.
 *
 */
class MinicondaExtension {
    File bootstrapDirectory
    File buildEnvironmentDirectory
    String minicondaVersion
    String minicondaExecutable32
    String minicondaExecutable64
}


class MinicondaPlugin implements Plugin<Project> {
    def os = System.getProperty('os.name').replaceAll(' ', '')

    def resolveMiniconda(project, is64, myExt) {
        def myExtension = "sh"
        if (os.contains("Windows")) {
            os = "Windows"
            myExtension = "exe"
        }
        def myName = "Miniconda2"
        // versions <= 3.16 were named "Miniconda-${version}"
        if (VersionNumber.parse(myExt.minicondaVersion) <= VersionNumber.parse("3.16")) {
            myName = "Miniconda"
        }
        project.dependencies {
            if (is64) {
                minicondaInstaller64(group: "miniconda", name: myName, version: myExt.minicondaVersion) {
                    artifact {
                        name = myName
                        type = myExtension
                        classifier = "$os-x86_64"
                        extension = myExtension
                    }
                }
            } else {
                minicondaInstaller32(group: "miniconda", name: myName, version: myExt.minicondaVersion) {
                    artifact {
                        name = myName
                        type = myExtension
                        classifier = "$os-x86"
                        extension = myExtension
                    }
                }

            }
        }
    }


    def createBootstrapPython(project, is64, minicondaBootstrapVersionDir) {
        def conf = is64 ? project.configurations.minicondaInstaller64 : project.configurations.minicondaInstaller32

        project.task([type: Exec], "bootstrapPython" + (is64 ? "64" : "32")) {
            def installDir = "$minicondaBootstrapVersionDir${is64 ? '_64' : '_32'}"

            outputs.dir(installDir)
            onlyIf {
                !(new File(installDir).exists())
            }

            if (os.contains("Windows")) {
                commandLine conf.singleFile, "/InstallationType=JustMe", "/AddToPath=0", "/RegisterPython=0", "/S", "/D=$installDir"
            } else {
                commandLine "bash", conf.singleFile, "-b", "-p", installDir
            }
//            doFirst {
//                if (!myExt.bootstrapDirectory.exists()) {
//                    myExt.bootstrapDirectory.mkdir()
//                }
//            }
        }
    }

    @Override
    void apply(Project project) {
        def myExt = project.extensions.create("miniconda", MinicondaExtension.class)


        project.repositories {
            ivy {
                url "http://repo.continuum.io"
                layout "pattern", {
                    artifact "[organisation]/[module]-[revision]-[classifier].[ext]"
                }
            }
        }


        project.configurations {
            minicondaInstaller32
            minicondaInstaller64
        }

        project.afterEvaluate {
            def conf32 = project.configurations.minicondaInstaller32
            conf32.incoming.beforeResolve {
                resolveMiniconda(project, false, myExt)
            }

            def conf64 = project.configurations.minicondaInstaller64
            conf64.incoming.beforeResolve {
                resolveMiniconda(project, true, myExt)
            }

            def minicondaBootstrapVersionDir = new File(myExt.bootstrapDirectory, myExt.minicondaVersion)

            createBootstrapPython(project, true, minicondaBootstrapVersionDir)
            createBootstrapPython(project, false, minicondaBootstrapVersionDir)



            myExt.minicondaExecutable32 = new File("${minicondaBootstrapVersionDir}_32/${Os.isFamily(Os.FAMILY_WINDOWS) ? 'Scripts/conda.exe' : 'bin/conda'}")

            myExt.minicondaExecutable64 = new File("${minicondaBootstrapVersionDir}_64/${Os.isFamily(Os.FAMILY_WINDOWS) ? 'Scripts/conda.exe' : 'bin/conda'}")

        }
    }
}


apply plugin: MinicondaPlugin


miniconda {
    bootstrapDirectory = new File(buildDir, '.miniconda')
    buildEnvironmentDirectory = new File(buildDir, 'MinicondaEnvs')
    minicondaVersion = 'latest'
    //minicondaExecutable32 - initialized during configuration phase
    //minicondaExecutable64 - initialized during configuration phase
}


def condaCreate(project, name, version, cl) {
    def lst = cl()

    return task("conda create $name") {

        def env = file("$miniconda.buildEnvironmentDirectory/$name")
        def is64 = name.endsWith("_64")

        if (is64) {
            dependsOn "bootstrapPython64"
        } else {
            dependsOn "bootstrapPython32"
        }

        inputs.property("packages", lst)
        outputs.dir(env)

        onlyIf {
            !env.exists()
        }

        doLast {
            project.exec {
                commandLine is64 ? miniconda.minicondaExecutable64 : miniconda.minicondaExecutable32, "create", "-p", env, "-y", "-f", "python=$version", "cython", "numpy", "nose", "ipython", "pip"
            }

            lst.collect { e -> [file("$miniconda.buildEnvironmentDirectory/$name/${Os.isFamily(Os.FAMILY_WINDOWS) ? 'Scripts/pip.exe' : 'bin/pip'}"), "install"] + e }.each {
                cmd ->
                    project.exec {
                        commandLine cmd.flatten()
                    }
            }
        }
    }
}

task setupMinicondaEnvWin() {
    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        dependsOn condaCreate(project, "py27_64", "2.7") {
            ["django>=1.7,<1.8",
             ["-U", "setuptools>=0.9"],
             ["-U", "pip>=1.4", "wheel>=0.21", "twine"]
            ]
        },
                condaCreate(project, "py34_64", "3.4") {
                    ["django>=1.9",
                     ["-U", "setuptools>=0.9"],
                     ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
                },
                condaCreate(project, "py35_64", "3.5") {
                    ["django>=1.9",
                ["-U", "setuptools>=0.9"],
                     ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
                },

        condaCreate(project, "py27_32", "2.7") {
            ["django>=1.7,<1.8",
             ["-U", "setuptools>=0.9"],
             ["-U", "pip>=1.4", "wheel>=0.21", "twine"]
            ]
        },
        condaCreate(project, "py34_32", "3.4") {
            ["django>=1.9",
             ["-U", "setuptools>=0.9"],
             ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
        }, condaCreate(project, "py35_32", "3.5") {
                    ["django>=1.9",
                     ["-U", "setuptools>=0.9"],
                     ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
                }


    }
}

task setupMinicondaEnvMac() {
    if (Os.isFamily(Os.FAMILY_MAC)) {

        dependsOn          \
              condaCreate(project, "py27_64", "2.7") {
            ["django>=1.7,<1.8",
             ["-U", "setuptools>=0.9"],
             ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
        },
                condaCreate(project, "py34_64", "3.4") {
                    ["django>=1.9",
                     ["-U", "setuptools>=0.9"],
                     ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
                },
                condaCreate(project, "py35_64", "3.5") {
                    ["django>=1.9",
                     ["-U", "setuptools>=0.9"],
                     ["-U", "pip>=1.4", "wheel>=0.21", "twine"]]
                }
    }
}


task buildBinariesOnWindows(type: Exec, dependsOn: 'setupMinicondaEnvWin') {
    workingDir projectDir

    environment PYTHONPATH: projectDir,
                MINICONDA32_ENVS: miniconda.buildEnvironmentDirectory,
                MINICONDA64_ENVS: miniconda.buildEnvironmentDirectory

    commandLine "${miniconda.buildEnvironmentDirectory}/py27_32/python.exe", "build_tools/build_binaries_windows.py"
}

task buildOnMac(dependsOn: 'setupMinicondaEnvMac') << {

    println "Hi Mac"
}


task buildBinaries() {

    if (Os.isFamily(Os.FAMILY_WINDOWS)) {
        dependsOn buildBinariesOnWindows
    } else if (Os.isFamily(Os.FAMILY_MAC)) {
        dependsOn buildOnMac
    }


}
