/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import de.undercouch.gradle.tasks.download.Download
import org.apache.tools.ant.taskdefs.condition.Os
import com.facebook.fresco.buildsrc.Deps
import com.facebook.fresco.buildsrc.GradleDeps

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        classpath GradleDeps.Android.gradlePlugin
        classpath GradleDeps.Kotlin.gradlePlugin

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

plugins {
    id "de.undercouch.download" version "5.3.1"
    id "com.vanniktech.maven.publish" version "0.25.3"
}

// Make sure to add trailing slash to the absolute paths
LinkedHashMap<String, String> commonNdkLocations = [
        "macOS-internal":"/opt/android_sdk/ndk/",
        "linux-ubuntu":"/usr/local/lib/android/sdk/ndk/",
]

subprojects {

    repositories {
        google()
        mavenCentral()
    }

    // FIXME: This picks up non-Java files by default, failing to parse them.
    // Need to configure this more carefully.
    tasks.withType(Javadoc).all {
        enabled = false
    }

    tasks.withType(com.android.build.gradle.tasks.JavaDocGenerationTask).all {
        enabled = false
    }


    if (System.getenv("SANDCASTLE") == "1") {
        tasks.withType(Test).all {
            systemProperty("robolectric.dependency.repo.id", "central")
            systemProperty("robolectric.dependency.repo.url", "https://maven.thefacebook.com/nexus/content/repositories/central/")
            systemProperty("robolectric.logging", "stdout")
            systemProperty("robolectric.logging.enabled", "true")
            systemProperty("java.net.preferIPv6Addresses", "true")
            systemProperty("java.net.preferIPv4Stack", "false")
            systemProperty("jdk.attach.allowAttachSelf", "true")
            jvmArgs '-XX:+StartAttachListener'
        }
    }

    configurations.all {
        resolutionStrategy.force Deps.jsr305
    }

    task allclean {
    }

    // Sets the ndkPath for each module when running on CI
    if (System.getenv("SANDCASTLE") == "1") {
        String ndkDir = System.getenv("ANDROID_NDK_HOME")
        project.plugins.whenPluginAdded { plugin ->
            if ("com.android.build.gradle.AppPlugin" == plugin.class.name) {
                project.android.ndkPath = ndkDir
            } else if ("com.android.build.gradle.LibraryPlugin" == plugin.class.name) {
                project.android.ndkPath = ndkDir
            }
        }
    }

    apply plugin: 'de.undercouch.download'

    ext.makeNdkTasks = { name, deps ->
        task "ndk_build_${name}"(dependsOn: deps, type: Exec) {
            inputs.files("src/main/jni/${name}")
            outputs.dir("$buildDir/${name}")
            commandLine getNdkBuildFullPath(project),
                    'NDK_PROJECT_PATH=null',
                    'NDK_APPLICATION_MK=../Application.mk',
                    'NDK_OUT=' + temporaryDir,
                    "NDK_LIBS_OUT=$buildDir/${name}",
                    '-C', file("src/main/jni/${name}").absolutePath,
                    '--jobs', Runtime.getRuntime().availableProcessors()
        }

        task "ndk_clean_$name"(type: Exec) {
            ignoreExitValue true
            commandLine getNdkBuildFullPath(project),
                    'NDK_PROJECT_PATH=null',
                    'NDK_APPLICATION_MK=../Application.mk',
                    'NDK_OUT=' + temporaryDir,
                    "NDK_LIBS_OUT=$buildDir/${name}",
                    '-C', file("src/main/jni/${name}").absolutePath,
                    'clean'
        }

        tasks.withType(JavaCompile) {
            compileTask -> compileTask.dependsOn "ndk_build_$name"
        }
        clean.dependsOn "ndk_clean_$name"
    }

    ext.getNdkBuildName =  {
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            return "ndk-build.cmd"
        } else {
            return "ndk-build"
        }
    }

    ext.discoverNdkPathFromCommonLocations = { String ndkVersion ->
        String foundNdkLocation = null
        for (entry in commonNdkLocations) {
            String variant = entry.key
            String location = entry.value

            String ndkDir = location + ndkVersion
            File ndkFolder = new File(ndkDir)
            if (ndkFolder.exists()) {
                println("NDK Path found using: common $variant location")
                foundNdkLocation = ndkDir
                break
            }
        }

        return foundNdkLocation
    }

    ext.getNdkBuildFullPath = { Project project ->
        String path = null

        // Latest method using the common NDK version used throughout the project and using the standard NDK SxS location on macOS
        if (path == null) {
            path = discoverNdkPathFromCommonLocations(GradleDeps.Native.version)
        }

        // Fallback method for CI
        if (path == null) {
            String ndkDir = System.getenv("ANDROID_NDK_HOME")
            if (ndkDir != null) {
                File ndkFolder = new File(ndkDir)
                if (ndkFolder.exists()) {
                    path = ndkDir
                    println("NDK Path found using: ANDROID_NDK_HOME")
                }
            }
        }

        // Legacy methods of finding NDK path
        if (path == null) {
            File propFile = project.rootProject.file('local.properties')
            if (!propFile.exists()) {
                println("NDK Path found using: local.props missing, just the command name")
                return getNdkBuildName()
            }
            Properties properties = new Properties()
            properties.load(propFile.newDataInputStream())
            def ndkCommand = properties.getProperty('ndk.command')
            if (ndkCommand != null) {
                println("NDK Path found using: ndk.command")
                return ndkCommand
            }
            def ndkPath = properties.getProperty('ndk.path')
            if (ndkPath != null) {
                println("NDK Path found using: ndk.path")
                path = ndkPath
            } else {
                def ndkDir = properties.getProperty('ndk.dir')
                if (ndkDir != null) {
                    println("NDK Path found using: ndk.dir")
                    path = ndkDir
                }
            }
        }

        if (path != null) {
            if (!path.endsWith(File.separator)) {
                path += File.separator
            }
            return path + getNdkBuildName()
        } else {
            // if none of above is provided, we assume ndk-build is already in $PATH
            return getNdkBuildName()
        }
    }

    ext.nativeDepsDir = new File("${projectDir}/nativedeps")
    ext.downloadsDir = new File("${nativeDepsDir}/downloads")
    ext.mergeDir = new File("${nativeDepsDir}/merge")

    task removeNativeDeps(type: Delete) {
        delete nativeDepsDir
    }
    allclean.dependsOn removeNativeDeps

    task createNativeDepsDirectories {
        nativeDepsDir.mkdirs()
        downloadsDir.mkdirs()
        mergeDir.mkdirs()
    }

    ext.createNativeLibrariesTasks = {name, libraryUrl, libraryFileName, libraryDestinationDir, sourceDir, includePaths, destinationDir ->
        // We create the DownloadTask
        tasks.create("download${name}", Download) {
            src libraryUrl
            onlyIfNewer true
            overwrite false
            dest "${downloadsDir}/${libraryFileName}"
            dependsOn createNativeDepsDirectories
        }
        // The unpack task
        tasks.create("unpack${name}", Copy) {
            String filePath = "${downloadsDir}/${libraryFileName}"
            ReadableResource resource
            if (filePath.endsWith("gz")) {
                resource = resources.gzip(filePath)
            } else if (filePath.endsWith("bz2")) {
                resource = resources.bzip2(filePath)
            } else {
                throw new GradleException("Could not unpack library " + filePath)
            }
            from tarTree(resource)
            into "${downloadsDir}/${libraryDestinationDir}"
            dependsOn "download${name}"
        }
        // The copy task
        Task unpackTask = tasks.getByName("unpack${name}")
        tasks.create("copy${name}", Copy) {
            from "${unpackTask.destinationDir}/${sourceDir}"
            from "src/main/jni/third-party/${destinationDir}"
            // Allows for overriding when duplicates are encountered.
            duplicatesStrategy DuplicatesStrategy.INCLUDE
            include(includePaths)
            into "${mergeDir}/${destinationDir}"
            dependsOn "unpack${name}"
        }

    }

    // Libjpeg-turbo
    createNativeLibrariesTasks(
            'Libjpeg',      // Name for the tasks
            "https://github.com/libjpeg-turbo/libjpeg-turbo/archive/${LIBJPEG_TURBO_VERSION}.tar.gz", // The Url for download
            "${LIBJPEG_TURBO_VERSION}.tar.gz", // The downloaded file
            'libjpeg', // The folder where the file is downloaded
            "libjpeg-turbo-${LIBJPEG_TURBO_VERSION}", // The first dir where we have put our customisation
            ['**/*.c', '**/*.h','**/*.S', '**/*.asm', '**/*.inc', '*.mk'], // Files to compile
            "libjpeg-turbo-${LIBJPEG_TURBO_VERSION}" // Final destination dir
    )

    // Libpng
    createNativeLibrariesTasks(
            'Libpng',      // Name for the tasks
            "https://github.com/glennrp/libpng/archive/v${LIBPNG_VERSION}.tar.gz", // The Url for download
            "v${LIBPNG_VERSION}.tar.gz", // The downloaded file
            'libpng', // The folder where the file is downloaded
            "libpng-${LIBPNG_VERSION}", // The first dir where we have put our customisation
            ['**/*.c', '**/*.h', '**/*.S', '*.mk'], // Files to compile
            "libpng-${LIBPNG_VERSION}" // Final destination dir
    )

    // Gif
    createNativeLibrariesTasks(
            'Giflib',      // Name for the tasks
            "https://sourceforge.net/projects/giflib/files/giflib-${GIFLIB_VERSION}.tar.gz/download", // The Url for download
            "giflib-${GIFLIB_VERSION}.tar.gz", // The downloaded file
            'giflib', // The folder where the file is downloaded
            "giflib-${GIFLIB_VERSION}", // The first dir where we have put our customisation
            ['*.c', '*.h', '*.mk'], // Files to compile
            "giflib" // Final destination dir
    )

    // Webp
    createNativeLibrariesTasks(
            'Libwebp',      // Name for the tasks
            "https://github.com/webmproject/libwebp/archive/v${LIBWEBP_VERSION}.tar.gz", // The Url for download
            "v${LIBWEBP_VERSION}.tar.gz", // The downloaded file
            'libwebp', // The folder where the file is downloaded
            "libwebp-${LIBWEBP_VERSION}", // The first dir where we have put our customisation
            ['**/*.c', '**/*.h', '*.mk'], // Files to compile
            "libwebp-${LIBWEBP_VERSION}" // Final destination dir
    )
}
