// Build Script
// ============

if (System.env.TRAVIS == 'true') {
  allprojects {
    tasks.withType(GroovyCompile) {
      groovyOptions.fork = false
    }
    tasks.withType(Test) {
      maxParallelForks = 1
      maxHeapSize = '512m'
    }
  }
}

import groovy.io.FileType

buildscript {
  repositories {
    mavenLocal()
    maven {
      url 'https://plugins.gradle.org/m2/'
    }
    mavenCentral()
    jcenter()
  }
  dependencies {
    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.1'
    classpath 'gradle.plugin.com.github.sherter.google-java-format:google-java-format-gradle-plugin:0.6'
    classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3'
    classpath 'net.ltgt.gradle:gradle-apt-plugin:0.10'
  }
}


apply plugin: 'jacoco'
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: 'com.google.protobuf'
apply plugin: 'com.github.sherter.google-java-format'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'signing'
apply plugin: 'net.ltgt.apt'

sourceCompatibility = 1.8

group = 'com.google.api'
project.version = file('version.txt').text.trim()

def protoVersion = '3.4.0'

// Dependencies
// ------------

ext {
  // Shortcuts for libraries we are using
  libraries = [
    // General

    // Guava 23.0 is for Java 8, Java 7 needs to use 23.0-android.
    guava: 'com.google.guava:guava:23.0-android',
    jsr305: 'com.google.code.findbugs:jsr305:3.0.0',
    autovalue: 'com.google.auto.value:auto-value:1.4',
    commonsLang: 'org.apache.commons:commons-lang3:3.6',
    commonsCli: 'commons-cli:commons-cli:1.4',
    snakeyaml: 'org.yaml:snakeyaml:1.18',
    commonmark: 'com.atlassian.commonmark:commonmark:0.9.0',
    gax: 'com.google.api:gax:1.5.1',

    // Gapi
    toolsFx: 'com.google.api:api-compiler:0.0.7',

    // Testing
    junit: 'junit:junit:4.12',
    truth: 'com.google.truth:truth:0.34',
    toolsFxTesting: 'com.google.api:api-compiler:0.0.6:testing',

    // Protobuf
    protobuf: 'com.google.protobuf:protobuf-java:' + protoVersion,
    protoc:  'com.google.protobuf:protoc:' + protoVersion,

    // JSON
    jackson: 'com.fasterxml.jackson.core:jackson-databind:2.9.0',
    jacksonGuava: 'com.fasterxml.jackson.datatype:jackson-datatype-guava:2.9.0',

    // Formatter
    javaFomatter: 'com.google.googlejavaformat:google-java-format:1.1'
  ]
}

repositories {
  mavenLocal()
  mavenCentral()
}

dependencies {
  compile libraries.guava,
    libraries.autovalue,
    libraries.commonsCli,
    libraries.commonsLang,
    libraries.gax,
    libraries.jackson,
    libraries.jacksonGuava,
    libraries.javaFomatter,
    libraries.jsr305,
    libraries.protobuf,
    libraries.snakeyaml,
    libraries.toolsFx,
    libraries.toolsFxTesting,
    libraries.commonmark

  testCompile libraries.junit,
    libraries.truth,
    libraries.toolsFxTesting
}

task discoJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
  archiveName = "discoGen-${version}.jar"
  manifest {
    attributes 'Main-Class': 'com.google.api.codegen.DiscoveryFragmentGeneratorTool'
  }
  from sourceSets.main.output
  configurations = [ project.configurations.runtime ]
  exclude 'META-INF/*.SF'
  exclude 'META-INF/*.DSA'
  exclude 'META-INF/*.RSA'
}

task fatJar(type: com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar) {
  archiveName = "gapic.jar"
  from sourceSets.main.output
  configurations = [ project.configurations.runtime ]
  exclude 'META-INF/*.SF'
  exclude 'META-INF/*.DSA'
  exclude 'META-INF/*.RSA'
}

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

check.dependsOn jacocoTestReport

// Source jar
task sourcesJar(type: Jar, dependsOn: classes) {
  classifier = 'sources'
  from sourceSets.main.allSource
}

// Protobuf
// --------

sourceSets {
  main {
    proto {
      // Include proto sources for GAPIC generator config.
      srcDir 'src/main/proto'
    }
    java {
      // Include location where proto plugin puts generated sources.
      srcDir "${buildDir}/generated/source/proto/main/java"
    }
  }
}

protobuf {
  protoc {
    artifact = libraries.protoc
  }
}

// JavaDoc
// -------

task javadocJar(type: Jar) {
  classifier = 'javadoc'
  from javadoc
}

javadoc.options {
  encoding = 'UTF-8'
  links 'https://docs.oracle.com/javase/7/docs/api/'
}

// Test data
// ---------

sourceSets {
  test {
    resources {
      // Include all resources from testdata and testsrc folders.
      srcDir 'src/test/java'
      include '**/testdata/**'
      include '**/testsrc/**'
    }
    resources {
      // Include protos of core platform and toolkit,
      // as some tests depend on this.
      srcDir "${projectDir}/modules/googleapis"
      include '**/*.proto'
    }
  }
}

task setupProtocEnvironment {
  doLast {
    def protocPath = project.configurations.protobufToolsLocator_protoc.resolve().getAt(0)
    if (protocPath == null) {
      throw new RuntimeException("protoc path is null")
    }
    test.setEnvironment(PROTOC_COMPILER: protocPath)
  }
}

test.dependsOn setupProtocEnvironment

task showRuntimeClassPath {
  doLast {
    println 'output: ' + sourceSets.main.runtimeClasspath.asPath
  }
}

// Test Logging
// ============
test {
  testLogging {
      events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
  }
}

// Eclipse Annotation Processing
// -----------------------------

// TODO(wrwg): figure whether there is direct support for this in eclipse plugin,
// and use that instead.

ext {
  eclipseAptFolder = '.apt_generated'
  eclipseSettingsDir = file('.settings')
}

configurations {
  codeGeneration
}

dependencies {
  codeGeneration libraries.autovalue, libraries.jsr305
  compile libraries.autovalue, libraries.jsr305
}

compileJava.classpath += configurations.codeGeneration

eclipse {
  jdt.file.withProperties {
    it['org.eclipse.jdt.core.compiler.processAnnotations'] = 'enabled'
  }
}

tasks.eclipseJdt {
  doFirst {
    def aptPrefs =
        file("${eclipseSettingsDir}/org.eclipse.jdt.apt.core.prefs")
    aptPrefs.parentFile.mkdirs()

    aptPrefs.text = """\
        eclipse.preferences.version=1
        org.eclipse.jdt.apt.aptEnabled=true
        org.eclipse.jdt.apt.genSrcDir=${eclipseAptFolder}
        org.eclipse.jdt.apt.reconcileEnabled=true
        """.stripIndent()

    file('.factorypath').withWriter {
      new groovy.xml.MarkupBuilder(it).'factorypath' {
        project.configurations.codeGeneration.each { dep->
          factorypathentry(
            kind:'EXTJAR',
            id:dep.absolutePath,
            enabled:true,
            runInBatchMode:false)
        }
      }
    }
  }
}

tasks.cleanEclipseJdt {
  doFirst {
    delete file("${eclipseSettingsDir}/org.eclipse.jdt.apt.core.prefs"),
      file('.factorypath')
  }
}

artifacts {
  archives javadocJar, sourcesJar
}

signing {
  required { gradle.taskGraph.hasTask('uploadArchives') }
  sign configurations.archives
}

if (project.hasProperty('ossrhUsername') && project.hasProperty('ossrhPassword')) {
  uploadArchives {
    repositories {
      mavenDeployer {
        beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }

        repository(url: 'https://oss.sonatype.org/service/local/staging/deploy/maven2/') {
          authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        snapshotRepository(url: 'https://oss.sonatype.org/content/repositories/snapshots/') {
          authentication(userName: ossrhUsername, password: ossrhPassword)
        }

        pom.project {
          name 'Google API Codegen Toolkit'
          packaging 'jar'
          artifactId 'toolkit'
          description 'Google API Codegen Toolkit'
          url 'https://github.com/googleapis/toolkit'

          scm {
            url 'https://github.com/googleapis/toolkit'
            connection 'scm:git:https://github.com/googleapis/toolkit.git'
          }

          licenses {
            license {
              name 'The Apache License, Version 2.0'
              url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
            }
          }

          developers {
            developer {
              id 'GoogleAPIs'
              name 'GoogleAPIs'
              email 'googleapis@googlegroups.com'
              url 'https://github.com/googleapis'
              organization 'Google, Inc.'
              organizationUrl 'https://www.google.com'
            }
          }
        }
      }
    }
  }
} else {
  task failUploadArchives {
    doLast {
      throw new GradleException('uploadArchives needs ossrhUsername and ossrhPassword '
        + 'to be set. They can be set inside your ~/.gradle/gradle.properties file.')
    }
  }
  tasks.uploadArchives.dependsOn(failUploadArchives)
}

allprojects {
  gradle.projectsEvaluated {
    tasks.withType(JavaCompile) {
      options.compilerArgs << '-Xlint:unchecked'
    }
  }
}

task createProperties(dependsOn: processResources) {
  doLast{
    new File("$buildDir/resources/main/com/google/api/codegen/").mkdirs()
    Properties p = new Properties()
    p['version'] = project.version.toString()
    p.store(new PrintWriter("$buildDir/resources/main/com/google/api/codegen/codegen.properties", 'UTF-8'), null)
  }
  outputs.file("$buildDir/resources/main/com/google/api/codegen/codegen.properties")
}

classes {
  dependsOn createProperties
}

// Task to run CodeGeneratorTool
// =============================
//
// Command line args can be passed to the tool as a comma-separated list:
//   ./gradlew runCodeGen '-Pclargs=--arg1=val1,--arg2=val2,--arg3=val3'
task runCodeGen(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.CodeGeneratorTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

// Task to run SynchronizerTool
// =============================
//
// Command line args can be passed to the tool as a comma-separated list:
//   ./gradlew runSynchronizer '-Pclargs=--arg1=val1,--arg2=val2,--arg3=val3'
task runSynchronizer(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.SynchronizerTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

// Task to display the cache path of GRPC Java plugin
task showGrpcJavaPluginPath {
  doLast {
    DependencyResolver resolver = new DependencyResolver(project)
    println 'output: ' + resolver.resolveExecutable(
      'io.grpc:protoc-gen-grpc-java:1.2.0')
  }
}

// Task to display the cache path of protobuf
task showProtobufPath() {
  doLast {
    DependencyResolver resolver = new DependencyResolver(project)
    println 'output: ' + resolver.extractArchive(
      'com.google.protobuf:protobuf-java:' + protoVersion);
  }
}

// Task to display the cache path of Google Java formatter
task showJavaFormatterPath {
  doLast {
    DependencyResolver resolver = new DependencyResolver(project)
    println 'output: ' + resolver.locateArchive(
      'com.google.googlejavaformat:google-java-format:1.1:all-deps')
  }
}

// Task to run ConfigGeneratorTool
// =============================
//
// Command line args can be passed to the tool as a comma-separated list:
//   ./gradlew runConfigGen '-Pclargs=--arg1=val1,--arg2=val2,--arg3=val3'
task runConfigGen(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.configgen.ConfigGeneratorTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

// Task to run GrpcMetadataGeneratorTool
// =============================
//
// Command line args can be passed to the tool as a comma-separated list:
//   ./gradlew runGrpcMetadataGen '-Pclargs=--arg1=val1,--arg2=val2,--arg3=val3'
task runGrpcMetadataGen(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.grpcmetadatagen.GrpcMetadataGeneratorTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

// Task to run DiscoveryConfigGeneratorTool
// =================================================================
task runDiscoConfigGen(type: JavaExec) {
//
// Command line args can be passed to the tool as a comma-separated list:
//   ./gradlew runDiscoConfigGen '-Pclargs=--discovery_doc=../discoveries/compute.v1.json,-output=../gapic/google/compute/v1/compute_gapic.yaml'
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.configgen.DiscoConfigGeneratorTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

// Task to run DiscoveryFragmentGeneratorTool
// =================================================================
task runDiscoGen(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.DiscoveryFragmentGeneratorTool'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

task runDiscoBatch(type: JavaExec) {
  classpath = sourceSets.main.runtimeClasspath
  main = 'com.google.api.codegen.DiscoveryFragmentGeneratorBatch'
  if (project.hasProperty('clargs')) {
    args = clargs.split(',').toList()
  }
}

task verifyLicense {
  doLast {
    def licenseText = new File(rootProject.rootDir, 'license-header-javadoc.txt').text
    def srcFiles = []
    sourceSets
        .collectMany{it.allJava.getSrcDirs()}
        .each{it.eachFileRecurse(FileType.FILES, {srcFiles << new Tuple(it, it.text)})}
    srcFiles = srcFiles
        .findAll{!it.get(0).path.contains('/generated/') && it.get(0).path.endsWith('.java')}
        .collect{new Tuple(it.get(0), it.get(1).replaceAll("Copyright 20[0-9]{2}", 'Copyright 20xx'))}
        .findAll{!it.get(1).startsWith(licenseText)}
    if (srcFiles.asList().size() > 0) {
      srcFiles.each({println 'missing license: ' + it.get(0)})
      throw new IllegalStateException('Above files do not have licenses')
    }
  }
}

test.dependsOn verifyLicense

tasks.googleJavaFormat {
  exclude '.apt_generated/**'
  exclude 'bin/**'
  exclude 'build/**'
  exclude 'benchmark/**'
}
tasks.verifyGoogleJavaFormat {
  exclude '.apt_generated/**'
  exclude 'bin/**'
  exclude 'build/**'
  exclude 'benchmark/**'
}
test.dependsOn verifyGoogleJavaFormat
