/*
 * *****************************************************************************
 * Copyright (C) 2014-2025 Dennis Sheirer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 * ****************************************************************************
 */

import java.text.SimpleDateFormat



/**
 * Instructions for building/compiling the sdrtrunk application.
 *
 * Prerequisites:
 * Install and configure an OpenJDK version 22+ that includes the JavaFX modules (e.g. Bellsoft Liberica JDK)
 * - Optional: install and configure Gradle 8.10+
 *
 * Scenario 1: run the application via gradle command line from the source code root directory:
 * command: ./gradlew run
 *
 * Scenario 2: create an application release for the current operating system
 * command: ./gradlew runtimeZipCurrent
 * Note: release image is located in the /build/image/ directory
 *
 * Scenario 3: create releases for Linux and OSX operating systems using downloaded JDKs
 * command: ./gradlew runtimeZipOthers
 * Note: release images are located in the /build/image/ directory
 *
 * Scenario 4: create release for Windows operating system using downloaded JDK
 * command: ./gradlew runtimeZipWindows
 * Note: release image is located in the /build/image/ directory
 */
plugins {
    id 'application'
    id 'java'
    id 'idea'
    id 'org.beryx.runtime' version '1.12.7'
}

repositories {
    mavenCentral()
    maven { url "https://jitpack.io" }
}

//Version is defined in gradle.properties so that we can CLI override it for nightly builds.
version = project.findProperty('projectVersion')

//Java 24 is required for this version of the Project Panama preview/incubator feature
java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(24)
    }
}

sourceSets {
    main.java.srcDirs 'src/main'
    test.java.srcDirs 'src/test'
}

test {
    useJUnitPlatform()
}

dependencies {

    // JUnit Tests
    testImplementation(platform("org.junit:junit-bom:5.13.1"))
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.13.1'
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.13.1")
    testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.13.1")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    //Jitpack imports
    implementation 'com.github.dnault:libresample4j:master'
    implementation 'com.github.DSheirer.jmbe:jmbe-api:1.0.0'
    implementation 'com.github.nwaldispuehl:java-lame:v3.98.4'

    //mavenCentral/jcenter imports
    implementation 'ch.qos.logback:logback-classic:1.5.18'
    implementation 'ch.qos.logback:logback-core:1.5.18'
    implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.19.1'
    implementation 'com.fazecast:jSerialComm:2.9.3'
    implementation 'com.github.jiconfont:jiconfont-font_awesome:4.7.0.1'
    implementation 'com.github.jiconfont:jiconfont-javafx:1.0.0'
    implementation 'com.github.jiconfont:jiconfont-swing:1.0.1'
    implementation 'com.github.wendykierp:JTransforms:3.1'
    implementation 'com.google.code.gson:gson:2.13.1'
    implementation 'com.google.guava:guava:33.4.8-jre'
    implementation 'com.jidesoft:jide-oss:3.6.18'
    implementation 'com.miglayout:miglayout-swing:11.4.2'
    implementation 'com.mpatric:mp3agic:0.9.1'
    implementation 'commons-io:commons-io:2.19.0'
    implementation 'eu.hansolo:charts:1.0.5'
    implementation 'io.github.dsheirer:radio-reference-api:18.0.0'
    implementation 'io.github.dsheirer:usb4java-native-libraries:1.3.1' //OSX & Windows aarch64 native libs
    implementation 'javax.usb:usb-api:1.0.2'
    implementation 'net.coderazzi:tablefilter-swing:5.5.4'
    implementation 'org.apache.commons:commons-compress:1.27.1'
    implementation 'org.apache.commons:commons-lang3:3.18.0'
    implementation 'org.apache.commons:commons-math3:3.6.1'
    implementation 'org.apache.commons:commons-csv:1.14.0'
    implementation 'org.apache.mina:mina-core:2.2.4'
    implementation 'org.apache.mina:mina-http:2.2.4'
    implementation 'org.controlsfx:controlsfx:11.2.2'
    implementation 'org.rauschig:jarchivelib:1.2.0'
    implementation 'org.slf4j:slf4j-api:2.0.17'
    implementation 'org.usb4java:libusb4java:1.3.0'
    implementation 'org.usb4java:usb4java:1.3.0'
    implementation 'org.usb4java:usb4java-javax:1.3.0'
    implementation 'pl.edu.icm:JLargeArrays:1.6'
}

def os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem

/**
 * This is needed for the JDK23 vector API ... until it moves out of incubation or preview
 */
tasks.withType(JavaCompile) {
    options.compilerArgs.add("--enable-preview") //Project Panama Vector API is still in incubator
    options.compilerArgs.add("--add-modules=jdk.incubator.vector") //Project Panama Vector API is still in incubator
}

/**
 * JVM Arguments for running the application on Windows.
 */
def jvmArgsWindows =
        ['--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED', //Needed for controls-fx.jar
         '--add-exports=java.desktop/com.sun.java.swing.plaf.windows=ALL-UNNAMED', //windows users for JIDE
         '--add-modules=jdk.incubator.vector',   //Project Panama Vector API is still in incubator
         '--enable-preview', //Project Panama Vector API is still in incubator
         '--enable-native-access=ALL-UNNAMED', //Suppress unsafe warnings for FFM API Foreign Memory calls
         '--enable-native-access=javafx.graphics', //JDK24 - suppress restricted java.lang.System calls
         '--sun-misc-unsafe-memory-access=allow', //JDK24 - suppress sun.misc.Unsafe::allocateMemory warning
         '-Djava.library.path=c:\\Program Files\\SDRplay\\API\\x64'] //SDRPlay API library path

/**
 * JVM Arguments for running the application on Linux.
 */
def jvmArgsLinux =
        ['--add-exports=javafx.base/com.sun.javafx.event=ALL-UNNAMED', //Needed for controls-fx.jar
         '--add-modules=jdk.incubator.vector',   //Needed while Project Panama API is still in incubator
         '--enable-preview', //Project Panama Vector & Foreign Function APIs remain in incubator
         '--sun-misc-unsafe-memory-access=allow', //JDK24 - suppress sun.misc.Unsafe::allocateMemory warning
         '--enable-native-access=javafx.graphics', //JDK24 - suppress restricted java.lang.System calls
         '--enable-native-access=ALL-UNNAMED'] //SDRPlay API library path

application {
    mainClassName = "io.github.dsheirer.gui.SDRTrunk"

    if(os.isWindows()) {
        applicationDefaultJvmArgs = jvmArgsWindows
    }
    else {
        applicationDefaultJvmArgs = jvmArgsLinux
    }
}

test {
    if(os.isWindows()) {
        jvmArgs = jvmArgsWindows
    }
    else {
        jvmArgs = jvmArgsLinux
    }
}

jar {
    manifest {
        attributes (
                'Implementation-Title'  : 'sdrtrunk project',
                'Implementation-Version' : archiveVersion,
                'Created-By'            : "Gradle ${gradle.gradleVersion}",
                'Build-Timestamp'       : new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(new Date()),
                'Build-JDK'             : "${System.properties['java.version']} (${System.properties['java.vendor']} ${System.properties['java.vm.version']}",
                'Build-OS'              : "${System.properties['os.name']} (${System.properties['os.arch']} ${System.properties['os.version']}"
        )
    }
}

idea {
    module {
        downloadJavadoc = true
        downloadSources = true
    }
}

javadoc {
    options.addStringOption('-add-modules', 'jdk.incubator.vector')
    options.addStringOption('Xdoclint:none', '-quiet')
}

/**
 * Runtime target OS and CPU image names.  We append version here so that version details are at end of zip filename.
 */
String targetLinuxAarch64 = 'linux-aarch64-v' + version
String targetLinuxX86_64 = 'linux-x86_64-v' + version
String targetOsxAarch64 = 'osx-aarch64-v' + version
String targetOsxX86_64 = 'osx-x86_64-v' + version
String targetWindowsX86_64 = 'windows-x86_64-v' + version
String targetWindowsAarch64 = 'windows-aarch64-v' + version

/**
 * Optional pre-downloaded Java Development Kit (JDK) for each target OS and CPU.  These locations are hard-coded to the
 * author's development environment, but can be changed to your environment if you want to use this build pattern.
 */
String jdk_base = '/home/denny/java_jdks/'
String jdk_linux_aarch64 = jdk_base + 'linux-arm64/jdk-22.0.2-full'
String jdk_linux_x86_64 = jdk_base + 'linux-x64/jdk-22.0.2-full'
String jdk_osx_x86_64 = jdk_base + 'osx-x64/jdk-22.0.2-full.jdk'
String jdk_osx_aarch64 = jdk_base + 'osx-arm64/jdk-22.0.2-full.jdk'
String jdk_windows_x86_64 = jdk_base + 'windows-x64/jdk-22.0.2-full'
String jdk_windows_aarch64 = jdk_base + 'windows-arm64/jdk-22.0.2-full'

/**
 * Download URLs to download the JDK as part of the gradle build packaging process
 */
def jdk_download_base = "https://download.bell-sw.com/java/24.0.1+11/bellsoft-jdk24.0.1+11-"
def jdk_download_suffix = "-full.tar.gz"
def jdk_download_linux_aarch64 = jdk_download_base + "linux-aarch64" + jdk_download_suffix
def jdk_download_linux_x86_64 = jdk_download_base + "linux-amd64" + jdk_download_suffix
def jdk_download_osx_x86_64 = jdk_download_base + "macos-amd64" + jdk_download_suffix
def jdk_download_osx_aarch64 = jdk_download_base + "macos-aarch64" + jdk_download_suffix
def jdk_download_windows_x86_64 = jdk_download_base + "windows-amd64-full.zip"
def jdk_download_windows_aarch64 = jdk_download_base + "windows-aarch64-full.zip"

/**
 * Configures the runtime zip task with additional options/settings.
 * @param rt task to configure
 * @param jvmArgs to use (windows or linux)
 * @return configured task.
 */
def configure(org.beryx.runtime.RuntimeZipTask rt, List<String> jvmArgs) {
    //Use the correct set of JVM arguments
    rt.extension.launcherData.get().jvmArgs = jvmArgs

    //Additional modules to include with auto-detected modules.
    //jdk.crypto.ec - needed for HTTPS connections (broadcastify calls & map tile server)
    //jdk.incubator.vector - needed for Project Panama foreign function and vector apis
    //jdk.accessibility is used with assistive technologies like screen readers
    //java.management for JVM resource monitoring
    rt.extension.addModules('jdk.crypto.ec', 'jdk.incubator.vector', 'jdk.accessibility', 'java.management')

    //Use auto-detected modules and 'add' any specified modules.
    rt.extension.additive.set(true)

    //Recommended options for reducing/shrinking runtime target image size
    rt.extension.addOptions('--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages')

    //Runtime images have auto appended version in image zip name.  Override to include version in single target image.
    rt.extension.imageZip.set(file("$buildDir/image/sdr-trunk.zip"))
}

/**
 * Creates a release package for the current operating system.
 *
 * Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
 *
 * Usage: gradle runtimeZipCurrent
 * Usage: gradlew runtimeZipCurrent   (windows - using gradlew)
 * Usage: ./gradlew runtimeZipCurrent   (linux - using gradlew)
 */
tasks.register('runtimeZipCurrent', org.beryx.runtime.RuntimeZipTask) {rt ->
    def arch = System.properties.getProperty("os.arch")
    def javaHome = org.gradle.internal.jvm.Jvm.current().getJavaHome().toString()

    if(os.isWindows()) {
        if(arch.equals("amd64")) {
            rt.extension.targetPlatform(targetWindowsX86_64, javaHome)
        }
        else if(arch.equals("aarch64")) {
            rt.extension.targetPlatform(targetWindowsAarch64, javaHome)
        }
        configure(rt, jvmArgsWindows)
    }
    else if(os.isLinux())
    {
        if(arch.equals("amd64")) {
            rt.extension.targetPlatform(targetLinuxX86_64, javaHome)
        }
        else if(arch.equals("aarch64")) {
            rt.extension.targetPlatform(targetLinuxAarch64, javaHome)
        }
        configure(rt, jvmArgsLinux)
    }
    else if(os.isMacOsX())
    {
        if(arch.equals("amd64")) {
            rt.extension.targetPlatform(targetOsxX86_64, javaHome)
        }
        else if(arch.equals("aarch64")) {
            rt.extension.targetPlatform(targetOsxAarch64, javaHome)
        }
        configure(rt, jvmArgsLinux)
    }
}


/**
 * Creates a Windows release package.
 *
 * Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
 *
 * Usage: gradle runtimeZipWindows
 * Usage: gradlew runtimeZipWindows   (windows - using gradlew)
 * Usage: ./gradlew runtimeZipWindows   (linux - using gradlew)
 */
tasks.register('runtimeZipWindows', org.beryx.runtime.RuntimeZipTask) {rt ->
    //Windows aarch64
    if(file(jdk_windows_aarch64).exists()) {
        rt.extension.targetPlatform(targetWindowsAarch64, jdk_windows_aarch64, [])
    }
    else {
        rt.extension.targetPlatform(targetWindowsAarch64) {
            jdkHome = jdkDownload(jdk_download_windows_aarch64)
        }
    }
    //Windows x86-64
    if(file(jdk_windows_x86_64).exists()) {
        rt.extension.targetPlatform(targetWindowsX86_64, jdk_windows_x86_64, [])
    }
    else {
        rt.extension.targetPlatform(targetWindowsX86_64) {
            jdkHome = jdkDownload(jdk_download_windows_x86_64)
        }
    }

    configure(rt, jvmArgsWindows)
}

/**
 * Creates Linux & OSX release packages.
 *
 * Note: you cannot create both Windows and Linux releases at the same time due to limitations of the Runtime plugin
 *
 * Usage: gradle runtimeZipOthers
 * Usage: gradlew runtimeZipOthers   (windows - using gradlew)
 * Usage: ./gradlew runtimeZipOthers   (linux - using gradlew)
 */
tasks.register('runtimeZipOthers', org.beryx.runtime.RuntimeZipTask) {rt ->
    //Linux aarch64
    if(file(jdk_linux_aarch64).exists()) {
        rt.extension.targetPlatform(targetLinuxAarch64, jdk_linux_aarch64, [])
    }
    else {
        rt.extension.targetPlatform(targetLinuxAarch64) {
            jdkHome = jdkDownload(jdk_download_linux_aarch64)
        }
    }
    //Linux x86-64
    if(file(jdk_linux_x86_64).exists()) {
        rt.extension.targetPlatform(targetLinuxX86_64, jdk_linux_x86_64, [])
    }
    else {
        rt.extension.targetPlatform(targetLinuxX86_64) {
            jdkHome = jdkDownload(jdk_download_linux_x86_64)
        }
    }
    //OSX aarch64
    if(file(jdk_osx_aarch64).exists()) {
        rt.extension.targetPlatform(targetOsxAarch64, jdk_osx_aarch64, [])
    }
    else {
        rt.extension.targetPlatform(targetOsxAarch64) {
            jdkHome = jdkDownload(jdk_download_osx_aarch64)
        }
    }
    //OSX x86-64
    if(file(jdk_osx_x86_64).exists()) {
        rt.extension.targetPlatform(targetOsxX86_64, jdk_osx_x86_64, [])
    }
    else {
        rt.extension.targetPlatform(targetOsxX86_64) {
            jdkHome = jdkDownload(jdk_download_osx_x86_64)
        }
    }

    configure(rt, jvmArgsLinux)
}
