buildscript {
    repositories {
        mavenCentral()
        maven { url "https://jitpack.io" }
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.17'
        classpath 'com.google.gradle:osdetector-gradle-plugin:1.6.0'
        classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
        classpath 'org.openjfx:javafx-plugin:0.0.10'
    }
}

configure(rootProject) {

    // remove the 'bisq-*' scripts and 'lib' dir generated by the 'installDist' task
    task clean {
        doLast {
            delete fileTree(dir: rootProject.projectDir, include: 'bisq-*'), 'lib'
        }
    }
}

configure(subprojects) {
    apply plugin: 'com.google.osdetector'

    ext { // in alphabetical order
        grpcVersion = '1.42.1'
        javafxVersion = '16'
        protocVersion = '3.19.1'

        os = osdetector.os == 'osx' ? 'mac' : osdetector.os == 'windows' ? 'win' : osdetector.os
    }
}


configure([project(':cli'),
           project(':daemon'),
           project(':desktop'),
           project(':seednode'),
           project(':statsnode'),
           project(':apitest')]) {

    apply plugin: 'application'

    build.dependsOn installDist
    installDist.destinationDir = file('build/app')
    distZip.enabled = false
    distTar.enabled = false

    // the 'installDist' and 'startScripts' blocks below configure bisq executables to put
    // generated shell scripts in the root project directory, such that users can easily
    // discover and invoke e.g. ./bisq-desktop, ./bisq-seednode, etc.
    // See https://stackoverflow.com/q/46327736 for details.

    installDist {
        doLast {
            // copy generated shell scripts, e.g. `bisq-desktop` directly to the project
            // root directory for discoverability and ease of use

            copy {
                from "$destinationDir/bin"
                into rootProject.projectDir
            }
            // copy libs required for generated shell script classpaths to 'lib' dir under
            // the project root directory
            copy {
                from "$destinationDir/lib"
                into "${rootProject.projectDir}/lib"
            }

            // edit generated shell scripts such that they expect to be executed in the
            // project root dir as opposed to a 'bin' subdirectory
            def windowsScriptFile = file("${rootProject.projectDir}/bisq-${applicationName}.bat")
            windowsScriptFile.text = windowsScriptFile.text.replace(
                'set APP_HOME=%DIRNAME%..', 'set APP_HOME=%DIRNAME%')

            def unixScriptFile = file("${rootProject.projectDir}/bisq-$applicationName")
            unixScriptFile.text = unixScriptFile.text.replace(
                'APP_HOME=$( cd "${APP_HOME:-./}.." && pwd -P ) || exit', 'APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit')

            if (applicationName == 'desktop') {
                def script = file("${rootProject.projectDir}/bisq-$applicationName")
                script.text = script.text.replace(
                    'DEFAULT_JVM_OPTS=""', 'DEFAULT_JVM_OPTS="-XX:MaxRAM=8g -Xss1280k -XX:+UseG1GC ' +
                    '-XX:MaxHeapFreeRatio=10 -XX:MinHeapFreeRatio=5 -XX:+UseStringDeduplication ' +
                    '-Djava.net.preferIPv4Stack=true"')
            }

            if (applicationName == 'apitest') {
                // Pass the logback config file as a system property to avoid chatty
                // logback startup due to multiple logback.xml files in the classpath
                // (:daemon & :cli).
                def script = file("${rootProject.projectDir}/bisq-$applicationName")
                script.text = script.text.replace(
                    'DEFAULT_JVM_OPTS=""', 'DEFAULT_JVM_OPTS="' +
                    '-Dlogback.configurationFile=apitest/build/resources/main/logback.xml"')
            }

            if (osdetector.os != 'windows')
                delete fileTree(dir: rootProject.projectDir, include: 'bisq-*.bat')
            else
                delete fileTree(dir: rootProject.projectDir, include: 'bisq-*', exclude: '*.bat')
        }
    }

    startScripts {
        // rename scripts from, e.g. `desktop` to `bisq-desktop`
        applicationName = "bisq-$applicationName"
    }
}


configure(project(':common')) {
    apply plugin: 'org.openjfx.javafxplugin'

    javafx {
        version = "$javafxVersion"
        modules = ['javafx.graphics']
    }

    ext.getHash = {
        def p1 = 'git rev-parse HEAD'.execute()
        p1.waitFor()
        return p1.text
    }

    jar.manifest.attributes(
        "Implementation-Version": getHash())

    dependencies {
        implementation project(':proto')
        annotationProcessor libs.lombok
        compileOnly libs.javax.annotation
        compileOnly libs.lombok
        implementation libs.logback.classic
        implementation libs.logback.core
        implementation(libs.bitcoinj) {
            exclude(module: 'bcprov-jdk15on')
            exclude(module: 'guava')
            exclude(module: 'jsr305')
            exclude(module: 'okhttp')
            exclude(module: 'okio')
            exclude(module: 'protobuf-java')
            exclude(module: 'slf4j-api')
        }
        implementation libs.google.findbugs
        implementation libs.google.gson
        implementation libs.google.guava
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
        implementation libs.protobuf.java
        implementation libs.commons.io
        implementation libs.jopt
        implementation libs.apache.commons.lang3
        implementation libs.bouncycastle.bcpg.jdk15on
        implementation libs.kotlin.stdlib.jdk8
        implementation libs.jetbrains.annotations
        implementation libs.slf4j.api
        runtimeOnly(libs.grpc.netty.shaded) {
            exclude(module: 'animal-sniffer-annotations')
            exclude(module: 'guava')
        }
    }
}


configure(project(':p2p')) {
    apply plugin: 'org.openjfx.javafxplugin'

    javafx {
        version = "$javafxVersion"
        modules = ['javafx.base']
    }

    dependencies {
        implementation project(':proto')
        implementation project(':common')
        annotationProcessor libs.lombok
        compileOnly libs.lombok
        implementation libs.google.guava
        implementation libs.protobuf.java
        implementation libs.fxmisc.easybind
        implementation libs.slf4j.api
        implementation(libs.netlayer.tor.external) {
            exclude(module: 'slf4j-api')
        }
        implementation(libs.netlayer.tor.native) {
            exclude(module: 'slf4j-api')
        }
        implementation(libs.bitcoinj) {
            exclude(module: 'bcprov-jdk15on')
            exclude(module: 'guava')
            exclude(module: 'jsr305')
            exclude(module: 'okhttp')
            exclude(module: 'okio')
            exclude(module: 'protobuf-java')
            exclude(module: 'slf4j-api')
        }
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
        implementation(libs.apache.httpclient) {
            exclude(module: 'commons-codec')
        }
        testAnnotationProcessor libs.lombok
        testCompileOnly libs.lombok
        testImplementation libs.logback.classic
        testImplementation libs.logback.core
        testImplementation libs.apache.commons.lang3
    }
}


configure(project(':core')) {
    apply plugin: 'org.openjfx.javafxplugin'

    javafx {
        version = "$javafxVersion"
        modules = ['javafx.base']
    }

    dependencies {
        implementation project(':proto')
        implementation project(':assets')
        implementation project(':common')
        implementation project(':p2p')
        annotationProcessor libs.lombok
        compileOnly libs.javax.annotation
        compileOnly libs.lombok
        implementation libs.logback.classic
        implementation libs.logback.core
        implementation libs.jackson.annotations
        implementation libs.jackson.core
        implementation libs.google.findbugs
        implementation libs.google.gson
        implementation libs.google.guava
        implementation libs.protobuf.java
        implementation libs.commons.codec
        implementation libs.commons.io
        implementation libs.jopt
        implementation libs.apache.commons.lang3
        implementation libs.apache.httpcore
        implementation libs.fxmisc.easybind
        implementation libs.jetbrains.annotations
        implementation libs.slf4j.api
        implementation(libs.jackson.databind) {
            exclude(module: 'jackson-annotations')
        }
        implementation(libs.netlayer.tor.external) {
            exclude(module: 'slf4j-api')
        }
        implementation(libs.netlayer.tor.native) {
            exclude(module: 'slf4j-api')
        }
        implementation(libs.bitcoinj) {
            exclude(module: 'bcprov-jdk15on')
            exclude(module: 'guava')
            exclude(module: 'jsr305')
            exclude(module: 'okhttp')
            exclude(module: 'okio')
            exclude(module: 'protobuf-java')
            exclude(module: 'slf4j-api')
        }
        implementation(libs.jsonrpc4j) {
            exclude(module: 'base64')
            exclude(module: 'httpcore-nio')
        }
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
        implementation(libs.apache.httpclient) {
            exclude(module: 'commons-codec')
        }
        testAnnotationProcessor libs.lombok
        testCompileOnly libs.lombok
        testImplementation libs.natpryce.make.it.easy
    }

    test {
        systemProperty 'jdk.attach.allowAttachSelf', true
    }
}

configure(project(':desktop')) {
    apply plugin: 'com.github.johnrengelman.shadow'
    apply plugin: 'org.openjfx.javafxplugin'
    apply from: 'package/package.gradle'

    shadowDistTar.enabled = false
    shadowDistZip.enabled = false

    javafx {
        version = "$javafxVersion"
        modules = ['javafx.controls', 'javafx.fxml']
    }

    version = file("src/main/resources/version.txt").text.trim()

    jar.manifest.attributes(
        "Implementation-Title": project.name,
        "Implementation-Version": version)

    mainClassName = 'bisq.desktop.app.BisqAppMain'

    jar {
        preserveFileTimestamps = false
        reproducibleFileOrder = true
    }

    sourceSets.main.resources.srcDirs += ['src/main/java'] // to copy fxml and css files

    dependencies {
        implementation project(':assets')
        implementation project(':common')
        implementation project(':proto')
        implementation project(':p2p')
        implementation project(':core')
        annotationProcessor libs.lombok
        compileOnly libs.lombok
        implementation libs.logback.classic
        implementation libs.logback.core
        implementation libs.google.gson
        implementation libs.google.guava
        implementation libs.protobuf.java
        implementation libs.jcsv
        implementation libs.jfoenix
        implementation libs.commons.io
        implementation libs.fontawesomefx
        implementation libs.fontawesomefx.commons
        implementation libs.fontawesomefx.materialdesign.font
        implementation libs.qrgen
        implementation libs.apache.commons.lang3
        implementation libs.bouncycastle.bcpg.jdk15on
        implementation libs.fxmisc.easybind
        implementation libs.jetbrains.annotations
        implementation libs.slf4j.api
        implementation(libs.bitcoinj) {
            exclude(module: 'bcprov-jdk15on')
            exclude(module: 'guava')
            exclude(module: 'jsr305')
            exclude(module: 'okhttp')
            exclude(module: 'okio')
            exclude(module: 'protobuf-java')
            exclude(module: 'slf4j-api')
        }
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
        testAnnotationProcessor libs.lombok
        testCompileOnly libs.lombok
        testImplementation libs.natpryce.make.it.easy
    }

    test {
        systemProperty 'jdk.attach.allowAttachSelf', true
    }
}


configure(project(':seednode')) {
    apply plugin: 'com.github.johnrengelman.shadow'

    shadowDistTar.enabled = false
    shadowDistZip.enabled = false

    jar.manifest.attributes(
        "Implementation-Title": project.name,
        "Implementation-Version": version)

    mainClassName = 'bisq.seednode.SeedNodeMain'

    dependencies {
        implementation project(':common')
        implementation project(':proto')
        implementation project(':p2p')
        implementation project(':core')
        implementation libs.protobuf.java
        annotationProcessor libs.lombok
        compileOnly libs.lombok
        implementation libs.google.guava
        implementation libs.slf4j.api
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
    }
}

configure(project(':statsnode')) {
    mainClassName = 'bisq.statistics.StatisticsMain'

    dependencies {
        implementation project(':common')
        implementation project(':p2p')
        implementation project(':core')
        annotationProcessor libs.lombok
        compileOnly libs.lombok
        implementation libs.slf4j.api
        implementation(libs.google.guice) {
            exclude(module: 'guava')
        }
    }
}

configure(project(':apitest')) {
    mainClassName = 'bisq.apitest.ApiTestMain'

    // The external dao-setup.gradle file contains tasks to install and clean dao-setup
    // files downloaded from
    //          https://github.com/bisq-network/bisq/raw/master/docs/dao-setup.zip
    // These tasks are not run by the default build, but they can can be run during
    // full or partial builds, or by themselves.
    // To run the regular clean + build + test (non api), and install dao-setup files:
    //      ./gradlew clean build :apitest:installDaoSetup
    // To install or re-install dao-setup file only:
    //      ./gradlew :apitest:installDaoSetup -x test
    // To clean installed dao-setup files:
    //      ./gradlew :apitest:cleanDaoSetup -x test
    apply from: 'dao-setup.gradle'

    // We have to disable the :apitest 'test' task by default because we do not want
    // to interfere with normal builds.  To run JUnit tests in this subproject:
    // Run a normal build and install dao-setup files first, then run:
    //              'gradle  :apitest:test -DrunApiTests=true'
    test.enabled = System.getProperty("runApiTests") == "true"

    sourceSets {
        main {
            resources {
                exclude 'dao-setup'
                exclude 'dao-setup.zip'
            }
        }
    }

    test {
        outputs.upToDateWhen { false }          // Don't use previously cached test outputs.
        testLogging {
            showStackTraces = true              // Show full stack traces in the console.
            exceptionFormat = "full"
            // Show passed & failed tests, and anything printed to stderr by the tests in the console.
            // Do not show skipped tests in the console;  they are shown in the html report.
            events "passed", "failed", "standardError"
        }

        afterSuite { desc, result ->
            if (!desc.parent) {
                println("${result.resultType} " +
                    "[${result.testCount} tests, " +
                    "${result.successfulTestCount} passed, " +
                    "${result.failedTestCount} failed, " +
                    "${result.skippedTestCount} skipped]  html report contains skipped test info")

                // Show report link if all tests passed in case you want to see more detail, stdout, skipped, etc.
                if (result.resultType == TestResult.ResultType.SUCCESS) {
                    DirectoryReport htmlReport = getReports().getHtml()
                    String reportUrl = new org.gradle.internal.logging.ConsoleRenderer()
                        .asClickableFileUrl(htmlReport.getEntryPoint())
                    println("REPORT  " + reportUrl)
                }
            }
        }
    }

    dependencies {
        implementation project(':proto')
        implementation project(':common')
        implementation project(':core')
        implementation project(':seednode')
        implementation project(':desktop')
        implementation project(':daemon')
        implementation project(':cli')
        annotationProcessor libs.lombok
        compileOnly libs.javax.annotation
        compileOnly libs.lombok
        implementation libs.logback.classic
        implementation libs.logback.core
        implementation libs.google.gson
        implementation libs.google.guava
        implementation libs.protobuf.java
        implementation libs.jopt
        implementation libs.apache.commons.lang3
        implementation libs.slf4j.api
        implementation(libs.bitcoinj) {
            exclude(module: 'bcprov-jdk15on')
            exclude(module: 'guava')
            exclude(module: 'jsr305')
            exclude(module: 'okhttp')
            exclude(module: 'okio')
            exclude(module: 'protobuf-java')
            exclude(module: 'slf4j-api')
        }
        implementation(libs.grpc.protobuf) {
            exclude(module: 'animal-sniffer-annotations')
            exclude(module: 'guava')
        }
        implementation(libs.grpc.stub) {
            exclude(module: 'animal-sniffer-annotations')
            exclude(module: 'guava')
        }
        testAnnotationProcessor libs.lombok
        testCompileOnly libs.lombok
        testRuntimeOnly libs.javax.annotation
    }
}

if (hasProperty('buildScan')) {
    buildScan {
        termsOfServiceUrl = 'https://gradle.com/terms-of-service'
        termsOfServiceAgree = 'yes'
    }
}