plugins {
    id 'org.hidetake.ssh' version '1.1.4'
}

apply plugin: 'com.android.library'
apply plugin: 'checkstyle'
apply plugin: 'maven'
apply plugin: 'signing'


version = "${SEMVER}".replace("_", ".")

android {
    compileSdkVersion 26
    buildToolsVersion '26.0.2'

    defaultConfig {
        minSdkVersion 18
        project.archivesBaseName = "sweetblue"
    }

    buildTypes {
        release {
            minifyEnabled false
        }
        debug {
            minifyEnabled false
        }
    }

    // Commenting out Java 8 support for now until the lambda issue can be fixed
    // See https://issuetracker.google.com/issues/68977385
//    compileOptions {
//        sourceCompatibility = '1.8'
//        targetCompatibility = '1.8'
//    }
}

// Set base variables
ext.JAR_BASE_NAME = "sweetblue_${SEMVER}"
ext.BUNDLE_FOLDER = projectDir.absolutePath + "/" + STAGE + "/" + JAR_BASE_NAME
ext.JAR_DIR = BUNDLE_FOLDER + "/jars"
ext.JAR_NAME = JAR_BASE_NAME + ".jar"
ext.JAVADOC_JAR_NAME = JAR_BASE_NAME + "-javadoc.jar"
ext.SOURCES_JAR_NAME = JAR_BASE_NAME + "-sources.jar"
ext.AS_BUILD_SUFFIX = "/android_studio/build"
ext.AS_APP_BUILD_SUFFIX = "/android_studio/app/build"
ext.AS_SUFFIX = "/android_studio/sweetblue"
ext.ECLIPSE_SUFFIX = "/eclipse/lib"


// List of all of the modules' build.gradle files
def moduleFiles = files(rootDir.getAbsolutePath() + "/integration/build.gradle") \
        + files(rootDir.absolutePath + "/library/build.gradle") \
        + files(rootDir.absolutePath + "/sweetunit/build.gradle") \
        + files(rootDir.absolutePath + "/tester/build.gradle") \
        + files(rootDir.absolutePath + "/lint.gradle")

repositories {
    mavenCentral()
    google()
}

dependencies {
}

// Task definitions
task checker(type: Checkstyle) {
    configFile file("../scripts/config/checkstyle/checkstyle.xml")
    source '../src'
    include '**/*.java'
    exclude '**/gen/**'
    classpath = files()
}

// Creates Sweetblue jar
task jar(type: Jar, dependsOn: "compileReleaseSources") {
    from 'build/intermediates/classes/release'
    archiveName = JAR_NAME
    destinationDir = new File(JAR_DIR)
    group = "sweetblue"
    description = "Generates a Sweetblue jar."
}

// Create the source Jar
task sourceJar(type: Jar, dependsOn: jar) {
    archiveName = SOURCES_JAR_NAME
    classifier = 'sources'
    from android.sourceSets.main.java.sourceFiles
    destinationDir = new File(JAR_DIR)
    group = "sweetblue"
    description = "Generates SweetBlue sources jar."
}

// disable the crazy super-strict doclint tool in Java 8
if (JavaVersion.current().isJava8Compatible()) {
    tasks.withType(Javadoc) {
        options.addStringOption('Xdoclint:none', '-quiet')
    }
}

// Generate javadocs
task gendocs(type: Javadoc) {
    String path = rootDir.absolutePath + "/scripts/assets/doc_style.css"
    options.stylesheetFile = new File(path)
    options.windowTitle = "SweetBlue"
    options.memberLevel = JavadocMemberLevel.PROTECTED
    options.author = true
    //exclude '**/backend/**'
    //excludes = ["com.idevicesinc.sweetblue.backend"]
    String home = android.getSdkDirectory().getAbsolutePath()
    options.linksOffline('http://d.android.com/reference', home + '/docs/reference')
    String v = "${SEMVER}"
    version = v.replace("_", '.')
    options.setDocTitle("SweetBlue " + version + " API")
    destinationDir = new File("${BUNDLE_FOLDER}/docs/api")
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))

    // Check for warnings, and cause build to fail if there are any.
    // This is a temporary solution until a more official solution
    // makes it's way into Gradle.
    def outputEvents = []
    def listener = new StandardOutputListener() {
        void onOutput(CharSequence output) {
            outputEvents << output
        }
    }
    doFirst {
        getLogging().addStandardOutputListener(listener)
    }
    doLast {
        getLogging().removeStandardOutputListener(listener)
        outputEvents.each { e ->
            if (e =~ " warning -") {
                throw new GradleException("You have some javadoc warnings, please fix them!")
            }
        }
    }
    group = "sweetblue"
}

// Create javadoc jar file
task javadocJar(type: Jar, dependsOn: gendocs) {
    archiveName = JAVADOC_JAR_NAME
    classifier = 'javadoc'
    from gendocs.destinationDir
    destinationDir = new File(JAR_DIR)
    group = "sweetblue"
    description = "Generates the javadoc jar."
}

// Copy the src and res directories, and Readme file
task copyFiles {
    group = "sweetblue"

    doLast {
        checkDir("${BUNDLE_FOLDER}")
        copy {
            from "src/main/java"
            into "${BUNDLE_FOLDER}/src"
        }
        copy {
            from "src/main/res"
            into "${BUNDLE_FOLDER}/res"
        }
        copy {
            from "../README.md"
            into BUNDLE_FOLDER
        }
    }
}

static def checkDir(String dir) {
    File f = new File(dir)
    if (!f.exists()) {
        f.mkdirs()
    }
}

// Pull down the samples repo
task getSamples(dependsOn: [jar, sourceJar, javadocJar, "assembleRelease"]) {
    group = "sweetblue"

    doLast {
        // If the directory already exists, wipe it out, and start over
        // again, so this doesn't fail the build
        String samplePath = projectDir.absolutePath + "/${STAGE}/samples"
        File f = new File(samplePath)
        if (f.exists()) {
            delete "${samplePath}"
        }

        // When running on the build server, we need to inject the username and password
        // otherwise it will pull the un/pw of the current user.
        String gu = System.getenv("G_UNAME")
        def r
        if (!gu || !gu.trim()) {
            r = "git clone https://bitbucket.org/idevices/sweetblue_samples.git ${samplePath}".execute()
        } else {
            String run = "git clone https://" + System.getenv("G_UNAME") + ":" + System.getenv("G_PW") + "@bitbucket.org/idevices/sweetblue_samples.git ${samplePath}"
            r = run.execute()
        }
        r.waitFor()
        String v = r.exitValue()
        if (!v.equals("0")) {
            throw new RuntimeException(r.errorStream.text)
        }
    }
}


ext.mainJar = "${BUNDLE_FOLDER}/jars/${JAR_BASE_NAME}.jar"
ext.sourcesJar = "${BUNDLE_FOLDER}/jars/${JAR_BASE_NAME}-sources.jar"
ext.javadocJar = "${BUNDLE_FOLDER}/jars/${JAR_BASE_NAME}-javadoc.jar"
ext.mainAar = "build/outputs/aar/sweetblue-release.aar"

// Copy the samples to the bundle folder
task copySamples(dependsOn: [copyFiles, getSamples]) {
    group = "sweetblue"

    doLast {
        String d = "${STAGE}/samples/samples"
        copy {
            from d
            into "${BUNDLE_FOLDER}/samples"
        }
    }
}

// Creates a new gradle build task for the input build.gradle file
def buildSampleTask(buildDir) {
    return tasks.create("build${buildDir}SampleTask", GradleBuild) {
        buildFile = "${buildDir}/android_studio/app/build.gradle"
        tasks = ['assemble']
    }
}

// Copy the new sweetblue jar, sourcejar, and javadoc jars to each sample AS
// project, and build
// Copy the aar file to the bundle folder for inclusion in the zip file
task copyAndRenameJars(dependsOn: copySamples) {
    group = "sweetblue"

    doLast {
        File sampleDir = new File("${BUNDLE_FOLDER}/samples/")
        FileCollection collection = files {
            sampleDir.listFiles(new FileFilter() {
                @Override
                boolean accept(File file) {
                    return !file.isHidden()
                }
            })
        }
        collection.each { File file ->
            copy {
                from mainAar
                into file.getAbsolutePath() + AS_SUFFIX
            }
            copy {
                from mainJar
                into file.getAbsolutePath() + ECLIPSE_SUFFIX
                rename("_${SEMVER}", "")
            }
            copy {
                from sourcesJar
                into file.getAbsolutePath() + ECLIPSE_SUFFIX
                rename("_${SEMVER}", "")
            }
            copy {
                from javadocJar
                into file.getAbsolutePath() + AS_SUFFIX
                rename("_${SEMVER}", "")
            }
            copy {
                from javadocJar
                into file.getAbsolutePath() + ECLIPSE_SUFFIX
                rename("_${SEMVER}", "")
            }
            copy {
                from '../local.properties'
                into file.getAbsolutePath() + "/android_studio"
            }
//            File outerBuildFile = new File(file.getAbsolutePath() + "/android_studio/build.gradle")
//            String contents = outerBuildFile.getText("UTF-8")
//            contents = contents.replace("classpath", "// classpath")
//            outerBuildFile.write(contents, "UTF-8")
            // TODO - Fix this! With the latest APIs, this no longer works.
//            buildSampleTask(file.getAbsolutePath()).execute()
//            contents = contents.replace("// classpath", "classpath")
//            outerBuildFile.write(contents, "UTF-8")
            delete(file.getAbsolutePath() + "/android_studio/local.properties")
            
            // Delete build folders to save on space in the resulting zip file
            delete(file.getAbsolutePath() + AS_APP_BUILD_SUFFIX)
            delete(file.getAbsolutePath() + AS_BUILD_SUFFIX)
        }
        copy {
            from mainAar
            into "${BUNDLE_FOLDER}/aar/"
        }
    }
}

task copyGPL(dependsOn: copyAndRenameJars) {
    group = "sweetblue"

    doLast {
        copy {
            from "../LICENSE"
            into "${BUNDLE_FOLDER}"
        }
        delete "${BUNDLE_FOLDER}/sweetblue_commercial_license.pdf"
    }
}

ext.SB_COMM_LICENSE = System.getenv("SB_COMM_LICENSE")

task copyCommercialLicense(dependsOn: copyAndRenameJars) {
    group = "sweetblue"

    doLast {
        copy {
            from "${SB_COMM_LICENSE}"
            into "${BUNDLE_FOLDER}"
        }
        delete "${BUNDLE_FOLDER}/LICENSE"
    }
}

task zipTrial(type: Zip, dependsOn: copyGPL) {
    from "${BUNDLE_FOLDER}"
    archiveName = "sweetblue.zip"
    destinationDir = new File(projectDir.absolutePath + "/${STAGE}")
    group = "sweetblue"
}

task zipCommercial(type: Zip, dependsOn: copyCommercialLicense) {
    from "${BUNDLE_FOLDER}"
    archiveName = "sweetblue_commercial.zip"
    destinationDir = new File(projectDir.absolutePath + "/${STAGE}")
    group = "sweetblue"
}

task zipJar(dependsOn: [zipTrial, zipCommercial]) {
    group = "sweetblue"
    description = "Pulls down samples, builds them, and zips up all SweetBlue files."

    doLast {
        copy {
            from projectDir.absolutePath + "/${STAGE}/sweetblue.zip"
            into projectDir.absolutePath + "/${STAGE}"
            rename { String fileName ->
                fileName.replace("sweetblue.zip", "${JAR_BASE_NAME}.zip")
            }
        }
    }
}

static String getHexString(byte[] data) {
    def hex = "0123456789abcdef".toCharArray()
    StringBuilder b = new StringBuilder()
    for (int i = 0; i < data.length; i++) {
        int v = data[i] & 0xFF
        b.append(hex[v >>> 4])
        b.append(hex[v & 0x0F])
    }
    return b.toString().trim()
}

import java.security.MessageDigest

task outputVersion {
    group = "sweetblue"
    description = 'Outputs the current version to version.txt file, for build server purposes.'
    doLast {
        File ver = new File('version.txt')
        ver.write(version, 'UTF-8')
    }
}

task incrementVersion() {
    doLast {
        String[] vers = "${version}".split('\\.')
        int release = Integer.parseInt(vers[2])
        release++
        String newVersion = vers[0] + "_" + vers[1] + "_" + release
        File buildFile = new File(rootDir.absolutePath + "/gradle.properties")
        String contents = buildFile.getText('UTF-8')
        contents = contents.replaceAll("SEMVER=.*", "SEMVER=${newVersion}")
        buildFile.write(contents, 'UTF-8')
    }
}

task bumpVersion {
    group = "sweetblue"
    description = "Updates readme file with the latest version number, and updates hash in Uuids.java"
    doLast {
        MessageDigest md = MessageDigest.getInstance("SHA1")
        byte[] res = md.digest(version.getBytes())
        String hash = getHexString(res)
        File uuids = new File(projectDir.absolutePath + "/src/main/java/com/idevicesinc/sweetblue/utils/Uuids.java")
        String contents = uuids.getText('UTF-8')
        contents = contents.replaceAll("BLUETOOTH_CONNECTED_HASH = \".*\"", "BLUETOOTH_CONNECTED_HASH = \"${hash}\"")
        uuids.write(contents, 'UTF-8')
        File readme = new File(rootDir.absolutePath + "/README.md")
        contents = readme.getText('UTF-8')
        contents = contents.replaceAll("version-.*-blue", "version-${version}-blue")
        contents = contents.replaceAll("sweetblue:.*'", "sweetblue:${version}'")
        readme.write(contents, 'UTF-8')
    }
}

task createAndPushGitTag {
    group = "sweetblue"
    description = 'Creates a tag based on the current version and pushes it to origin'
    doLast {
        exec {
            commandLine 'git', 'tag', "-a", "v${version}", "-m", "\"${version} Release\""
        }
        exec {
            commandLine 'git', "push", "origin", "v${version}"
        }
    }
}

task gitAddCommitPush {
    // Takes parameter "message" for git commit message
    group = "sweetblue"
    description = "Adds, commits with message, and pushes all tracked files to git"
    doLast {
        // git add -u
        String gu = System.getenv("G_UNAME")
        def r1 = "git add -u".execute()
        r1.waitFor()
        String v1 = r1.exitValue()
        if(!v1.equals("0"))
            throw new RuntimeException(r1.errorStream.text)

        // git commit -m "$message"
        String commit = "git commit -m \"" + message + "\""
        println(commit)
        def r2 = (commit).execute()
        r2.waitFor()
        String v2 = r2.exitValue()
        if(!v2.equals("0"))
        {
            throw new RuntimeException(r2.errorStream.text)
        }

        def r3 = ("git push origin HEAD").execute() // Push to current head
        r3.waitFor()
        String v3 = r3.exitValue()
        if(!v3.equals("0"))
        {
            throw new RuntimeException(r3.errorStream.text)
        }
    }
}

task bumpCompileSdkVersion (dependsOn: getSamples) {
    // Takes parameter compileSdkVersion (e.g. 25)
    group = "sweetblue"
    description = "Updates compileSdkVersion and targetSdkVersion in all inner project's build.gradle"
    doLast {
        def allFiles = moduleFiles

        // Add samples to allFiles
        File samplesDir = file(projectDir.absolutePath + "/${STAGE}/samples/samples")
        def samples = files { samplesDir.listFiles() }
        samples.each {File sample ->
            allFiles.add files(sample.absolutePath + "/android_studio/app/build.gradle") }
        println allFiles.asFileTree.files

        allFiles.each { File f ->
            String contents = f.getText('UTF-8')
            contents = contents.replaceAll("compileSdkVersion \\d+", "compileSdkVersion " + compileSdkVersion)  // Replace compileSdkVersion
            contents = contents.replaceAll("targetSdkVersion \\d+", "targetSdkVersion " + compileSdkVersion)  // Replace targetSdkVersion
            f.write(contents, 'UTF-8')
        }
    }
}

task bumpGradleVersion (dependsOn: getSamples) {
    // Takes parameter gradleVersion (e.g. 3.3)
    group = "sweetblue"
    description = "Updates the Gradle distribution version in all inner project's build.gradle"
    doLast {
        def allFiles = files(rootDir.getAbsolutePath() + "/gradle/wrapper/gradle-wrapper.properties") + files()

        File samplesDir = file(projectDir.absolutePath + "/${STAGE}/samples/samples")
        def samples = files { samplesDir.listFiles() }
        samples.each {File sample ->
            allFiles.add files(sample.absolutePath + "/android_studio/gradle/wrapper/gradle-wrapper.properties") }
        println allFiles.asFileTree.files

        allFiles.each { File f ->
            String contents = f.getText('UTF-8')
            contents = contents.replaceAll("services.gradle.org/distributions/.*zip", "services.gradle.org/distributions/gradle-" + gradleVersion + "-all.zip")  // Replace the Gradle distro version
            f.write(contents, 'UTF-8')
        }
    }
}

task bumpGradlePluginVersion (dependsOn: getSamples) {
    // Takes parameter gradlePluginVersion (e.g. 2.3.3)
    group = "sweetblue"
    description = "Updates the Gradle plugin version in all inner project's build.gradle"
    doLast {
        def allFiles = files(rootDir.absolutePath + "/build.gradle") \
        + files(rootDir.absolutePath + "/lint.gradle")

        File samplesDir = file(projectDir.absolutePath + "/${STAGE}/samples/samples")
        def samples = files { samplesDir.listFiles() }
        samples.each {File sample ->
            allFiles.add files(sample.absolutePath + "/android_studio/build.gradle") }
        println allFiles.asFileTree.files

        allFiles.each { File f ->
            String contents = f.getText('UTF-8')
            contents = contents.replaceAll("'com.android.tools.build:gradle:.*'", "'com.android.tools.build:gradle:" + gradlePluginVersion + "'")  // Replace the Gradle plugin version
            f.write(contents, 'UTF-8')
        }
    }
}


task cleanFolders {
    doLast {
        delete "${STAGE}/${STANDARD_DIR}", "${STAGE}/${PRO_DIR}", "build"
    }
}


def checkStyleWarningsFile = 'build/reports/checkstyle/checkstyle.xml'

task verifyNoCheckstyleWarnings(type: GradleBuild) {
    doLast {
        File warningsFile = file(checkStyleWarningsFile)
        if (warningsFile.exists() && warningsFile.text.contains("<error ")) {
            throw new GradleException("Checkstyle detected warnings! For more info, check $warningsFile")
        }
    }
    group = "sweetblue"
}

def buildAliases = [
        'bundleNoZip': ['copyAndRenameJars', 'bumpVersion', 'verifyNoCheckstyleWarnings'],
        'fullBuild'  : ['copyAndRenameJars', 'bumpVersion', 'verifyNoCheckstyleWarnings', 'zipJar', 'cleanFolders']
]

task fullBuild(dependsOn: [copyAndRenameJars, check, verifyNoCheckstyleWarnings, zipJar]) {
    group = "sweetblue"
    description = "Perform full build, and zip up all files for release."
}

def expandedTaskList = []

gradle.startParameter.taskNames.each {
    expandedTaskList << (buildAliases[it] ? buildAliases[it] : it)
}

gradle.startParameter.taskNames = expandedTaskList.flatten()

ext.ARCHIVA_URL = System.getenv("ARCHIVA_URL")
ext.a_user = System.getenv("ARCHIVA_USER")
ext.a_pw = System.getenv("ARCHIVA_PW")
ext.COMMERCE_PW = System.getenv("SWEETBLUE_BIG_COMMERCE_PASSWORD")

import org.gradle.plugins.signing.Sign

gradle.taskGraph.whenReady { taskGraph ->
    if (taskGraph.allTasks.any { it instanceof Sign }) {

        allprojects { ext."signing.keyId" = System.getenv("SIGN_ID") }
        allprojects { ext."signing.secretKeyRingFile" = System.getenv("SIGN_RING") }
        allprojects { ext."signing.password" = System.getenv("SIGN_PW") }
    }
}

uploadArchives {
    repositories {
        mavenDeployer {
            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

            pom.groupId = 'com.idevicesinc'
            pom.artifactId = 'sweetblue'


            repository(url: "${ARCHIVA_URL}") {
                authentication(userName: "${a_user}", password: "${a_pw}")
            }

            pom.project {
                name 'SweetBlue'
                packaging 'aar'
                description 'Android Bluetooth (BLE) library'
                url 'http://idevicesinc.com/sweetblue'
            }
        }
    }
}

task uploadInternal(type: Upload) {
    group = "upload"
    description = "Uploads artifact to our internal maven repository"
    configuration = uploadArchives.configuration
    uploadDescriptor = true
    repositories {
        mavenDeployer {
            beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

            pom.groupId = 'com.idevicesinc'
            pom.artifactId = 'sweetblue'

            repository(url: "http://10.0.1.239:5819/repository/internal") {
                authentication(userName: "${a_user}", password: "${a_pw}")
            }

            pom.project {
                name 'SweetBlue'
                packaging 'aar'
                description 'Android Bluetooth (BLE) library'
                url 'http://idevicesinc.com/sweetblue'
            }
        }
    }
}

// This is a hack to avoid signing archives when SweetBlue is run as a submodule within another project. Obviously, we need to sign to deploy,
// so we apply the signing.gradle file (which the build server swaps out before building, then clears the file when done).
apply from: 'signing.gradle'

task androidJavadocs(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

remotes {
    webServer {
        host = System.getenv("SWEETBLUE_SERVER_ADDRESS")
        user = System.getenv("SWEETBLUE_COM_FTP_USERNAME")
        password = System.getenv("SWEETBLUE_COM_FTP_PASSWORD")
    }
}

task uploadWebServerZips(dependsOn: zipJar) {
    group = "upload"
    description = "Upload zip files to iDevices public web server."

    doLast {
        ssh.run {
            session(remotes.webServer) {
                put from: projectDir.absolutePath + "/${STAGE}/${JAR_BASE_NAME}.zip", into: '/var/www/html/sweetblue/downloads'
                put from: projectDir.absolutePath + "/${STAGE}/sweetblue.zip", into: '/var/www/html/sweetblue/downloads'
            }
        }
    }
}

task uploadCommerceZip(dependsOn: zipJar) {
    group = "upload"
    description = "Upload zip file to iDevices big commerce server."

    doLast {
        // Upload zip file to the big commerce site
        def curlS = ['curl', '-T', projectDir.absolutePath + "/${STAGE}/sweetblue_commercial.zip", "--digest", "https://sweetblue%40idevicesinc.com:${COMMERCE_PW}@solutions.idevicesinc.com/dav/product_downloads/s/sweetblue.zip"]
        def curl = curlS.execute()
        curl.waitFor()
        if (curl.exitValue() != 0) {
            throw new RuntimeException("Failed to upload zip file to Big Commerce! Error: " + curl.errorStream.text)
        }
    }
}

task uploadZips(dependsOn: [uploadWebServerZips, uploadCommerceZip]) {
    group = "upload"
    description = "Upload zip files to iDevices public web and big commerce servers."
}

task uploadDocs(dependsOn: gendocs) {
    group = "upload"
    description = "Upload docs to iDevices public web server."

    doLast {
        ssh.run {
            session(remotes.webServer) {
                put from: "/${BUNDLE_FOLDER}/docs/api", into: '/var/www/html/sweetblue/docs'
            }
        }
    }
}

task uploadToIDevServer(dependsOn: [uploadZips, uploadDocs]) {
    group = "upload"
    description = "Upload zip files and docs to iDevices server."
}

artifacts {
    archives sourceJar
}