import java.nio.file.Files
import java.nio.file.Paths

plugins {
    // Supports functionality similar to Maven BOM.
    // Helps to avoid re-declaring dependency version in each subproject.
    // See https://github.com/spring-gradle-plugins/dependency-management-plugin
    id "io.spring.dependency-management" version "1.0.11.RELEASE"
    id "com.github.spotbugs" version "4.2.3" apply false
    id "com.github.hierynomus.license-report" version "0.15.0"

    id 'com.github.jk1.dependency-license-report' version '1.17'
    id "com.vanniktech.dependency.graph.generator" version "0.5.0"
}

ext {
    globalWebDir = file("$rootDir/web")
    isReleaseVersion = !version.endsWith("SNAPSHOT")
}

// To enable JavaDoc generation add Gradle property to command line:
// -PincludeJavaDocs

apply plugin: 'base'
apply plugin: "com.github.hierynomus.license-report"
apply from: "$rootDir/gradle/License.gradle"

// We don't want to apply plugins and build artifacts for non-leaf (grouping) projects.
// So we create a list of leaf projects and apply all java-related plugins on them only.
def leafProjects = subprojects.findAll { subproject ->
    subproject.subprojects.empty
}
leafProjects.remove(project(":java:installer"))
ext.leafProjects = leafProjects // Publish as external variable

apply from: 'test.gradle'

// Spotbugs
def enableSpotbugs = hasProperty("spotbugs") || Boolean.getBoolean("spotbugs") || Boolean.parseBoolean(System.getenv('SPOTBUGS'))
if (enableSpotbugs) {
    println("Spotbugs is ENABLED")
}

licenseReport {
    // prepare allowed licenses

//    for (nl.javadude.gradle.plugins.license.LicenseMetadata a in downloadLicenses.allowedLicenses) {
//        println()
//
//        def names = downloadLicenses.aliases.get(a)
//        for (name in names) {
//            if (name instanceof String)
//                println("{\"moduleLicense\": \"" + name + "\"},")
//            else if (name instanceof nl.javadude.gradle.plugins.license.LicenseMetadata)
//                println("{\"moduleLicense\": \"" + name.licenseName + "\"},")
//        }
//    }

    excludeGroups = ['javax.servlet.*']
    excludes = ['asm:asm', 'net.jcip:jcip-annotations', 'com.fasterxml.jackson:jackson-bom']

    configurations = ['runtimeClasspath']
    allowedLicensesFile = new File("$rootDir/allowed-lic.json")
}

checkLicense {
    outputs.upToDateWhen { false }
}

configure(leafProjects) {
    apply plugin: 'java-library'
    apply plugin: 'maven-publish'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: "com.github.spotbugs" // Static Code analysis
    apply plugin: 'signing'

    compileJava.options.encoding = 'UTF-8'
    compileJava.options.compilerArgs += '--add-exports=java.base/sun.nio.ch=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-exports=java.desktop/sun.swing=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-exports=java.desktop/com.sun.java.swing.plaf.windows=ALL-UNNAMED'

    compileJava.options.compilerArgs += '--add-opens=java.base/sun.nio.ch=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-opens=java.base/java.io=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-opens=java.base/java.lang=ALL-UNNAMED'
    compileJava.options.compilerArgs += '--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED'


    compileTestJava.options.compilerArgs += '--add-exports=java.base/sun.nio.ch=ALL-UNNAMED'
    compileTestJava.options.compilerArgs += '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED'
    compileTestJava.options.compilerArgs += '--add-opens=java.base/sun.nio.ch=ALL-UNNAMED'
    compileTestJava.options.compilerArgs += '--add-opens=java.base/java.io=ALL-UNNAMED'
    compileTestJava.options.compilerArgs += '--add-opens=java.base/java.lang=ALL-UNNAMED'
    compileTestJava.options.compilerArgs += '--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED'

    sourceCompatibility = 11
    targetCompatibility = 11

    configurations.all {
        resolutionStrategy {
            // Disable this line on case of version conflict and then run :dependency task OR execute build with --scan option
            failOnVersionConflict()
        }

        // same api defined in javax.annotation-api-*
        exclude group: 'jakarta.annotation', module: 'jakarta.annotation-api' // GNU license
    }

    spotbugsMain {
        enabled = false
        reports {
            html.enabled = true
        }
        reportLevel = "high"
    }

    spotbugsTest {
        enabled = false
        reports {
            html.enabled = true
        }
        reportLevel = "high"
    }

    task allDeps(type: DependencyReportTask) {}

    // Defines versions of dependencies to be used by subprojects
    // https://github.com/spring-gradle-plugins/dependency-management-plugin#dependency-management-dsl
    dependencyManagement {
        imports {
            mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.5'
        }

        dependencies {
            dependencySet(group: 'com.epam.deltix', version: '3.0.3') {
                entry 'gflog-api'
                entry 'gflog-core'
                entry 'gflog-jul'
                entry 'gflog-jcl'
                entry 'gflog-slf4j'
                entry 'gflog-mail'
            }

//            dependency 'com.epam.deltix:gflog-api:3.0.1'
//            dependency 'com.epam.deltix:gflog-core:3.0.1'
//            dependency 'com.epam.deltix:gflog-jul:3.0.1'
//            dependency 'com.epam.deltix:gflog-jcl:3.0.1'
//            dependency 'com.epam.deltix:gflog-slf4j:3.0.1'
//            dependency 'com.epam.deltix:gflog-mail:3.0.1'

            dependency 'com.epam.deltix:value-types:0.9.3'
            dependency 'com.epam.deltix:dfp:0.12.5'
            dependency 'com.epam.deltix:thread-affinity:1.0.4'
            dependency 'com.epam.deltix:hd-date-time:0.2.11'
            dependency 'com.epam.deltix:containers:3.1.2'

            dependencySet(group: 'com.epam.deltix', version: '6.0.65') {
                entry 'timebase-collections'
                entry 'timebase-messages'
                entry 'timebase-lang'
                entry 'timebase-util'
            }

            dependency 'org.apache.poi:poi:4.1.1'
            dependency 'org.apache.poi:poi-ooxml:4.1.1'

//            dependency 'java:tools:1.8.0_121'
            dependency 'com.sun.activation:javax.activation:1.2.0'
            dependency 'javax.activation:javax.activation-api:1.2.0'

            dependency 'com.google.guava:guava:32.0.1-jre'
            dependency 'com.google.code.gson:gson:2.8.9'
            dependency 'com.google.code.findbugs:jsr305:3.0.2'
            dependency 'com.google.code.findbugs:annotations:3.0.1'

            dependency 'net.sf.opencsv:opencsv:1.7'

            dependency 'org.slf4j:slf4j-api:1.7.14'

            dependency 'javax.mail:mail:1.4.7'

            dependency 'javax.servlet.jsp.jstl:jstl-api:1.2' // JSTL Support
            dependency 'org.owasp.encoder:encoder:1.1.1' // prevent XSS attacks in servlets

            dependency 'org.apache.taglibs:taglibs-standard-impl:1.2.5' // Tomcat JSTL Support

            dependency 'org.codehaus.groovy:groovy:2.5.3'

            dependency 'org.apache.ant:ant:1.9.13'

            dependency 'org.hdrhistogram:HdrHistogram:2.1.10'

//            dependencySet(group: 'org.apache.hadoop', version: '2.10.1') {
//                entry 'hadoop-annotations'
//                entry 'hadoop-auth'
//                entry 'hadoop-common'
//                entry 'hadoop-mapreduce-client-common'
//                entry 'hadoop-mapreduce-client-core'
//                entry 'hadoop-yarn-api'
//                entry 'hadoop-yarn-client'
//                entry 'hadoop-yarn-common'
//            }

            dependency 'io.micrometer:micrometer-registry-prometheus:1.7.3'

            dependencySet(group: 'org.apache.tomcat.embed', version: '8.0.53') {
                entry 'tomcat-embed-core' // Tomcat core
                entry 'tomcat-embed-jasper' // Tomcat JSP support
                entry 'tomcat-embed-logging-juli' // Tomcat Logging
            }

            dependencySet(group: 'io.aeron', version: '1.38.1') {
                entry 'aeron-client'
                entry 'aeron-driver'
                entry 'aeron-archive'
            }

            dependency 'com.lmax:disruptor:3.3.6'

            // JMH
            dependencySet(group: 'org.openjdk.jmh', version: '1.23') {
                entry 'jmh-core'
                entry 'jmh-generator-annprocess'
            }

            dependency 'com.intellij:annotations:12.0'

            // Fix for conflicting versions
            // This section enlists only dependencies that are not directly used by our code but used by our dependencies
            // and cause version conflict. Versions specified here may need to be updated when we update 3rd party dependeiceis.
            // The project should be buildable without this section but with "failOnVersionConflict" option turned off.
            
            dependency 'net.java.dev.jna:jna:4.2.1'
            dependency 'org.hamcrest:hamcrest-core:1.3'

            dependency 'commons-lang:commons-lang:2.6'
            dependency 'commons-logging:commons-logging:1.1.1'
            dependency 'commons-collections:commons-collections:3.2.2'
            dependency 'commons-io:commons-io:2.15.1'
            dependency 'commons-codec:commons-codec:1.13'
            dependency 'commons-net:commons-net:3.9.0'

            dependency 'org.apache.commons:commons-compress:1.26.1'
            dependency 'org.apache.commons:commons-lang3:3.7'
            dependency 'org.apache.commons:commons-math3:3.6'
            dependency 'org.apache.commons:commons-text:1.10.0'

            dependency 'org.reflections:reflections:0.9.11'

            dependencySet(group: 'org.apache.httpcomponents', version: '4.5.13') {
                entry 'httpclient'
                entry 'httpcore'
                entry 'httpasyncclient'
            }
            dependency 'org.apache.httpcomponents:httpcore:4.4.4'

            // used by izpack
            dependency 'org.apache.tika:tika-core:1.26'
            dependency 'org.apache.tika:tika-parsers:1.26'

            dependency 'org.apache.yetus:audience-annotations:0.5.0'

            dependency 'org.tukaani:xz:1.6'
            dependency 'joda-time:joda-time:2.8.1'

            dependency 'com.google.errorprone:error_prone_annotations:2.0.19'

            dependency 'org.glassfish:javax.json:1.0.4'

            dependency 'org.objenesis:objenesis:2.2'

            dependencySet(group: 'com.fasterxml.jackson.core', version: '2.13.5') {
                entry 'jackson-core'
                entry 'jackson-annotations'
                entry 'jackson-databind'
            }
            dependency 'com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.13.5'

            dependencySet(group: 'com.squareup.okhttp3', version: '3.3.1') {
                entry 'okhttp'
            }

            dependencySet(group: 'org.apache.parquet', version: '1.11.1') {
                entry 'parquet-common'
                entry 'parquet-column'
                entry 'parquet-encoding'
                entry 'parquet-hadoop'
            }

            dependencySet(group: 'org.bouncycastle', version: '1.68') {
                entry 'bcpkix-jdk15on'
                entry 'bcprov-jdk15on'
                entry 'bcprov-ext-jdk15on'
                entry 'bcmail-jdk15on'
            }

            dependency 'log4j:log4j:1.2.17'

            dependency 'javax.xml.bind:jaxb-api:2.2.8'
            dependency 'com.sun.xml.bind:jaxb-impl:2.3.0'
            dependency 'com.sun.xml.bind:jaxb-core:2.3.0'

            dependencySet(group: 'org.codehaus.jackson', version: '1.9.13') {
                entry 'jackson-mapper-asl'
                entry 'jackson-core-asl'
            }
            dependency 'org.xerial.snappy:snappy-java:1.1.10.4'
            dependency 'org.slf4j:slf4j-log4j12:1.7.10'

            dependency 'com.sun.xml.bind:jaxb-impl:2.3.0'
            dependency 'junit:junit:4.13.1'

            dependency 'org.apache.bcel:bcel:6.6.0'

            dependency 'org.wildfly.openssl:wildfly-openssl:1.1.3.Final'
            dependency 'org.wildfly.openssl:wildfly-openssl-java:1.1.3.Final'
            // End of version conflict resolution
        }
    }

    ext {
        vendor = 'EPAM Systems, Inc.'
    }

    group = 'org.finos.timebase-ce'
    archivesBaseName = project.path.replace(":java:", "").replaceAll(':', '-')

    repositories {
        mavenCentral()
    }

    javadoc {
        exclude "**/package-info.java" // javadoc error with java 11.0.17
        options.encoding = 'UTF-8'
    }

    dependencies {
        spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1'

        compileOnly 'com.google.code.findbugs:jsr305'
        compileOnly 'com.google.code.findbugs:annotations'

        testCompileOnly 'com.google.code.findbugs:jsr305'
        testCompile 'junit:junit:4.13.1'
        testCompile 'org.mockito:mockito-core:1.10.19'
    }

    spotbugs {
        toolVersion = "4.2.3"
        effort = "max"
        reportLevel = "medium"
        excludeFilter = rootProject.file('spotbugs-excludes.xml')
    }

    jar {
        manifest {
            baseName archivesBaseName
            description description
            attributes 'Manifest-Version': "1.0",
                    'Created-By': vendor,
                    'Implementation-Title': archivesBaseName,
                    'Implementation-Vendor': vendor,
                    'Implementation-Version': archiveVersion
        }
    }

    java {
        withJavadocJar()
        withSourcesJar()
    }

    processResources {
        from sourceSets.main.java.srcDirs
        exclude '**/*.java'
        includeEmptyDirs = false
    }

    processTestResources {
        from sourceSets.test.java.srcDirs
        exclude '**/*.java'
        includeEmptyDirs = false
    }

    afterEvaluate {
        // populate project classpath after evaluating
        jar.manifest.attributes 'Class-Path': configurations.runtimeClasspath.collect { it.getName() }.join(' ')
    }

    // Don't start resource copy if we not finished root "clean"
    classes.mustRunAfter rootProject.tasks.getByName("clean")
    // Don't start resource copy if we not finished root "clean"
    testClasses.mustRunAfter rootProject.tasks.getByName("clean")

    // Contains current project jar and all required dependencies for that project
    def allJarsPath = 'build/alljars'

    task gatherProjectDependencies(type: Sync) {
        description 'Copies all project runtime dependencies to ' + allJarsPath
        from project.configurations.runtimeClasspath
        into allJarsPath
    }

    task gatherAllJarsWithDependencies(type: Copy, dependsOn: ['jar', gatherProjectDependencies]) {
        group 'build'
        description 'Copies all project JAR and all it\'s runtime dependencies to ' + allJarsPath
        from jar // Main produced JAR of the subproject
        into allJarsPath
    }

    def allTestJarsPath = 'build/alltestjars'

    task gatherProjectTestDependencies(type: Sync) {
        description 'Copies all project test dependencies to ' + allTestJarsPath
        from project.configurations.testRuntimeClasspath
        into allTestJarsPath
    }

    task generateTestJar(type: Jar) {
        description 'Generates JAR with test classes'
        classifier 'tests'
        from sourceSets.test.output
    }

    task gatherAllTestJarsWithDependencies(type: Copy, dependsOn: ['jar', generateTestJar, gatherProjectTestDependencies]) {
        group 'build'
        description 'Copies all project JAR and all it\'s test dependencies to ' + allTestJarsPath
        from jar // Main produced JAR of the subproject
        from generateTestJar // JAR with test classes

        into allTestJarsPath
    }

    task logJars { doLast { configurations.compile.each { File file -> println '\t' + file.name } } }
    task logJarFiles { doLast { configurations.compile.each { File file -> println '\t' + file } } }
    task logTestJarsFiles { doLast { configurations.testCompile.each { File file -> println '\t' + file } } }

    tasks.withType(Javadoc) {
        // "Xdoclint:all,-reference" - disables fail on missing JavaDoc reference. TODO: Consider removing this.
        // "-quiet" - skips warning messages (warnings still shown).
        options.addStringOption('Xdoclint:all,-reference', '-quiet')
        options.addStringOption('encoding', 'UTF-8')
    }

    def rUser = findProperty('SONATYPE_NEXUS_USERNAME') ?:  System.getenv('SONATYPE_NEXUS_USERNAME') ?: "FakeUser"
    def rPass = findProperty('SONATYPE_NEXUS_PASSWORD') ?:  System.getenv('SONATYPE_NEXUS_PASSWORD') ?: "FakePass"

    // Publishing
    publishing {
        repositories {
            maven {
                url = findProperty('SONATYPE_REPOSITORY') ?: System.getenv('SONATYPE_REPOSITORY') ?: "FakeRepo"

                credentials {
                    username rUser
                    password rPass
                }
            }
        }

        publications {
            mavenJava(MavenPublication) {
                from components.java

                artifactId = archivesBaseName

                versionMapping {
                    usage(Usage.JAVA_RUNTIME) {
                        fromResolutionResult()
                    }
                    usage(Usage.JAVA_API) {
                        fromResolutionResult()
                        //fromResolutionOf("runtimeClasspath")
                    }
                }

                pom {
                    name = project.name
                    packaging = 'jar'

                    url = 'https://github.com/finos/TimeBase-CE.git'

                    scm {
                        connection = 'scm:git:https://github.com/finos/TimeBase-CE.git'
                        developerConnection = 'scm:git:https://github.com/finos/TimeBase-CE.git'
                        url = 'https://github.com/finos/TimeBase-CE.git'
                    }

                    licenses {
                        license {
                            name = 'The Apache License, Version 2.0'
                            url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }

                    developers {
                        developer {
                            id = 'alex-karpovich'
                            name = 'Alexander Karpovich'
                            email = 'aliaksandr_karpovich@epam.com'
                            url = 'https://github.com/alex-karpovich'
                            organization = 'EPAM Systems'
                            organizationUrl = 'https://www.epam.com/'
                        }
                    }
                }
            }
        }

        signing {
            def signingKey = findProperty('SIGNING_PRIVATE_KEY') ?: System.getenv('SIGNING_PRIVATE_KEY') ?: "FakeUser"
            def signingPassword = findProperty('SIGNING_PASSWORD') ?: System.getenv('SIGNING_PASSWORD') ?: "FakePass"

            useInMemoryPgpKeys(signingKey, signingPassword)
            sign publishing.publications.mavenJava

            required { isReleaseVersion }
        }
    }

    afterEvaluate {
        tasks.withType(GenerateMavenPom).all {
            getPom().description.set(project.description)
        }
    }

    tasks.test { enabled = false }

    task copyJarsToLib(type: Copy, dependsOn: jar) {
        mustRunAfter clean
        mustRunAfter ':clean' // Root clean
        from configurations.runtimeClasspath
        from jar.getOutputs().files.getSingleFile()
        into "$rootDir/lib"
    }

    build.dependsOn(copyJarsToLib)

    task printDependencies(type: DependencyReportTask) {
        description "Prints project dependency tree"
    }
}

def webAbbrs = [':java:timebase:web': 'default', ':java:timebase:webmonitor': 'tb']
webAbbrs.each { key, value ->
    project(key) {
        clean.doFirst {
            file("$globalWebDir/$value").deleteDir()
        }

        classes.doLast {
            copy {
                from webAppDir
                into file("$globalWebDir/$value")
            }
        }
    }
}

def javaDocProjects = [':java:timebase:server', ':java:timebase:aerondirect',':java:timebase:api', ':java:timebase:pub', ':java:timebase:client']
task aggregatedJavaDoc(type: Javadoc, description: 'Generate javadocs from selected projects', group: 'Documentation') {
    destinationDir = file("$buildDir/docs/javadoc")
    title = "$project.name $version API"
    options.author false
    options.links 'http://docs.spring.io/spring/docs/4.3.x/javadoc-api/', 'http://docs.oracle.com/javase/8/docs/api/', 'http://docs.spring.io/spring-ws/docs/2.3.0.RELEASE/api/', 'http://docs.spring.io/spring-security/site/docs/4.0.4.RELEASE/apidocs/'
    options.addStringOption 'Xdoclint:none', '-quiet'

    javaDocProjects.each { name ->
        project(name).tasks.withType(Javadoc).each { javadocTask ->
            source += javadocTask.source
            classpath += javadocTask.classpath
            excludes += javadocTask.excludes
            includes += javadocTask.includes
        }
    }
}

build.dependsOn leafProjects.collect { proj -> proj.build }, project.tasks.getByName('downloadLicenses')

task cleanSubprojects {
    dependsOn leafProjects.collect { proj -> proj.tasks.getByName("clean") }
    description 'Performs clean on all leaf Java projects'
}

task cleanJava {
    dependsOn cleanSubprojects
}
