/*
 * Copyright 2018 ConsenSys AG.
 *
 * Licensed 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.
 */

apply plugin: 'java-library'

jar {
  baseName 'pantheon-core'
  manifest {
    attributes(
      'Specification-Title': baseName,
      'Specification-Version': project.version,
      'Implementation-Title': baseName,
      'Implementation-Version': calculateVersion()
      )
  }
}

dependencies {
  implementation project(':config')
  implementation project(':crypto')
  implementation project(':enclave')
  implementation project(':ethereum:rlp')
  implementation project(':ethereum:trie')
  implementation project(':metrics:core')
  implementation project(':services:kvstore')

  implementation 'com.fasterxml.jackson.core:jackson-databind'
  implementation 'com.google.guava:guava'
  implementation 'io.vertx:vertx-core'
  implementation 'org.apache.logging.log4j:log4j-api'

  runtime 'org.apache.logging.log4j:log4j-core'

  testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
  testImplementation project(path:':ethereum:referencetests', configuration: 'testOutput')
  testImplementation project(':testutil')

  testImplementation 'junit:junit'
  testImplementation 'org.assertj:assertj-core'
  testImplementation 'org.mockito:mockito-core'

  integrationTestImplementation project(path: ':config', configuration: 'testSupportArtifacts')

  integrationTestImplementation 'junit:junit'
  integrationTestImplementation 'org.assertj:assertj-core'
  integrationTestImplementation 'org.mockito:mockito-core'
  integrationTestImplementation project(':testutil')
  integrationTestImplementation 'net.consensys:orion'

  testSupportImplementation project(path: ':config', configuration: 'testSupportArtifacts')
  testSupportImplementation project(':testutil')

  testSupportImplementation 'junit:junit'
  testSupportImplementation 'org.assertj:assertj-core'
  testSupportImplementation 'org.mockito:mockito-core'

  compileOnly 'org.openjdk.jmh:jmh-generator-annprocess'

  jmhImplementation project(path: ':config', configuration: 'testSupportArtifacts')
  jmhImplementation project(':crypto')
  jmhImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
  jmhImplementation project(':ethereum:rlp')
  jmhImplementation project(':ethereum:trie')
  jmhImplementation project(':metrics:core')
  jmhImplementation project(':services:kvstore')
  jmhImplementation project(':util')

  jmhImplementation 'com.google.guava:guava'
}

configurations { testArtifacts }
task testJar (type: Jar) {
  baseName = "${project.name}-test"
  from sourceSets.test.output
}

test {
  exclude 'tech/pegasys/pantheon/ethereum/vm/**ReferenceTest.class'
  exclude 'tech/pegasys/pantheon/ethereum/vm/blockchain/**.class'
  exclude 'tech/pegasys/pantheon/ethereum/vm/generalstate/**.class'
  exclude 'tech/pegasys/pantheon/ethereum/core/TransactionTest.class'
}

def generateTestFiles(FileTree jsonPath, File templateFile, String pathstrip, String destination, String namePrefix) {
  def referenceTestTemplate = templateFile.text

  // This is how many json files to include in each test file
  def fileSets = jsonPath.getFiles().collate(5)

  fileSets.eachWithIndex { fileSet, idx ->
    def paths = []
    fileSet.each { testJsonFile ->
      if (!testJsonFile.getName().toString().startsWith(".")) {
        String parentDirectory = testJsonFile.getParentFile().getName()
        String testFile = testJsonFile.getName()
        if(testJsonFile.getParentFile().getParentFile().getName() != pathstrip) {
          paths << pathstrip + "/" + testJsonFile.getParentFile().getParentFile().getName() + "/" + parentDirectory + "/" + testFile
        } else {
          paths << pathstrip + "/" + parentDirectory + "/" + testFile
        }
      }
    }

    def testFile = file(destination + "/" + namePrefix + "_" + idx + ".java")

    def allPaths = '"' + paths.join('", "') + '"'

    def testFileContents = referenceTestTemplate
      .replaceAll("%%TESTS_FILE%%", allPaths)
      .replaceAll("%%TESTS_NAME%%", namePrefix + "_" + idx)
    testFile.newWriter().withWriter { w -> w << testFileContents }
  }
}

task blockchainReferenceTestsSetup {
  generateTestFiles(
    fileTree('../referencetests/src/test/resources/BlockchainTests'),
    file("./src/test/resources/tech/pegasys/pantheon/ethereum/vm/BlockchainReferenceTest.java.template"),
    "BlockchainTests",
    "./src/test/java/tech/pegasys/pantheon/ethereum/vm/blockchain",
    "BlockchainReferenceTest"
    )
}

task generalstateReferenceTestsSetup {
  generateTestFiles(
    fileTree("../referencetests/src/test/resources/GeneralStateTests"),
    file("./src/test/resources/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTest.java.template"),
    "GeneralStateTests",
    "./src/test/java/tech/pegasys/pantheon/ethereum/vm/generalstate",
    "GeneralStateReferenceTest"
    )
}

task generalstateRegressionReferenceTestsSetup {
  generateTestFiles(
    fileTree("./src/test/resources/regressions/generalstate"),
    file("./src/test/resources/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTest.java.template"),
    "regressions",
    "./src/test/java/tech/pegasys/pantheon/ethereum/vm/generalstate",
    "GeneralStateRegressionReferenceTest"
    )
}

task cleanupReferenceTests(type: Delete) {
  delete fileTree("./src/test/java/tech/pegasys/pantheon/ethereum/vm/generalstate/") {
    include("**/GeneralStateReferenceTest*.java")
    include("**/GeneralStateRegressionReferenceTest*.java")
  }
  delete fileTree("./src/test/java/tech/pegasys/pantheon/ethereum/vm/blockchain/") { include("**/BlockchainReferenceTest*.java") }
}

clean.dependsOn(cleanupReferenceTests)

task referenceTests(type: Test, dependsOn: [
  "blockchainReferenceTestsSetup",
  "generalstateReferenceTestsSetup",
  "generalstateRegressionReferenceTestsSetup",
  "compileTestJava"
]) {
  compileTestJava.mustRunAfter blockchainReferenceTestsSetup
  compileTestJava.mustRunAfter generalstateReferenceTestsSetup
  compileTestJava.mustRunAfter generalstateRegressionReferenceTestsSetup
  doFirst {
    if (!file("../referencetests/src/test/resources/README.md").exists()) {
      throw new GradleException("ethereum/referencetests/src/test/resources/README.md missing: please clone submodules (git submodule update --init --recursive)")
    }
  }
  scanForTestClasses = false
  enableAssertions = true
  include 'tech/pegasys/pantheon/ethereum/vm/**ReferenceTest.class'
  include 'tech/pegasys/pantheon/ethereum/vm/blockchain/**.class'
  include 'tech/pegasys/pantheon/ethereum/vm/generalstate/**.class'
  include 'tech/pegasys/pantheon/ethereum/core/TransactionTest.class'
}

artifacts {
  testArtifacts testJar
  testSupportArtifacts testSupportJar
}
