import org.apache.ivy.plugins.resolver.FileSystemResolver

group = 'sealife'

project(':atlantic') {
    apply plugin: 'java'
    configurations {
        other
    }
    dependencies {
        other "sea.fish:herring:1.0", files("$rootDir/lib/selfResolving1.jar")
    }
}

project(':northSea') {
    apply plugin: 'java'
    configurations {
        other
    }
    dependencies {
        other "sea.fish:squid:1.0", files("$rootDir/lib/selfResolving2.jar"), project(path: ':atlantic', configuration: 'other')
    }
}

repositories {
    add(new FileSystemResolver()) {
        name = "repo"
        addArtifactPattern("$rootDir/repo/[organization]/[module]-[revision].[ext]")
        addIvyPattern("$rootDir/repo/[organization]/ivy-[module]-[revision].xml")
        checkmodified = true
    }
}

configurations {
    oneDepWithNoTransitives
    oneDepWithTransitives
    twoDepsWithNoTransitives
    twoDepsWithTransitives
    twoDepsWithOneAsTransitive
    twoDepsWithVersionConflicts
    twoDepsWithDifferentDependencyConfigurations
    depWithMultipleConfigurations
    extended
    extending.extendsFrom extended
    extendingWithDifferentConfiguration.extendsFrom extended
    selfResolving
    mixed.extendsFrom selfResolving, twoDepsWithTransitives
    subprojectAtlantic
    subprojectNorthSea
    classifier
    extendingClassifier.extendsFrom classifier
    customArtifacts
}

dependencies {
    oneDepWithNoTransitives "sea.fish:herring:1.0"
    oneDepWithTransitives "sea.fish:tuna:1.0"
    twoDepsWithNoTransitives "sea.fish:herring:1.0", "sea.mammals:seal:1.0"
    twoDepsWithTransitives "sea.mammals:orca:1.0", "sea.fish:tuna:1.0"
    twoDepsWithOneAsTransitive "sea.fish:shark:1.0", "sea.fish:tuna:1.0"
    twoDepsWithVersionConflicts "sea.fish:shark:1.0", "sea.mammals:orca:1.0"
    twoDepsWithDifferentDependencyConfigurations "sea.fish:shark:1.0", "sea.fish:billfish:1.0"
    depWithMultipleConfigurations group: 'sea.fish', name: 'tuna', version: '1.0', configuration: 'default'
    depWithMultipleConfigurations group: 'sea.fish', name: 'tuna', version: '1.0', configuration: 'specialWaters'
    extended "sea.fish:tuna:1.0"
    extending "sea.mammals:orca:1.0"
    extendingWithDifferentConfiguration group: 'sea.fish', name: 'tuna', version: '1.0', configuration: 'specialWaters'
    extendingWithDifferentConfiguration "sea.mammals:seal:1.0"
    selfResolving files("$rootDir/lib/selfResolving1.jar"), files("$projectDir/someDir")
    subprojectAtlantic project(path: ':atlantic', configuration: 'other')
    subprojectNorthSea project(path: ':northSea', configuration: 'other')
    classifier "sea.fish:herring:1.0"
    classifier('sea.mammals:dolphin:1.0') {
	    artifact {
	        name = 'dolphin'
	        type = 'jar'
	        extension = 'jar'
	        classifier = 'oceanic'
        }
        artifact {
	        name = 'dolphin'
	        type = 'jar'
	        extension = 'jar'
	        classifier = 'river'
        }
	}
    // A resolve should return both, tuna and custom-tuna. A files filtering on shark or tuna either or.
    // But Ivy does not return the correct resolve report. In fact if you produce an equivalent ivy.xml, only custom-tuna is returned, not tuna-1.0.jar.
    // Therefore we don't test the resolve of customArtifacts
    customArtifacts "sea.fish:shark:1.0"
    customArtifacts("sea.fish:tuna:1.0") {
        artifact {
	        name = 'custom-tuna'
	        type = 'jar'
	        extension = 'jar'
            url = "file:///$rootDir/lib/selfResolving1.jar"
        }
    }

}

task test(dependsOn: [configurations.subprojectAtlantic, configurations.subprojectNorthSea]) << {
    assertCorrectFilesForCompleteConfigurations()
    assertFilesForDependencySubsets()
    assertFilesForConfigurationCopies()
}

def assertCorrectFilesForCompleteConfigurations() {
    expectedResults = [
            oneDepWithNoTransitives: ['herring-1.0.jar'] as Set,
            oneDepWithTransitives: ['tuna-1.0.jar', 'herring-1.0.jar'] as Set,
            twoDepsWithNoTransitives: ['seal-1.0.jar', 'herring-1.0.jar'] as Set,
            twoDepsWithTransitives: ['tuna-1.0.jar', 'orca-1.0.jar', 'seal-1.0.jar', 'herring-1.0.jar'] as Set,
            twoDepsWithOneAsTransitive: ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'herring-1.0.jar'] as Set,
            twoDepsWithVersionConflicts: ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'orca-1.0.jar', 'herring-1.0.jar'] as Set,
            twoDepsWithDifferentDependencyConfigurations: ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'billfish-1.0.jar', 'herring-1.0.jar', 'squid-1.0.jar'] as Set,
            depWithMultipleConfigurations: ['tuna-1.0.jar', 'herring-1.0.jar', 'squid-1.0.jar'] as Set,
            extendingWithDifferentConfiguration: ['tuna-1.0.jar', 'herring-1.0.jar', 'squid-1.0.jar', 'seal-1.0.jar'] as Set,
            extending: ['tuna-1.0.jar', 'herring-1.0.jar', 'seal-1.0.jar', 'orca-1.0.jar'] as Set,
            selfResolving: ['selfResolving1.jar', 'someDir'] as Set,
            mixed: ['tuna-1.0.jar', 'orca-1.0.jar', 'seal-1.0.jar', 'herring-1.0.jar', 'selfResolving1.jar', 'someDir'] as Set,
            subprojectAtlantic: ['selfResolving1.jar', 'herring-1.0.jar'] as Set,
            subprojectNorthSea: ['selfResolving1.jar', 'herring-1.0.jar', 'selfResolving2.jar', 'squid-1.0.jar'] as Set,
            classifier: ['dolphin-1.0-oceanic.jar', 'dolphin-1.0-river.jar', "herring-1.0.jar"] as Set,
            extendingClassifier: ['dolphin-1.0-oceanic.jar', 'dolphin-1.0-river.jar', "herring-1.0.jar"] as Set
    ]
    expectedResults.each { configurationName, expectedFileNames ->
        Set resolvedFileNames = configurations[configurationName].files.collect { it.name }
        assert expectedFileNames == resolvedFileNames
    }
}

def assertFilesForDependencySubsets() {
    assertSubsetFiles(configurations.oneDepWithNoTransitives, { dep -> dep.name == 'herring' }, ['herring-1.0.jar'])
    assertSubsetFiles(configurations.oneDepWithTransitives, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithNoTransitives, { dep -> dep.name == 'herring' }, ['herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithTransitives, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithOneAsTransitive, { dep -> dep.name == 'shark' }, ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithOneAsTransitive, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithVersionConflicts, { dep -> dep.name == 'shark' }, ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithVersionConflicts, { dep -> dep.name == 'orca' }, ['orca-1.0.jar', 'seal-2.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithDifferentDependencyConfigurations, { dep -> dep.name == 'shark' }, ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.twoDepsWithDifferentDependencyConfigurations, { dep -> dep.name == 'billfish' }, ['tuna-1.0.jar', 'billfish-1.0.jar', 'squid-1.0.jar'])
    assertSubsetFiles(configurations.depWithMultipleConfigurations, { dep -> dep.configuration == 'default' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.extendingWithDifferentConfiguration, { dep -> dep.name != 'seal' }, ['tuna-1.0.jar', 'herring-1.0.jar', 'squid-1.0.jar'])
    assertSubsetFiles(configurations.extendingWithDifferentConfiguration, { dep -> dep.name == 'tuna' && dep.configuration == 'default' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.extending, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.selfResolving, { dep -> dep.source.singleFile.name == 'someDir' }, ['someDir'])
    assertSubsetFiles(configurations.mixed, { dep ->
        dep instanceof org.gradle.api.artifacts.SelfResolvingDependency || dep.name == 'tuna' }, ['someDir', 'selfResolving1.jar', 'tuna-1.0.jar', 'herring-1.0.jar'])
    assertSubsetFiles(configurations.classifier, { dep -> dep.name == 'dolphin' }, ['dolphin-1.0-oceanic.jar', 'dolphin-1.0-river.jar'])
    assertSubsetFiles(configurations.extendingClassifier, { dep -> dep.name == 'dolphin' }, ['dolphin-1.0-oceanic.jar', 'dolphin-1.0-river.jar'])
}

def assertSubsetFiles(configuration, spec, expectedFileNames) {
    Set resolvedFileNames = configuration.files(spec).collect { it.name }
    assert expectedFileNames as Set == resolvedFileNames
}

def assertFilesForConfigurationCopies() {
    assertConfigurationCopyFiles(configurations.oneDepWithNoTransitives, { dep -> true }, ['herring-1.0.jar'])
    assertConfigurationCopyFiles(configurations.oneDepWithTransitives, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'])
    assertConfigurationCopyFiles(configurations.twoDepsWithVersionConflicts, { dep -> dep.name == 'shark' }, ['tuna-1.0.jar', 'shark-1.0.jar', 'seal-2.0.jar', 'herring-1.0.jar'])
    assertConfigurationCopyFiles(configurations.twoDepsWithVersionConflicts, { dep -> dep.name == 'orca' }, ['orca-1.0.jar', 'seal-1.0.jar'])
    assertConfigurationCopyFiles(configurations.extending, { dep -> true }, ['seal-1.0.jar', 'orca-1.0.jar'])
    assertConfigurationCopyFiles(configurations.extending, { dep -> dep.name == 'tuna' }, ['tuna-1.0.jar', 'herring-1.0.jar'], true)
    assertConfigurationCopyFiles(configurations.selfResolving, { dep -> true }, ['selfResolving1.jar', 'someDir'])
    assertConfigurationCopyFiles(configurations.selfResolving, { dep -> dep.source.singleFile.name == 'someDir' }, ['someDir'])
    assertConfigurationCopyFiles(configurations.mixed, { dep ->
        dep instanceof org.gradle.api.artifacts.SelfResolvingDependency || dep.name == 'tuna' }, ['someDir', 'selfResolving1.jar', 'tuna-1.0.jar', 'herring-1.0.jar'], true)
}

def assertConfigurationCopyFiles(configuration, spec, expectedFileNames, recursive = false) {
    String method = recursive ? 'copyRecursive' : 'copy'
    Set resolvedFileNames = configuration."$method"(spec).collect { it.name }
    assert expectedFileNames as Set == resolvedFileNames
}
