/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */

boolean isUsingArtifactory = rootProject.hasProperty('artifactoryUser') && rootProject.artifactoryUser &&
        rootProject.hasProperty('artifactoryPassword') && rootProject.artifactoryPassword

if (isUsingArtifactory) {
    logger.lifecycle 'Deployment environment set to Artifactory'
}

def embedded = ['asm', 'asm-util', 'asm-analysis', 'asm-tree', 'asm-commons', 'antlr', 'picocli', 'openbeans']
def removeJarjaredDependencies = { p ->
    p.dependencies.removeAll(p.dependencies.findAll {
        it.groupId == 'org.codehaus.groovy' || embedded.contains(it.artifactId)
    })
}

allprojects {
    if (project == rootProject || modules().contains(project)) {
        apply plugin: 'maven'
        apply from: "${rootProject.projectDir}/gradle/pomconfigurer.gradle"
        install.dependsOn checkCompatibility
    }
}

apply from: 'gradle/backports.gradle'

ext.basename = { String s -> s.take(s.lastIndexOf('.')) }
ext.deriveFile = { File archive, String suffix -> new File(archive.parent, basename(archive.name) + "-${suffix}.jar") }

allprojects {
    if (project == rootProject || modules().contains(project)) {
        ext.addSigFile = { File sigFile, c, ext, n ->
            if (sigFile.exists()) {
                project.artifacts.add('archives', sigFile) {
                    if (n) {
                        name = n
                    }
                    classifier = c
                    type = 'asc'
                    extension = ext
                }
            }
        }
        ext.signWithClassifier = { String c, File f ->
            if (rootProject.isReleaseVersion) {
                signing.sign(c, f)
                def ascFile = new File(f.parent, f.name + '.asc')
                addSigFile(ascFile, c, 'jar.asc', null)
            }
        }
        ext.signWithName = { String baseName, File f ->
            if (rootProject.isReleaseVersion) {
                signing.sign(null, f)
                def ascFile = new File(f.parent, f.name + '.asc')
                addSigFile(ascFile, null, 'jar.asc', baseName)
            }
        }
        ext.signArchiveTask = { archiveTask ->
            if (rootProject.isReleaseVersion) {
                signing.sign(archiveTask.classifier, archiveTask.archivePath)
                def ascFile = new File(archiveTask.destinationDir, archiveTask.archiveName + '.asc')
                addSigFile(ascFile, archiveTask.classifier, archiveTask.extension + '.asc', archiveTask.baseName)
            }
        }

        uploadArchives {
            repositories {
                mavenDeployer {
                    pom pomConfigureClosure
                    beforeDeployment { MavenDeployment deployment -> if (rootProject.isReleaseVersion) signing.signPom(deployment) }
                }
            }
        }

        install {
            repositories {
                mavenInstaller {
                    pom pomConfigureClosure
                    beforeDeployment { MavenDeployment deployment -> if (rootProject.isReleaseVersion) signing.signPom(deployment) }
                }
            }
        }

        artifacts {
            archives jarjar.outputFile
            archives sourceJar
            archives javadocJar
            archives groovydocJar
        }

        configurations.archives.with {
            artifacts.removeAll(artifacts.find { it.name =~ 'raw' } )
        }

        [uploadArchives, install]*.with {
            dependsOn([grooidjar, jarjar, sourceJar, javadocJar, groovydocJar])
            if (rootProject.indyCapable()) {
                dependsOn jarjarWithIndy
            }
            doFirst {
                if (rootProject.indyCapable()) {
                    project.artifacts.add('archives', jarjarWithIndy.outputFile)
                }
                def grooidJarFile = rootProject.ext.deriveFile(jarjar.outputFile, 'grooid')
                if (grooidJarFile.exists()) {
                    project.artifacts.add('archives', grooidJarFile)
                }
            }
        }

        install {
            doFirst {
                // gradle doesn't expect us to mutate configurations like we do here
                // so signing the configuration won't work and we do it manually here
                signWithName(jar.baseName, jarjar.outputFile)
                signArchiveTask(sourceJar)
                signArchiveTask(javadocJar)
                signArchiveTask(groovydocJar)
                def indyJar = rootProject.ext.deriveFile(jarjar.outputFile, 'indy')
                if (indyJar.exists()) {
                    signWithClassifier('indy', indyJar)
                }
                def grooidJarFile = rootProject.ext.deriveFile(jarjar.outputFile, 'grooid')
                if (grooidJarFile.exists()) {
                    signWithClassifier('grooid', grooidJarFile)
                }
            }
        }
    }
}

// the root project generates several alternate artifacts, e.g. 'groovy-all'
// we don't want them in the root project so add them as artifacts with a modified name
// we'll exclude the original artifacts during publication with an exclude pattern
def configureAdditionalArtifacts = {
    if (!rootProject.indyCapable()) {
        throw new GradleException("Indy must be enabled to upload archives")
    }

    project.artifacts.add('archives', distBin) { name = 'groovy-binary' }
    project.artifacts.add('archives', sourceAllJar) { name = 'groovy-all' }
    project.artifacts.add('archives', javadocAllJar) { name = 'groovy-all' }
    project.artifacts.add('archives', groovydocAllJar) { name = 'groovy-all' }
    signArchiveTask(sourceAllJar)
    signArchiveTask(javadocAllJar)
    signArchiveTask(groovydocAllJar)

    if (isReleaseVersion) {
        signing.sign(distBin.archivePath)
        def ascFile = new File(distBin.destinationDir, distBin.archiveName + '.asc')
        if (ascFile.exists()) {
            project.artifacts.add('archives', ascFile) {
                name = 'groovy-binary'
                type = 'asc'
                extension = 'zip.asc'
            }
        }
        signing.sign(distSrc.archivePath)
        signing.sign(distDoc.archivePath)
        signing.sign(dist.archivePath)
    }

    tasks.withType(Jar).matching { it.name.startsWith('backport') }.each { t ->
        project.artifacts.add('archives', t.archivePath) {
            name = t.baseName
            type = 'jar'
            classifier = t.classifier
        }
        if (isReleaseVersion) {
            signing.sign(t.classifier, t.archivePath)
            def ascFile = new File(t.destinationDir, t.archiveName + '.asc')
            if (ascFile.exists()) {
                project.artifacts.add('archives', ascFile) {
                    name = t.baseName
                    classifier = t.classifier
                    type = 'asc'
                    extension = t.extension + '.asc'
                }
            }
        }
    }
}

def optionalModules = [
        'groovy-bsf',
        'groovy-cli-commons',
        'groovy-dateutil',
        'groovy-jaxb',
        'groovy-yaml'
]

def pomAll = {
    addFilter('groovy') { artifact, file ->
        !(artifact.name.contains('groovy-all')) &&
                !(artifact.name.contains('groovy-binary')) &&
                !(artifact.name.contains('groovy-bom')) &&
                !(artifact.name.contains('backport'))
    }
    addFilter('all') { artifact, file ->
        // add an arbitrary artifact, so that the pom file is generated
        // we adjust the packaging attribute later
        artifact.name.contains('groovy-binary')
    }
    addFilter('bom') { artifact, file ->
        // add an arbitrary artifact, so that the pom file is generated
        // we adjust the packaging attribute later
        artifact.name.contains('groovy-binary')
    }
    addFilter('binary') { artifact, file ->
        artifact.name.contains('groovy-binary')
    }
    project.backports.each { pkg, classes ->
        addFilter("backports-$pkg") { artifact, file ->
            artifact.name == "groovy-backports-$pkg"
        }
    }

    // regular pom
    def groovypom = pom('groovy', pomConfigureClosure)

    // pom for binary zip
    def binarypom = pom('binary', pomConfigureClosureWithoutTweaks)
    binarypom.artifactId = 'groovy-binary'

    // poms for backports
    project.backports.each { pkg, classes ->
        String id = "backports-$pkg"
        def backportPom = pom(id, pomConfigureClosureWithoutTweaks)
        backportPom.artifactId = "groovy-$id"
        backportPom.whenConfigured { p ->
            p.dependencies.clear()
        }
    }

    groovypom.whenConfigured(removeJarjaredDependencies)

    binarypom.whenConfigured { p ->
        p.dependencies.clear()
    }

    // pom for "all" dependencies
    def allpom = pom('all', pomConfigureClosureWithoutTweaks)
    allpom.artifactId = 'groovy-all'
    allpom.whenConfigured { p ->
        // this is the only way to get a handle on `maven.Dependency`
        def dependencyClass = p.dependencies[0].getClass()
        p.dependencies.clear()
        // defer setting packaging until here otherwise gets overwritten
        p.packaging = 'pom'
        String groupId = project.group
        allprojects {
            if (it.name.startsWith('groovy') && !optionalModules.contains(it.name)) {
                def dep = dependencyClass.getDeclaredConstructor().newInstance()
                dep.groupId = groupId
                dep.artifactId = it.name
                dep.version = version
                p.dependencies.add(dep)
            }
        }
    }

    // bom for "all" dependencies
    def allbom = pom('bom', pomConfigureClosureWithoutTweaks)
    allbom.artifactId = 'groovy-bom'
    allbom.whenConfigured { p ->
        p.dependencies.clear()
        // defer setting packaging until here otherwise gets overwritten
        p.packaging = 'pom'
        p.withXml { xml ->
            def projectNode = xml.asNode()
            def dependencyManagement = projectNode.appendNode('dependencyManagement').appendNode('dependencies')
            String groupId = project.group
            allprojects { proj ->
                if (proj.name.startsWith('groovy')) {
                    dependencyManagement.appendNode('dependency').with { dep ->
                        dep.appendNode('groupId', groupId)
                        dep.appendNode('artifactId', proj.name)
                        dep.appendNode('version', proj.version)
                    }
                }
            }
        }
    }

    beforeDeployment { MavenDeployment deployment -> if (isReleaseVersion) signing.signPom(deployment) }
}

install {
    // make sure dependencies poms are built *before* the all pom
    dependsOn(modules()*.install)
    dependsOn([sourceAllJar, javadocAllJar, groovydocAllJar, distBin, distDoc, dist, distBin])
    repositories {
        mavenInstaller pomAll
    }
    doFirst configureAdditionalArtifacts
}

uploadArchives {
    // make sure dependencies poms are built *before* the all pom
    dependsOn(modules()*.uploadArchives)
    dependsOn([sourceAllJar, javadocAllJar, groovydocAllJar, distBin, distDoc, dist, distBin])
    repositories {
        mavenDeployer pomAll
    }
    doFirst configureAdditionalArtifacts
}
