def excludes = [
// dependency injection graph
'**/*Module.*',
'**/*Module*.*',

// Framework entry points
'**/*Activity*',
'**/*Fragment*',
'**/*Application*',
'**/*AndroidService*',

// We would like to exclude android widgets as well but our naming is inconsistent

// Proof of concept
'**/*Login2*',

// Generated
'**/*JsonAdapter*',
'**/*Item.*',
'**/*$Holder.*',
'**/*ViewHolder.*',
'**/*View.*',
'**/*BottomSheet.*'
]

def initializeReport(report, projects, classExcludes) {
    projects.each { project -> project.apply plugin: 'jacoco' }

    report.executionData {
        fileTree(rootProject.rootDir.absolutePath).include(
                "**/build/**/*.exec",
                "**/build/outputs/code_coverage/**/coverage.ec",
        )
    }
    report.reports {
        xml.required = true
        html.required = true
        csv.required = false
    }

    gradle.projectsEvaluated {
        def androidSourceDirs = []
        def androidClassDirs = []

        projects.each { project ->
            switch (project) {
                case { project.plugins.hasPlugin("com.android.application") }:
                    androidClassDirs.add("${project.buildDir}/tmp/kotlin-classes/gplayDebug")
                    androidSourceDirs.add("${project.projectDir}/src/main/kotlin")
                    androidSourceDirs.add("${project.projectDir}/src/main/java")
                    break
                case { project.plugins.hasPlugin("com.android.library") }:
                    androidClassDirs.add("${project.buildDir}/tmp/kotlin-classes/debug")
                    androidSourceDirs.add("${project.projectDir}/src/main/kotlin")
                    androidSourceDirs.add("${project.projectDir}/src/main/java")
                    break
                default:
                    report.sourceSets project.sourceSets.main
            }
        }

        report.sourceDirectories.setFrom(report.sourceDirectories + files(androidSourceDirs))
        def classFiles = androidClassDirs.collect { files(it).files }.flatten()
        report.classDirectories.setFrom(files((report.classDirectories.files + classFiles).collect {
            fileTree(dir: it, excludes: classExcludes)
        }))
    }
}

def collectProjects(predicate) {
    return subprojects.findAll { it.buildFile.isFile() && predicate(it) }
}

task generateCoverageReport(type: JacocoReport) {
    outputs.upToDateWhen { false }
    rootProject.apply plugin: 'jacoco'
    def projects = collectProjects { ['vector-app', 'vector', 'matrix-sdk-android'].contains(it.name) }
    initializeReport(it, projects, excludes)
}

task unitTestsWithCoverage(type: GradleBuild) {
    // the 7.1.3 android gradle plugin has a bug where enableTestCoverage generates invalid coverage
    startParameter.projectProperties.coverage = "false"
    tasks = ['testDebugUnitTest']
}

task instrumentationTestsWithCoverage(type: GradleBuild) {
    startParameter.projectProperties.coverage = "true"
    startParameter.projectProperties['android.testInstrumentationRunnerArguments.notPackage'] = 'im.vector.app.ui'
    tasks = [':vector-app:connectedGplayDebugAndroidTest', ':vector:connectedDebugAndroidTest', 'matrix-sdk-android:connectedDebugAndroidTest']
}
