/*
 *  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.
 */


import org.apache.groovy.gradle.CoreExtension
import org.apache.groovy.gradle.DgmConverter
import org.apache.groovy.gradle.JarJarTask

import javax.inject.Inject

plugins {
    id 'org.apache.groovy-common'
    id 'org.apache.groovy-base'
    id 'org.apache.groovy-published-library'
    id 'org.apache.groovy-documented'
    id 'antlr'
}

project.extensions.create('groovyCore', CoreExtension, sourceSets)

configurations {
    compilerCompile
    tools
    spec
}

sourceSets {
    main {
        java {
            if (!JavaVersion.current().isJava9Compatible()) {
                exclude '**/v9/*'
                exclude '**/vm9/*'
                exclude '**/PlatformLog.java'
            }
            if (!JavaVersion.current().isJava10Compatible()) {
                exclude '**/v10/*'
                exclude '**/vm10/*'
            }
            if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
                exclude '**/v16/*'
                exclude '**/vm16/*'
            }
        }
        groovy {
            if (!JavaVersion.current().isJava9Compatible()) {
                exclude '**/v9/*'
                exclude '**/vm9/*'
            }
            if (!JavaVersion.current().isJava10Compatible()) {
                exclude '**/v10/*'
                exclude '**/vm10/*'
            }
            if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
                exclude '**/v16/*'
                exclude '**/vm16/*'
            }
        }
        antlr {
            srcDirs = ['src/antlr']
        }
        resources {
            srcDirs = ['src/resources']
        }
    }
    test {
        groovy {
            srcDirs += ['src/test']
            if (!JavaVersion.current().isJava9Compatible()) {
                exclude '**/v9/*'
                exclude '**/vm9/*'
            }
            if (!JavaVersion.current().isJava10Compatible()) {
                exclude '**/v10/*'
                exclude '**/vm10/*'
            }
            if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
                exclude '**/v16/*'
                exclude '**/vm16/*'
            }
        }
        resources {
            srcDirs += ['src/test-resources']
        }
    }
    tools {
        compileClasspath = sourceSets.main.runtimeClasspath + configurations.tools
        runtimeClasspath = output + compileClasspath
    }
}

def dgmConverter = tasks.register("dgmConverter", DgmConverter) {
    classpath.from files(compileJava, configurations.compileClasspath)
    sources.from('src/main').include('**/*GroovyMethods.java')
}

dependencies {
    runtimeOnly files(dgmConverter)
}

tasks.named('jar') {
    from dgmConverter
}

tasks.named('jarjar') { JarJarTask it ->
    def groovyBundleVersion = sharedConfiguration.groovyBundleVersion.get()
    it.withManifest {
        version = groovyBundleVersion
        instruction '-nouses', 'true'
        instruction 'Export-Package', "*;version=${groovyBundleVersion}"
        instruction 'Eclipse-ExtensibleAPI', 'true'
    }
}

// Gradle classloading magic with Groovy will only work if it finds a *jar*
// on classpath. This "bootstrap jar" contains the minimal compiler, without .groovy compiled files

def bootstrapJar = tasks.register("bootstrapJar", Jar) {
    from compileJava
    from dgmConverter

    destinationDirectory = layout.buildDirectory.dir("bootstrap")
    archiveClassifier = 'bootstrap'
}

// The main Groovy compile tasks has a special setup because
// it uses the "bootstrap compiler"
tasks.withType(GroovyCompile).configureEach {
    groovyClasspath = files(bootstrapJar, groovyClasspath)
    if (it.name == 'compileGroovy') {
        classpath = files(bootstrapJar, classpath)
    }
    options.incremental = true
}

allprojects {
    tasks.withType(JarJarTask).configureEach {
        jarjarToolClasspath.from(rootProject.configurations.tools)
    }
}

interface CoreServices {
    @Inject
    ExecOperations getExecOperations()
}

def execOperations = objects.newInstance(CoreServices).execOperations

tasks.named('compileJava') {
    options.fork(memoryMaximumSize: sharedConfiguration.javacMaxMemory.get())
    inputs.files(configurations.tools)

    doLast {
        execOperations.javaexec { spec ->
            spec.classpath(rootProject.configurations.tools)
            spec.mainClass = 'org.jboss.bridger.Bridger'
            spec.args(groovyCore.classesToBridge.asList().collect { it.absolutePath })
        }
    }
}

tasks.named('compileTestGroovy') {
    groovyOptions.fork(memoryMaximumSize: groovycTest_mx)
}

tasks.register('checkCompatibility') {
    doLast {
        assert JavaVersion.current().java11Compatible
    }
}

tasks.named('javadoc') {
    groovyCore.excludedFromJavadocs.each {
        exclude it
    }
}

tasks.withType(Test).configureEach {
    jvmArgs /*"-Dgroovy.attach.groovydoc=true", "-Dgroovy.attach.runtime.groovydoc=true",*/ "-Dgroovy.antlr4.cache.threshold=100"
}

def generateGrammarSourceTask = tasks.named("generateGrammarSource") {
    maxHeapSize = '1g'
    outputs.cacheIf { true }
    outputDirectory = layout.buildDirectory.dir("generated/sources/antlr4").get().asFile

    final PARSER_PACKAGE_NAME = 'org.apache.groovy.parser.antlr4'
    arguments += ["-visitor", "-no-listener", "-package", PARSER_PACKAGE_NAME]

    doLast {
        def parserFilePattern = 'Groovy*'
        def outputPath = generateGrammarSource.outputDirectory.canonicalPath
        def parserPackagePath = "${outputPath}/${PARSER_PACKAGE_NAME.replace('.', '/')}"
        file(parserPackagePath).mkdirs()
        copy {
            from outputPath
            into parserPackagePath
            include parserFilePattern
        }
        delete fileTree(outputPath) {
            include parserFilePattern
        }
    }
}

sourceSets.main.java.srcDir generateGrammarSourceTask

configurations {
    sourcesForAggregation {
        canBeConsumed = true
        canBeResolved = false
        extendsFrom implementation, runtimeOnly
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION))
            attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL))
            attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.SOURCES))
            attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, "aggregation"))
        }
        outgoing {
            sourceSets.main.java.srcDirs.each {
                artifact(it)
            }
            sourceSets.main.groovy.srcDirs.each {
                artifact(it)
            }
            sourceSets.main.antlr.srcDirs.each {
                artifact(it)
            }
        }
    }
}
