// The MIT License (MIT)
//
// Copyright (c) 2007-2019 Broad Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: 'application'

import org.apache.tools.ant.filters.ReplaceTokens

//import proguard.gradle.ProGuardTask

mainClassName = 'org.broad.igv.ui.Main'
ext.moduleName = 'org.igv'

// Build sourceset for ProGuard
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        [group: 'net.sf.proguard', name: 'proguard-gradle', version: '6.1.1']
        classpath 'net.sf.proguard:proguard-gradle:6.1.1'
    }
}

repositories {
    mavenCentral()
}

sourceSets {
    main {
        resources {
            srcDirs = ['src/main/resources', 'src/main/resources-jlfgr-1_0']
            exclude "**/*LICENSE*", "**/META-INF, **/log4j2_*.xml"
        }
    }
}

configurations {
    implementation {
        exclude group: 'com.google.code.findbugs', module: 'annotations'
        exclude group: 'com.google.code.findbugs', module: 'jsr305'
        exclude group: 'com.google.errorprone'
        exclude group: 'com.google.guava', module: 'listenablefuture'
        exclude group: 'com.google.guava', module: 'failureaccess'
        exclude group: 'com.github.lucarosellini.rJava', module: 'JRI'
        exclude group: 'commons-beanutils', module: 'commons-beanutils'
        exclude group: 'ch.qos.logback', module: 'logback-classic'
        exclude group: 'io.netty', module: 'netty-codec-http2'
        exclude group: 'com.martiansoftware', module: 'jsap'
        exclude group: 'colt', module: 'colt'
        exclude group: 'com.thoughtworks.xstream', module: 'xstream'
        exclude group: 'org.reflections', module: 'reflections'
        exclude group: 'org.codehaus.mojo', module: 'animal-sniffer-annotations'
        exclude group: 'org.checkerframework', module: 'checker-qual'
        exclude group: 'com.ibm.icu', module: 'icu4j'

        exclude group: 'xmlpull', module: 'xmlpull'
        exclude group: 'xpp3', module: 'xpp3_min'
        exclude group: 'org.tukaani', module: 'xz'

        exclude group: 'org.apache.ant', module: 'ant'
        exclude group: 'org.apache.ant', module: 'ant-launcher'
        exclude group: 'org.apache.commons', module: 'commons-math'

        // Batik deps exclusions
        exclude group: 'org.apache.xmlgraphics', module: 'batik-script'
        exclude group: 'org.apache.xmlgraphics', module: 'batik-bridge'
        exclude group: 'org.apache.xmlgraphics', module: 'batik-anim'
        exclude group: 'org.apache.xmlgraphics', module: 'batik-css'
        exclude group: 'org.apache.xmlgraphics', module: 'batik-gvt'

        exclude group: 'xml-apis', module: 'xml-apis'
        exclude group: 'xml-apis', module: 'xml-apis-ext'
        exclude group: 'xalan', module: 'serializer'
        exclude group: 'xalan', module: 'xalan'

        // Amazon deps exclusions
        //exclude group: 'software.amazon', module: 'flow'
        //exclude group: 'software.amazon.awssdk', module: 'annotations'
    }
}

dependencies {
    implementation(
            fileTree(dir: 'lib', include: '*.jar'), // first search on disk (old behavior), then maven repos
            [group: 'com.google.code.gson', name: 'gson', version: '2.8.5'],
            [group: 'org.apache.commons', name: 'commons-math3', version: '3.6.1'],
            [group: 'commons-io', name: 'commons-io', version: '2.6'],
            [group: 'org.apache.commons', name: 'commons-compress', version: '1.18'],
            [group: 'org.xerial.snappy', name: 'snappy-java', version: '1.1.7.3'],
            [group: 'org.apache.commons', name: 'commons-jexl', version: '2.1.1'],
            [group: 'org.apache.commons', name: 'commons-lang3', version: '3.9'],
            [group: 'com.github.samtools', name: 'htsjdk', version: '2.24.1'],
            [group: 'org.swinglabs', name: 'swing-layout', version: '1.0.3'],
            //[group: 'org.bidib.com.jidesoft', name: 'jide-common', version: '3.7.3'],  // no longer in Maven Central
            [group: 'com.google.guava', name: 'guava', version: '27.0.1-jre'],
            [group: 'org.apache.xmlgraphics', name: 'batik-dom', version: '1.11'],
            [group: 'org.apache.xmlgraphics', name: 'batik-svggen', version: '1.11'],
            [group: 'org.apache.xmlgraphics', name: 'batik-codec', version: '1.11'],
            [group: 'org.netbeans.external', name: 'AbsoluteLayout', version: 'RELEASE110'],

            // Amazon deps
            [group: 'software.amazon.awssdk', name: 'cognitoidentity', version: '2.16.7'],
            [group: 'software.amazon.awssdk', name: 'sts', version: '2.16.7'],
            [group: 'software.amazon.awssdk', name: 's3', version: '2.16.7']
    )

    testImplementation(
            [group: 'junit', name: 'junit', version: '4.12'],
            [group: 'com.sparkjava', name: 'spark-core', version: '2.2'],
            [group: 'org.glassfish.jersey.core', name: 'jersey-common', version: '2.22.4']
    )
}


processResources {
    // Set the current timestamp for release builds; pass in a blank property to enable (i.e. -Ptimestamp="" at CLI)
    if (timestamp == "") {
        timestamp = new Date().format("MM/dd/yyyy hh:mm aa")
    }

    filesMatching('resources/about.properties') {
        filter(ReplaceTokens,
                tokens: [VERSION  : version, BUILD: buildNumber, DEFAULT_MASTER_RESOURCE_URL: dataServerUrl,
                         TIMESTAMP: timestamp, DEVELOPMENT: development])
    }
}

jar {
    archiveFileName = 'igv.jar'
    manifest {
        attributes(
                "Permissions": "all-permissions",
                "Application-Name": "IGV",
                "Built-By": System.getProperty('user.name'),
                "Main-Class": mainClassName,
        )
    }
}

compileJava {
    inputs.property("moduleName", moduleName)
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
        ]
        classpath = files()
    }
}

tasks.withType(Test) {
    systemProperties = System.getProperties()
    systemProperties['java.awt.headless'] = 'true'
    systemProperties['make.fail'] = 'false'
    systemProperties['include.longrunning'] = 'false'
    systemProperties['ignore.ioexceptions'] = 'false'
    systemProperties['org.xerial.snappy.tempdir'] = 'build/tmp'
    maxHeapSize = '2g'
    maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
}

compileTestJava {
    inputs.property("moduleName", moduleName)
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
                '--add-modules', 'junit',
                '--patch-module', "$moduleName=" + files(sourceSets.test.java.srcDirs).asPath,
        ]
        classpath = files()
    }
}

test {
    inputs.property("moduleName", moduleName)

    doFirst {
        jvmArgs = [
                '-Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize',
                '--module-path', classpath.asPath,
                '--add-modules', 'junit',
                '--add-modules', 'ALL-MODULE-PATH',
                '--add-reads', "$moduleName=junit",
                '@scripts/test_suite.args',
                '--patch-module', "$moduleName=" + files(sourceSets.test.java.outputDir, sourceSets.main.output.resourcesDir).asPath,
        ]
        classpath = files()
    }
}

task createDist(type: Copy, dependsOn: jar) {
    from("web/IGV_64.png")
    from("scripts") {
        include '*.bat'
        include '*.sh'
        include 'igv.command'
        include 'igv.args'
        include 'readme.txt'
        include 'igvtools*'
    }
    with copySpec {
        from("${buildDir}/libs")
        from("lib") {
            include '*.jar' 
        }
        into "lib"
    }
    // Copies all Maven-fetched dependency jars
    with copySpec {
        from configurations.default {
            exclude '**/*log4j*.jar' 
        }
        into "lib"
    }
    with copySpec { from("genomes/sizes") {} into "lib/genomes" }

    into "${buildDir}/IGV-dist"
}

tasks.distZip.enabled = false
tasks.distTar.enabled = false
tasks.startScripts.enabled = false

task createDistZip(type: Zip, dependsOn: createDist) {
    archiveName = "IGV_${version}.zip"
    from("${buildDir}/IGV-dist")
    into "IGV_${version}"
}

task createLinuxDistZip(type: Zip, dependsOn: createDist) {
    archiveName = "IGV_Linux_${version}.zip"
    from("${buildDir}/IGV-dist") {
        exclude "*.bat"
        exclude "*.command"
        exclude 'igvtools*'
        exclude 'lib/genomes'
    }
    into "IGV_Linux_${version}"
}

task createLinuxWithJavaDistZip(type: Zip, dependsOn: createDist) {
    archiveName = "IGV_Linux_${version}_WithJava.zip"
    with copySpec { from jdkBundleLinux into "jdk-11" }
    from("${buildDir}/IGV-dist") {
        exclude "*.bat"
        exclude "*.command"
        exclude 'igvtools*'
        exclude 'lib/genomes'
    }
    into "IGV_Linux_${version}"
    doLast {
        if (jdkBundleLinux == "") {
            throw new GradleException("Required property not set: jdkBundleLinux");
        }
    }
}

task createMacDistZip(type: Zip, dependsOn: createDist) {
    archiveName = "IGV_Mac_${version}.zip"
    from("${buildDir}/IGV-dist") {
        exclude "*.bat"
        exclude "*_hidpi*"
        exclude "igvtools*"
        exclude 'lib/genomes'
    }
    into "IGV_Mac_${version}"
}

task createMacWithJavaDistZip(type: Zip, dependsOn: createDist) {
    archiveName = "IGV_Mac_${version}_WithJava.zip"
    with copySpec { from jdkBundleMac into "jdk-11" }
    from("${buildDir}/IGV-dist") {
        exclude "*.bat"
        exclude "*_hidpi*"
        exclude "igvtools*"
        exclude 'lib/genomes'
    }
    into "IGV_Mac_${version}"
    doLast {
        if (jdkBundleMac == "") {
            throw new GradleException("Required property not set: jdkBundleMac");
        }
    }
}

task createMacAppDist(type: Copy, dependsOn: createDist) {
    with copySpec {
        from("scripts/mac.app") {
            exclude "Contents/Info.plist.template"
            exclude "Contents/MacOS/IGV.sh"
        }
        into "IGV_${version}.app"
    }
    with copySpec {
        from("scripts/mac.app/Contents/Info.plist.template")
        filter(ReplaceTokens, tokens: [VERSION: version])
        rename "Info.plist.template", "Info.plist"
        into "IGV_${version}.app/Contents"
    }
    with copySpec {
        from("web/IGV_64.png")
        into "IGV_${version}.app/Contents/Resources"
    }
    with copySpec {
        from("${buildDir}/IGV-dist/") include 'igv.args'
        into "IGV_${version}.app/Contents/Java/"
    }
    with copySpec {
        from("${buildDir}/IGV-dist/lib") include '*.jar'
        into "IGV_${version}.app/Contents/Java/lib"
    }
    into "${buildDir}/IGV-MacApp-dist"

    doLast {
        project.exec { commandLine('chmod', '775', "${buildDir}/IGV-MacApp-dist/IGV_${version}.app") }
    }
}

task createMacAppDistZip(type: Zip, dependsOn: createMacAppDist) {
    archiveName = "IGV_MacApp_${version}.zip"
    from("${buildDir}/IGV-MacApp-dist")

    doLast {
        project.exec { commandLine('chmod', '775', createMacAppDistZip.archivePath) }
    }
}

task createMacAppWithJavaDistZip(type: Zip, dependsOn: createMacAppDist) {
    archiveName = "IGV_MacApp_${version}_WithJava.zip"
    with copySpec { from jdkBundleMac into "IGV_${version}.app/Contents/jdk-11" }
    from("${buildDir}/IGV-MacApp-dist")

    doLast {
        if (jdkBundleMac == "") {
            throw new GradleException("Required property not set: jdkBundleMac");
        }
        project.exec { commandLine('chmod', '775', createMacAppWithJavaDistZip.archivePath) }
    }
}

task createWinDist(type: Copy, dependsOn: createDist) {
    with copySpec {
        from("${buildDir}/IGV-dist") {
            exclude "*.sh"
            exclude "*.command"
            exclude "igvtools*"
            exclude "igvtools_gui"
            exclude "igvtools_gui_hidpi"
            exclude 'lib/genomes'
        }
        from("resources") { include "IGV_64.ico" }
        into "IGV_${version}"
    }
    with copySpec {
        // Create a build-specific NSIS installer script.
        from("scripts/nsis/installer.nsi")
        filter(ReplaceTokens, tokens: [VERSION: version, JVM_INCL: ''])
    }
    from("scripts/nsis") { include "license_win.txt" }
    into "${buildDir}/IGV-WinExe-dist"
}

task createWinWithJavaDist(type: Copy, dependsOn: createWinDist) {
    with copySpec { from jdkBundleWindows into "IGV_${version}/jdk-11" }
    with copySpec {
        from("${buildDir}/IGV-WinExe-dist/IGV_${version}") { exclude 'installer.nsi' }
        into "IGV_${version}"
    }
    with copySpec {
        from("scripts/nsis/installer.nsi")
        filter(ReplaceTokens, tokens: [VERSION: version, JVM_INCL: '-WithJava'])
    }
    from("scripts/nsis") { include "license_win.txt" }
    into "${buildDir}/IGV-WinExe-WithJava-dist"

    doLast {
        if (jdkBundleWindows == "") {
            throw new GradleException("Required property not set: jdkBundleWindows");
        }
    }
}

task createWinExeDist(type: Exec, dependsOn: createWinDist) {
    commandLine(makensisCommand, "-O${buildDir}/tmp/nsis-WithJava-build.log",
            "${buildDir}/IGV-WinExe-dist/installer.nsi")
    doLast {
        if (makensisCommand == "") {
            throw new GradleException("Required property not set: makensisCommand");
        }
    }
}

task createWinWithJavaExeDist(type: Exec, dependsOn: createWinWithJavaDist) {
    commandLine(makensisCommand, "-O${buildDir}/tmp/nsis-build.log",
            "${buildDir}/IGV-WinExe-WithJava-dist/installer.nsi")
    doLast {
        if (makensisCommand == "") {
            throw new GradleException("Required property not set: makensisCommand");
        }
        if (jdkBundleWindows == "") {
            throw new GradleException("Required property not set: jdkBundleWindows");
        }
    }
}

task signWinExeDist(type: Exec, dependsOn: createWinExeDist) {
    standardInput = new ByteArrayInputStream(keyPassword.getBytes());
    commandLine(signcodeCommand, "-spc", spcFile, "-v", pvkFile, "-a", "sha512",
            "-\$", "commercial", "-n", "IGV ${version}", "-i", "http://www.igv.org/",
            "-t", tsaurl, "-tr", "10", "${buildDir}/IGV-WinExe-dist/IGV_Win_${version}-installer.exe")
    doLast {
        if (signcodeCommand == "") {
            throw new GradleException("Required property not set: signcodeCommand");
        }
    }
}

task signWinExeWithJavaDist(type: Exec, dependsOn: createWinWithJavaExeDist) {
    standardInput = new ByteArrayInputStream(keyPassword.getBytes());
    commandLine(signcodeCommand, "-spc", spcFile, "-v", pvkFile, "-a", "sha512",
            "-\$", "commercial", "-n", "IGV ${version}", "-i", "http://www.igv.org/",
            "-t", tsaurl, "-tr", "10", "${buildDir}/IGV-WinExe-WithJava-dist/IGV_Win_${version}-WithJava-installer.exe")
    doLast {
        if (signcodeCommand == "") {
            throw new GradleException("Required property not set: signcodeCommand");
        }
    }
}

task fullJar(type: Jar, dependsOn: jar) {
    // Based on https://discuss.gradle.org/t/removing-dependencies-from-a-jar-file-during-jar-task/5521/3
    from {
        ((configurations.compile - configurations.default) + "${buildDir}/libs/igv.jar").collect {
            zipTree(it)
        }
    } {
        exclude "META-INF/**"
    }

    manifest {
        attributes(
                "Permissions": "all-permissions",
                "Application-Name": "IGV",
                "Built-By": System.getProperty('user.name'),
                "Main-Class": mainClassName,
                "Class-Path": configurations.default.collect { it.getName() }.join(' ')
        )
    }
}

//build.dependsOn createDistZip,createLinuxDistZip,createMacDistZip,createMacAppDistZip

//if (!makensisCommand == "" && !signcodeCommand == "") {
//    dependsOn signWinExeDist
//}

// XXX: META-INF versions support (Java11) seem to clash with proguard at this point in time:
// https://sourceforge.net/p/proguard/bugs/665/
// https://sourceforge.net/p/proguard/discussion/182456/thread/8c56b22dc2/?limit=25
//task myproguard(type: ProGuardTask) {
////    configuration 'proguard.txt'
//
//    injars "${buildDir}/IGV-dist/lib"
//    outjars "${buildDir}/libs/igv-proguard.jar"
//
//    //libraryjars "${buildDir}/IGV-dist/lib", jarfilter:"lib/**.jar(!META-INF/**)"
//    //libraryjars "${System.getProperty('java.home')}/lib/rt.jar"
//}
