import java.util.concurrent.ConcurrentHashMap

description = "Apereo CAS Management Application $version"

defaultTasks "clean", "build"

buildscript {
    repositories {
        mavenLocal()
        mavenCentral() 
        gradlePluginPortal()
    }

    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"
        classpath "com.gorylenko.gradle-git-properties:gradle-git-properties:$gradleGitVersion"
        classpath "io.freefair.gradle:lombok-plugin:$gradleLombokVersion"

        classpath "net.ltgt.gradle:gradle-errorprone-plugin:$gradleErrorProneVersion"
        classpath "com.github.node-gradle:gradle-node-plugin:$gradleNodeVersion"
        classpath "io.github.gradle-nexus:publish-plugin:$gradleNexusPublishingVersion" 
    }
}

ext {
    srcTagMap = new ConcurrentHashMap<File, Set<String>>()

    sonatypeUsername = System.getProperty("sonatypeUsername")
    sonatypePassword = System.getProperty("sonatypePassword")

    publishSnapshots = Boolean.getBoolean("publishSnapshots")
    publishReleases = Boolean.getBoolean("publishReleases")

    skipBootifulArtifact = providers.systemProperty("skipBootifulArtifact").forUseAtConfigurationTime().present
    skipErrorProneCompiler = providers.systemProperty("skipErrorProneCompiler").forUseAtConfigurationTime().present

    enableRemoteDebugging = Boolean.getBoolean("enableRemoteDebugging")
    remoteDebuggingSuspend = Boolean.getBoolean("remoteDebuggingSuspend") ? "y" : "n"
    generateGitProperties = Boolean.getBoolean("generateGitProperties")

    ci = System.getenv("CI") || Boolean.getBoolean("CI")
}

def isArtifactSigningRequired = {
    return publishReleases
}

apply plugin: "io.github.gradle-nexus.publish-plugin"
nexusPublishing {
    packageGroup = "org.apereo"
    repositories {
        sonatype {
            stagingProfileId = "11d1ddbbdeae9d"
            username = "${sonatypeUsername}"
            password = "${sonatypePassword}"
        }
    }
    
    clientTimeout = java.time.Duration.ofSeconds(120)
    connectTimeout = java.time.Duration.ofSeconds(120)
    transitionCheckOptions {
        maxRetries.set(60)
        delayBetween.set(java.time.Duration.ofMillis(60000))
    }
}

apply from: rootProject.file("gradle/dependencies.gradle")

allprojects {
    apply plugin: "idea"
    apply plugin: "eclipse"
    apply plugin: "java-library"

    if (gradle.startParameter.taskNames.any {task -> task.equalsIgnoreCase("install") }) {
        apply plugin: "maven"
    }


    apply from: rootProject.file("gradle/tasks.gradle")

    if (rootProject.publishReleases || rootProject.publishSnapshots || rootProject.generateGitProperties) {
        apply plugin: "com.gorylenko.gradle-git-properties"
        gitProperties {
            extProperty = "gitProps"
            gitPropertiesName = "mgmt-git.properties"
            keys = ["git.branch", "git.build.time", "git.build.user.name",
                    "git.build.version", "git.commit.id", "git.remote.origin.url"]
        }
    }

    project.ext["forceBootifulArtifact"] = null


    java {
        toolchain {
            languageVersion = JavaLanguageVersion.of(project.targetCompatibility)
        }
    }

    idea {
        module {
            downloadSources = false
            downloadJavadoc = false
            jdkName = project.targetCompatibility
            excludeDirs += file(".gradle")
            [".settings", "classes", "bin", "out", "docs", "dependency-cache", "libs", "reports", "resources", "test-results", "tmp"].each {
                excludeDirs += file("$buildDir/$it")
            }
        }
    }

    repositories {
        mavenLocal()
        mavenCentral()
        maven {
            url "$sonatypeReleasesRepositoryUrl"
            mavenContent { releasesOnly() }
        }
        maven {
            url "https://build.shibboleth.net/maven/releases/"
            mavenContent {releasesOnly() }
            content {
                includeGroupByRegex "org\\.opensaml.*"
                includeGroupByRegex "net\\.shibboleth.*"
            }
        }
        maven {
            url "https://jitpack.io"
            content {
                includeGroupByRegex ".*wss4j.*"
            }
            mavenContent { releasesOnly() }
        }
    }

    javadoc {
        options.memberLevel = JavadocMemberLevel.PUBLIC
        options.addBooleanOption('html5', true)
        options.addStringOption('Xdoclint:html,reference,syntax', '-quiet')
        options.addStringOption('encoding', 'UTF-8')
        failOnError = providers.systemProperty("ignoreJavadocFailures").present
        excludes = ['**/generated/**']
    }
    
}

subprojects {
    
    task allDependenciesInsight(type: DependencyInsightReportTask,
            description: "Produce insight information for all dependencies") {
        doLast {}
    }
    task allDependencies(type: DependencyReportTask,
            description: "Display a graph of all project dependencies") {
        doLast {}
    }

    if (projectShouldBePublished(project)) {
        apply plugin: "maven-publish"
        apply plugin: "signing"
    }

    if (!rootProject.skipErrorProneCompiler) {
        apply plugin: "net.ltgt.errorprone"
    }

    ext.libraries = rootProject.ext.libraries

    repositories {
        mavenLocal()
        mavenCentral()
        maven {
            url "https://build.shibboleth.net/nexus/content/repositories/releases"
            content {
                includeGroupByRegex "org\\.opensaml.*"
                includeGroupByRegex "net\\.shibboleth.*"
            }
        }
        maven {
            url "https://oss.sonatype.org/content/repositories/snapshots"
            mavenContent { snapshotsOnly() }
        }
        maven {
            url "https://oss.sonatype.org/content/repositories/releases"
            mavenContent { releasesOnly() }
        }
        maven {
            url "https://splunk.jfrog.io/splunk/ext-releases-local"
            content {
                includeGroupByRegex ".*splunk.*"
            }
            mavenContent { releasesOnly() }
        }
        maven {
            url "https://repo.terracotta.org/maven2"
            mavenContent { releasesOnly() }
            content {
                includeGroup "org.terracotta"
            }
        }
    }

    configurations {
        tests
        provided
    }

    apply from: rootProject.file("gradle/overrides.gradle")

    /**
     * Apply publishing rules after the build has had a chance to
     * evaluate sub-projects to apply plugins, etc.
     */
    afterEvaluate { project ->
        if (projectShouldBePublished(project)) {
            //logger.info "Project ${project.name} should be published"
            apply from: rootProject.file("gradle/maven.gradle")

            publishing {
                publications {
                    def isWarPluginApplied = project.plugins.hasPlugin("war")
                    if (isWarPluginApplied) {
                        //logger.info "Project ${project.name} should be published as a WAR"
                        mavenWeb(MavenPublication) {
                            from components.web
                            pom {
                                createPom(it, project)
                            }
                            pom.withXml {
                                createPomRepositories(asNode())
                            }
                        }
                    } else if (project.hasProperty("skipPublication") && project.skipPublication) {
                        logger.info "Skipping artifact publication for project ${project.name}"
                    } else {
                        //logger.info "Project ${project.name} should be published as a JAR"
                        mavenJava(MavenPublication) {
                            from components.java
                            artifact tasks['sourcesJar']
                            artifact tasks['resourcesJar']
                            artifact tasks['javadocJar']
                            artifact tasks['testJar']

                            pom {
                                createPom(it, project)
                            }
                            pom.withXml {
                                createPomRepositories(asNode())
                            }
                        }
                    }
                }

                repositories {
                    if (rootProject.publishReleases) {
                        maven {
                            name "Sonatype-Releases"
                            url "${sonatypeRepositoryUrl}"
                            mavenContent {
                                releasesOnly()
                            }
                            credentials {
                                username "${sonatypeUsername}"
                                password "${sonatypePassword}"
                            }
                        }
                    }
                    if (rootProject.publishSnapshots) {
                        maven {
                            name "Sonatype-Snapshots"
                            url "${sonatypeSnapshotsRepositoryUrl}"
                            mavenContent {
                                snapshotsOnly()
                            }
                            credentials {
                                username "${sonatypeUsername}"
                                password "${sonatypePassword}"
                            }
                        }
                    }
                }
            }

            signing {
                required = isArtifactSigningRequired
                sign publishing.publications
            }
        }
    }

    artifacts {
        tests testJar
        if (rootProject.publishReleases || rootProject.publishSnapshots) {
            archives sourcesJar
            archives javadocJar
            archives resourcesJar
        }
        archives testJar
    }

    sourceSets {
        main {
            compileClasspath += configurations.provided
            runtimeClasspath += configurations.provided

            java {
                srcDirs = ["${projectDir}/src/main/java"]
            }
            resources {
                srcDirs = ["${projectDir}/src/main/resources"]
            }
        }
        test {
            java {
                srcDirs = ["${projectDir}/src/test/java"]
            }
            resources {
                srcDirs = ["${projectDir}/src/test/resources"]
            }
        }
    }

    ext.buildDate = null
    ext.buildJarFile = new File(project.buildDir, "libs/${project.name}-${project.version}.jar")

    tasks.withType(JavaCompile).configureEach {
        options.fork = true
        options.incremental = true

        def casCompilerArgs = ["-parameters"]

        def terminateCompilerOnWarning = project.ext.properties.get("terminateCompilerOnWarning", true)
        if (terminateCompilerOnWarning) {
            casCompilerArgs.add("-Werror")
        }

        if (!rootProject.skipErrorProneCompiler) {
            options.errorprone.allErrorsAsWarnings = false
            options.errorprone.disableWarningsInGeneratedCode = true
            options.errorprone.errorproneArgs.addAll(['-Xep:SameNameButDifferent:OFF', '-Xep:ParameterName:OFF',
                                                     '-Xep:MissingOverride:OFF', '-Xep:MissingSummary:OFF',
                                                     '-Xep:JavaUtilDate:OFF', '-Xep:JdkObsolete:OFF'])
            casCompilerArgs.add("-XDcompilePolicy=byfile")
        }
        options.compilerArgs.addAll(casCompilerArgs)
    }

    if (projectShouldBePublished(project)) {
        apply plugin: "io.freefair.lombok"
        lombok {
            version = "$lombokVersion"
        }
    }

    jar {
        manifest {
            attributes(
                    "Automatic-Module-Name": project.name,
                    "Implementation-Title": project.name,
                    "Implementation-Vendor": project.group,
                    "Created-By": project.group,
                    "Specification-Version": "${-> project.ext.has("gitProps") ? project.ext.gitProps['git.commit.id'] : 'N/A'}",
                    "Implementation-Version": project.version)
        }
    }


    if (!Boolean.getBoolean("skipCheckstyle") && projectShouldBePublished(project)) {
        apply plugin: "checkstyle"
        checkstyle {
            configProperties = [
                "checkstyle.suppressions.file" : new File(rootDir, "style/checkstyle-suppressions.xml"),
                "checkstyle.importcontrol.file": new File(rootDir, "style/import-control.xml")
            ]
            configFile = new File(rootDir, "style/checkstyle-rules.xml")
            ignoreFailures false
            showViolations true
            toolVersion "${checkstyleVersion}"
        }
    }

    dependencies {

        implementation libraries.validationapi

        api libraries.slf4j

        api libraries.commons
        api libraries.springboot
        api libraries.javax

        if (!skipErrorProneCompiler) {
            errorprone "com.google.errorprone:error_prone_core:$errorProneVersion"
        }
        testImplementation libraries.tests
        implementation libraries.log4j
    }
}

tasks.withType(Javadoc) {
    source subprojects.collect { project -> project.sourceSets.main.allJava }
    destinationDir = new File(buildDir, "javadoc")
    classpath = files(subprojects.collect { project -> project.sourceSets.main.compileClasspath })
    options.addBooleanOption('html5', true)
    failOnError = Boolean.getBoolean("ignoreJavadocFailures")
}

task aggregateJavadocsIntoJar(type: Jar, dependsOn: javadoc, description: "Aggregate all Javadocs into a single directory") {
    archiveClassifier = "javadoc"
    from javadoc
}

task rootSourcesJar(type: Jar, description: "Build JAR for the root CAS module") {
    archiveBaseName = "${project.archivesBaseName}"
    from rootProject.file("src")
}

task gradleHome(description: "Display GRADLE_HOME environment variable") {
    doFirst {
        println "\nexport GRADLE_HOME=" + gradle.gradleHomeDir
    }
}

if (rootProject.publishReleases || rootProject.publishSnapshots) {
    artifacts {
        archives aggregateJavadocsIntoJar
        archives rootSourcesJar
    }
}

task casVersion(description: "Display current CAS version") {
    doLast {
        println rootProject.version
    }
}

task signingKey(description: "Display CAS signing key id") {
    doLast {
        println "Signing key: " + project.findProperty("signing.keyId")
    }
}

task verifyRequiredJavaVersion {
    def requiredVersion = JavaVersion.toVersion(project.targetCompatibility)
    if (!JavaVersion.current().isCompatibleWith(requiredVersion)) {
        throw new GradleException("Current Java version ${JavaVersion.current()} does not match required Java version ${requiredVersion}")
    }
}

boolean projectShouldBePublished(Project project) {
    return !["api", "core", "docs", "support", "webapp", "cas-server-documentation"].contains(project.name)
}


