plugins {
    id 'java'
    id 'application'
    id 'checkstyle'
    id 'jacoco'
    id 'com.github.ben-manes.versions' version '0.12.0'
    id 'com.github.johnrengelman.shadow' version '1.2.3'
    id 'com.install4j.gradle' version '7.0.1'
    id 'de.undercouch.download' version '3.2.0'
    id "net.ltgt.errorprone" version "0.0.11"
}

apply from: 'gradle/scripts/yaml.gradle'

group = 'triplea'
description = 'TripleA is a free online turn based strategy game and board game engine, similar to such board games as Axis & Allies or Risk.'
mainClassName = "games.strategy.engine.framework.GameRunner"

ext {
    artifactsDir = file("$buildDir/artifacts")
    releasesDir = file("$buildDir/releases")
    rootFilesDir = file("$buildDir/rootFiles")
    schemasDir = file('config/triplea/schemas')

    gameEnginePropertiesFile = file('game_engine.properties')
    gameEnginePropertiesArtifactFile = file("$rootFilesDir/${gameEnginePropertiesFile.name}")
}

def getEngineVersion() {
    if (project.hasProperty('engineVersion')) {
        return project.engineVersion
    }

    def props = new Properties()
    gameEnginePropertiesFile.withInputStream { props.load(it) }
    def devEngineVersion = props.getProperty('engine_version')
    if (devEngineVersion) {
        return "${devEngineVersion}.dev"
    }

    throw new GradleException("unable to determine engine version: "
        + "you must define either the project property 'engineVersion' or the game engine property 'engine_version'")
}

version = getEngineVersion()

sourceSets {
    integTest {
        java.srcDir 'src/integ_test/java'
        resources.srcDir 'src/integ_test/resources'

        compileClasspath = sourceSets.main.output + sourceSets.test.output + configurations.testRuntime
        runtimeClasspath = output + compileClasspath
    }
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

tasks.withType(JavaCompile) {
    options.compilerArgs += [ '-Xlint:all' ]
    options.incremental = true
    options.encoding = 'UTF-8'
}

jar {
    manifest {
        attributes 'Main-Class': mainClassName, 'TripleA-Version': version
    }
}

repositories {
    jcenter()
}

dependencies {
    errorprone 'com.google.errorprone:error_prone_core:2.0.5'
    compile 'commons-io:commons-io:2.5'
    compile 'postgresql:postgresql:9.1-901-1.jdbc4'
    compile 'com.github.insubstantial:substance:7.3'
    compile 'com.google.code.findbugs:jsr305:3.0.2'
    compile 'com.google.guava:guava:19.0'
    compile 'com.googlecode.soundlibs:jlayer:1.0.1-2'
    compile 'com.sun.mail:mailapi:1.5.5'
    compile 'com.sun.mail:smtp:1.5.5'
    compile 'commons-io:commons-io:2.5'
    compile 'org.apache.httpcomponents:httpclient:4.5.3'
    compile 'org.apache.httpcomponents:httpmime:4.5.3'
    compile 'org.apache.commons:commons-math3:3.6.1'
    compile 'org.mindrot:jbcrypt:0.4'
    compile 'org.yaml:snakeyaml:1.17'
    compile 'org.json:json:20160810'
    compile 'com.yuvimasory:orange-extensions:1.3.0'

    testCompile 'eu.codearte.catch-exception:catch-exception:2.0.0-ALPHA-1'
    testCompile 'nl.jqno.equalsverifier:equalsverifier:2.3'
    testCompile 'org.hamcrest:java-hamcrest:2.0.0.0'
    testCompile 'org.mockito:mockito-core:2.8.47'
    testCompile 'junit:junit:4.12'
}

test {
    exclude '**/*Tests.class'
}


task integTest(type: Test) {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = 'Runs the integration tests.'

    testClassesDirs = sourceSets.integTest.output.classesDirs
    classpath = sourceSets.integTest.runtimeClasspath

    binResultsDir = file("$buildDir/integration_test_results/binary/integTest")

    reports {
        reports.html.destination = file("${reports.html.destination}/$name")
        reports.junitXml.destination = file("${reports.junitXml.destination}/$name")
    }

    mustRunAfter tasks.test
}

task jacocoRootReport(type: JacocoReport) {
    group = LifecycleBasePlugin.VERIFICATION_GROUP
    description = 'Generates code coverage report for all Test tasks.'

    sourceSets sourceSets.main
    executionData fileTree(buildDir).include('**/jacoco/*.exec')

    reports {
        html {
            destination = file("${project.jacoco.reportsDir}/root/html")
            enabled = true
        }
        xml {
            destination = file("${project.jacoco.reportsDir}/root/jacocoRootReport.xml")
            enabled = true
        }
    }
}

task validateYamls(group: 'verification', description: 'Validates YAML files.') {
    doLast {
        def lobbyServerYamlFile = file('lobby_server.yaml')
        validateYaml(lobbyServerYamlFile, file("$schemasDir/lobby_server.json"))

        def mapsYamlFile = file('triplea_maps.yaml')
        validateYaml(mapsYamlFile, file("$schemasDir/triplea_maps.json"))
        validateMapsYamlUris(mapsYamlFile)
    }
}

task renameShadowJar(type: Copy, group: 'release', dependsOn: [shadowJar]) {
    ext.output = file("$libsDir/all/triplea.jar")
    from shadowJar.archivePath
    into ext.output.parent
    rename shadowJar.archivePath.name, output.name
}

task downloadAssets(group: 'release') {
    doLast {
        [
            'icons/triplea_icon_16_16.png',
            'icons/triplea_icon_32_32.png',
            'icons/triplea_icon_48_48.png',
            'icons/triplea_icon_64_64.png',
            'icons/triplea_icon_128_128.png',
            'icons/triplea_icon_256_256.png',
            'install4j/macosx-amd64-1.8.0_144.tar.gz',
            'install4j/windows-amd64-1.8.0_144.tar.gz',
            'install4j/windows-x86-1.8.0_144.tar.gz'
        ].each { path ->
            download {
                src "https://raw.githubusercontent.com/triplea-game/assets/master/$path"
                dest "$buildDir/assets/$path"
                overwrite false
            }
        }
    }
}

task prepareGameEngineProperties() {
    group = 'release'
    description = 'Updates the game engine properties with final values for distribution.'

    doLast {
        copy {
            from gameEnginePropertiesFile
            into gameEnginePropertiesArtifactFile.parent
        }
        ant.propertyfile(file: gameEnginePropertiesArtifactFile) {
            entry key: 'engine_version', value: version
        }
    }
}

task allPlatform(type: Zip, group: 'release', dependsOn: [renameShadowJar, prepareGameEngineProperties]) {
    classifier 'all_platforms'
    ['assets', 'dice_servers'].each { folder ->
        from(folder) {
            into(folder)
        }
    }
    from(gameEnginePropertiesArtifactFile)
    from(renameShadowJar.output) {
        into('bin')
    }
}

task lobbyServer(type: Zip, group: 'release', dependsOn: renameShadowJar) {
    classifier 'server'
    ['config/lobby/lobby.properties'].each { fileName ->
        from(fileName) {
            into('config/lobby')
        }
    }
    from(renameShadowJar.output) {
        into('bin')
    }
}

task generateZipReleases(group: 'release', dependsOn: [allPlatform, lobbyServer]) {}

import com.install4j.gradle.Install4jTask
task generateInstallers(type: Install4jTask, dependsOn: [renameShadowJar, downloadAssets], group: 'release') {
    projectFile = file('build.install4j')
    release project.version
    doFirst {
        logger.lifecycle("building installer release of version '${project.version}'")
    }
}

task prepareInstallers(group: 'release', dependsOn: [generateInstallers]) {
    doLast {
        ant.chmod(dir: releasesDir, perm: '+x', includes: '*.sh')
    }
}

task prepareArtifacts(group: 'release', dependsOn: [generateZipReleases, prepareInstallers]) {
    doLast {
        def artifacts = [
            file("$libsDir/triplea-$version-all.jar"),
            file("$distsDir/triplea-$version-all_platforms.zip"),
            file("$distsDir/triplea-$version-server.zip"),
            file("$releasesDir/TripleA_${version}_macos.dmg"),
            file("$releasesDir/TripleA_${version}_unix.sh"),
            file("$releasesDir/TripleA_${version}_windows-32bit.exe"),
            file("$releasesDir/TripleA_${version}_windows-64bit.exe")
        ]
        artifacts.each {
            if (!it.exists()) {
                throw new GradleException("artifact '$it' does not exist")
            }
        }

        copy {
            from artifacts
            into artifactsDir
        }
    }
}

task release(group: 'release', dependsOn: [prepareArtifacts]) {}

gradle.taskGraph.whenReady { graph ->
    graph.getAllTasks().any({
        if (it.name == "generateInstallers") {
            if (!project.hasProperty('install4jHomeDir')) {
                File propertiesFile = file("${System.getProperty('user.home')}/.gradle/gradle.properties")
                throw new RuntimeException("Specify install4jHomeDir in $propertiesFile")
            }
            def p = file(project.install4jHomeDir)
            logger.lifecycle('using install4j home directory ' + p.getAbsolutePath())
            it.project.install4j.installDir = file(project.install4jHomeDir)
        }
    })
}

tasks.withType(Test) {
    testLogging {
        exceptionFormat = 'full'
    }
}

check {
    dependsOn 'integTest', 'validateYamls'
}

checkstyle {
    toolVersion = "8.0"
    configProperties = [samedir: configFile.parent]
}

checkstyleIntegTest {
    maxWarnings = checkstyleIntegTestMaxWarnings.toInteger()
    source sourceSets.integTest.output.resourcesDir
}

checkstyleMain {
    maxWarnings = checkstyleMainMaxWarnings.toInteger()
    source sourceSets.main.output.resourcesDir
}

checkstyleTest {
    maxWarnings = checkstyleTestMaxWarnings.toInteger()
    source sourceSets.test.output.resourcesDir
}

jacocoTestReport {
    reports {
        xml.enabled true
        html.enabled true
    }
}
