import java.text.SimpleDateFormat

buildscript {
    repositories {
        jcenter()
        maven { url 'https://repo.spring.io/plugins-release' }
    }
    dependencies {
        classpath 'io.spring.gradle:propdeps-plugin:0.0.10.RELEASE'
        classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:4.9.9'
        classpath 'com.typesafe:config:1.3.4'
    }
}


plugins {
    id 'application'
    id 'jacoco'
    id 'com.github.kt3k.coveralls' version '2.8.4'
    id 'com.jfrog.bintray' version '1.8.4'
    id 'org.ajoberstar.grgit' version '3.1.1' apply false
}

apply plugin: 'propdeps-maven'
apply plugin: 'com.jfrog.artifactory'

sourceCompatibility = 1.8

mainClassName = 'org.ethereum.Start'
applicationDefaultJvmArgs = ["-server", "-Xss2m", "-Xmx2G", "-XX:-OmitStackTraceInFastThrow"]

if ( project.hasProperty('jvmArgs') ) {
    applicationDefaultJvmArgs = applicationDefaultJvmArgs + project.jvmArgs.split('\\s+').toList()
}
if (project.hasProperty("mainClass")) {
    mainClassName = mainClass
}


ext.generatedSrcDir = file('src/gen/java')

sourceSets.main.java.srcDirs += generatedSrcDir


tasks.withType(JavaCompile){
    options.warnings = false
}

task runRopsten (type: JavaExec) {
    main = mainClassName
    classpath = sourceSets.main.runtimeClasspath
    jvmArgs = applicationDefaultJvmArgs + '-Dethereumj.conf.res=ropsten.conf'
}

task runTest (type: JavaExec) {
    main = mainClassName
    classpath = sourceSets.main.runtimeClasspath
    jvmArgs = applicationDefaultJvmArgs + '-Dethereumj.conf.res=test.conf'
}

/**
 *  This is TCK test command line option,
 *  to run the test:
 *     gradle tckRun -PfilePath=[ file path]
 *      e.g: gradle tckRun -PfilePath=E:\temp\test-case.json
 */
task tckRun(type:JavaExec){

    if (project.hasProperty("filePath")) {
        args = ["filerun", "$filePath"]
        jvmArgs = ["-Xss4M"]
    }

    if (project.hasProperty("content")) {
        args = ["content", "$content"]
        jvmArgs = ["-Xss4M"]
    }

    main = "org.ethereum.tck.RunTck"
    classpath = sourceSets.test.runtimeClasspath
}

/**
 * Runs all tests
 * EthereumJ also runs common Ethereum clients tests
 * See {@link #prepareGithubTests()} if you want to use local repo
 * instead of downloading tests during test execution
 */
test {

    beforeTest { descriptor ->
        logger.lifecycle("Running test: ${descriptor}")
    }

    jvmArgs = ["-Xss8m", "-Xmx3G"]

    prepareGithubTests()
    // If Github tests directory is provided, it's passed to test runner
    if (System.getProperty("GitHubTests.testPath") != null) {
        jvmArgs.add('-DGitHubTests.testPath' + '=' + System.getProperty("GitHubTests.testPath"))
    }

    testLogging {
        events "failed"
        exceptionFormat "short"
    }

    systemProperties System.properties
    systemProperty "user.dir", workingDir
    systemProperty "file.encoding", "UTF-8"
}

ext {
    slf4jVersion = '1.7.7'
    leveldbVersion = '0.7'
    scastleVersion = '1.58.0.0'
    springVersion = '4.3.19.RELEASE'
    hibernateVersion = '4.3.7.Final'
    junitVersion = '4.11'
}

dependencies {
    compile "io.netty:netty-all:4.0.30.Final"
    compile "com.madgag.spongycastle:core:${scastleVersion}" // for SHA3 and SECP256K1
    compile "com.madgag.spongycastle:prov:${scastleVersion}" // for SHA3 and SECP256K1

    compile "org.iq80.leveldb:leveldb:${leveldbVersion}"     // Java API wrapper around native components

    compile "org.ethereum:leveldbjni-all:1.18.3"             // native leveldb components

    compile "org.ethereum:rocksdbjni:5.9.2"                   // RocksDB Java API

    compile "org.ethereum:solcJ-all:0.4.25"                  // Solidity Compiler win/mac/linux binaries

    compile "com.google.guava:guava:24.1-jre"

    compile "com.cedarsoftware:java-util:1.8.0" // for deep equals
    compile "org.slf4j:slf4j-api:${slf4jVersion}"
    compile "ch.qos.logback:logback-classic:1.1.7"
    compile "com.fasterxml.jackson.core:jackson-databind:2.5.1"
    compile "org.apache.commons:commons-collections4:4.0"
    compile "org.apache.commons:commons-lang3:3.4"
    compile "commons-codec:commons-codec:1.10"
    compile "org.springframework:spring-context:${springVersion}"
    compile "com.typesafe:config:1.2.1"
    compile "com.googlecode.concurrent-locks:concurrent-locks:1.0.0"

    compile("com.googlecode.json-simple:json-simple:1.1.1") {
        exclude group: 'junit', module: 'junit'
    }

    compile "org.xerial.snappy:snappy-java:1.1.4" // Snappy compression

    // used to hide spring initialization logs messages in samples
    optional "org.slf4j:jcl-over-slf4j:${slf4jVersion}"

    testCompile "junit:junit:${junitVersion}"
    testCompile "org.springframework:spring-test:${springVersion}"
    testCompile "org.mockito:mockito-core:2.+"
    testCompile "com.github.briandilley.jsonrpc4j:jsonrpc4j:1.1"
}


javadoc {
    options.author = true
    options.header = project.name
    options.addStringOption('-quiet')
    options.encoding = "UTF-8"
    options.links(
            "https://docs.oracle.com/javase/8/docs/api/",
            "https://netty.io/4.0/api/"
    )
}

//create a single Jar with all dependencies
task fatJar(type: Jar) {
    classifier = 'all'
    manifest {
        attributes 'Main-Class' : mainClassName
        attributes 'Class-Path' : configurations.compile.collect { 'lib/' + it.getName() }.join(' ')
    }
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

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

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

artifacts {
    archives sourcesJar
    archives javadocJar
}

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

def bintrayUsername = project.hasProperty('bintrayUser') ? project.bintrayUser : ''
def bintrayPassword = project.hasProperty('bintrayKey') ? project.bintrayKey : ''
def pullRequest = System.getenv('TRAVIS_PULL_REQUEST')
def branchName = System.getenv('TRAVIS_BRANCH')

artifactory {
    contextUrl = 'https://oss.jfrog.org/artifactory'
    publish {
        repository {
            repoKey = 'oss-snapshot-local'
            username = bintrayUsername
            password = bintrayPassword
        }
    }
    resolve {
        repository {
            repoKey = 'libs-release'
        }
    }

}

artifactoryPublish.onlyIf {
    (branchName != null) &&
            (!pullRequest || pullRequest == 'false') &&
            project.version.endsWith('-SNAPSHOT') &&
            (branchName.startsWith('master') ||
                    branchName.startsWith('develop') ||
                    branchName.startsWith('stage'))
}

bintray {
    user = bintrayUsername
    key = bintrayPassword

    configurations = ['archives']

    dryRun = false //Whether to run this as dry-run, without deploying
    publish = true //If version should be auto published after an upload
    pkg {
        userOrg = 'ethereum' //An optional organization name when the repo belongs to one of the user's orgs
        repo = 'maven'
        name = 'org.ethereum'
    }
}

bintrayUpload.onlyIf {
    // comment 'false' and uncomment the next line to publish next release
    (!pullRequest || pullRequest == 'false') && !project.version.endsWith('-SNAPSHOT')
//     false
}

install {
    repositories.mavenInstaller {
        customizePom(pom, project)
    }
}

tasks.processResources.doLast(){
    println 'This will be printed after the build task even if something else calls the build task'

    File versionfile = file(new File('build/resources/main/build-info.properties'))
    versionfile.text = 'build.hash=' + gitCommitHash() + '\n' + 'build.time=' + buildTime() + '\n' + 'build.branch=' + gitCurBranch() + '\n'
}

task publish {

    println "publishing if master || develop current branch: " + branchName
    description = "Publishes snapshots to oss.jfrog.org and releases to Bintray/JCenter"
    dependsOn artifactoryPublish, bintrayUpload
}


def customizePom(pom, gradleProject) {
    pom.whenConfigured { generatedPom ->
        // eliminate test-scoped dependencies (no need in maven central poms)
        generatedPom.dependencies.removeAll { dep ->
            dep.scope == "test"
        }

        // sort to make pom dependencies order consistent to ease comparison of older poms
        generatedPom.dependencies = generatedPom.dependencies.sort { dep ->
            "$dep.scope:$dep.groupId:$dep.artifactId"
        }

        // add all items necessary for maven central publication
        generatedPom.project {
            name = "ethereumj"
            description = "Java implementation of the Ethereum protocol"
            url = "https://github.com/ethereum/ethereumj"
            organization {
                name = "Ethereum"
                url = "https://ethereum.org"
            }
            licenses {
                license {
                    name "GNU Lesser General Public License v3.0"
                    url "https://www.gnu.org/licenses/lgpl-3.0.en.html"
                    distribution "repo"
                }
            }
            scm {
                url = "https://github.com/ethereum/ethereumj"
                connection = "scm:git:git://github.com/ethereum/ethereumj"
                developerConnection = "scm:git:git://github.com/ethereum/ethereumj"
            }
            developers {
                developer {
                    id = "rmandeleil"
                    name = "Roman Mandeleil"
                    email = "roman.mandeleil@gmail.com"
                }

                developer {
                    id = "Nashatyrev"
                    name = "Anton Nashatyrev"
                    email = "Anton.nashatyrev@gmail.com"
                }

                developer {
                    id = "zilm13"
                    name = "Dmitry Shmatko"
                    email = "zilm@zilm.net"
                }

                developer {
                    id = "mkalinin"
                    name = "Mikhail Kalinin"
                    email = "noblesse.knight@gmail.com"
                }
            }
            issueManagement {
                system = "GitHub Issues"
                url = "https://github.com/ethereum/ethereumj/issues"
            }
        }
    }
}


 def gitCommitHash() {
    def process = "git rev-parse --short HEAD".execute()
    return process.text.trim()
 }

def buildTime() {
    def df = new SimpleDateFormat("[dd/MMM/yyyy]-[HH:mm]")
    df.setTimeZone(TimeZone.getTimeZone("GMT"));
    return '[GMT]-' + df.format(new Date())
}

def gitCurBranch() {
    def branchName = System.getenv('TRAVIS_BRANCH')
    if (branchName) return branchName
    def process = "git rev-parse --abbrev-ref HEAD".execute()
    return process.text.trim()
}

/**
 * This method is used to prepare local Ethereum Github tests for EthereumJ tests
 *
 * These tests  are designed for all Ethereum clients and
 * maintained by Ethereum Foundation/Community.
 * EthereumJ executes all of them but by default downloads every
 * single file using internet connection.
 * Alternatively you could use local repo to run tests from it.
 *
 * Common usage:
 * 1) Local run:
 *  a. Clone Ethereum tests repo (https://github.com/ethereum/tests)
 *    to some local directory
 *  b. Create `test-user.conf` file in test resources directory.
 *    This file is under `.gitignore`, so it's your local file only.
 *    You could override any EthereumJ configuration in it, but
 *    for using local Ethereum tests repo you need following line:
 *    GitHubTests.testPath=/some/path/with/Ethereum/tests/repo
 *  c. Run `./gradlew test` task.
 * 2) CI run:
 *  a. Clone Ethereum tests repo (https://github.com/ethereum/tests)
 *    to some local directory
 *  b. Run `test` task with following parameter:
 *    -DGitHubTests.testPath=/some/path/with/Ethereum/tests/repo
 *
 * In both cases this method will get commit hash from
 * `src/test/resources/github-tests.prop` and checkout local repo
 * to specific commit. So, EthereumJ tests will run common
 * Ethereum client tests using local copy of repository.
 *
 * Repo with tests is changed often and EthereumJ is guaranteed
 * to pass only tests from specific commit.
 */
import org.ajoberstar.grgit.Grgit
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
def prepareGithubTests() {
    String testsPathKey = "GitHubTests.testPath"
    String testsCommitKey = "GitHubTests.commit"
    String testUserConf = "ethereumj-core/src/test/resources/test-user.conf"
    String githubTestsProp = "ethereumj-core/src/test/resources/github-tests.prop"
    def repoPath = System.getProperty(testsPathKey)
    if (repoPath == null) {
        try {
            Config userTest = ConfigFactory.parseFile(new File(testUserConf))
            repoPath = userTest.getString(testsPathKey)
        } catch (Exception ex) {}
    }
    if (repoPath == null) return
    def commit = System.getProperty(testsCommitKey)
    if (commit == null) {
        Properties testProp = new Properties();
        testProp.load(new File(githubTestsProp).newDataInputStream());
        commit = testProp.getProperty(testsCommitKey)
    }
    if (repoPath != null && commit != null) {
        println "Tests: Checking out Ethereum Tests repo at " + repoPath + " to commit #" + commit
        try {
            def testsRepo = Grgit.open(dir: repoPath)
            testsRepo.fetch()
            testsRepo.checkout(branch: commit)
        } catch (Exception ex) {
            println "Error occurs while trying to checkout local Ethereum tests repo to specific commit"
            println "Either remove " + testsPathKey + " property to use remote repo in tests or fix the issue"
            println "Error: "
            println ex
            throw ex
        }
    }
}
