class GraphProject {
    def projects, project, nodeName, safeName
    GraphProject(projects, project) {
        def path = project.path.split(':').findAll { it }
        if (!path) path.add project.rootProject.name
        path = path.collect { it.split('[/\\\\]')[-1] }
        nodeName = path.join(':')
        safeName = path.join('_')
        this.projects = projects
        this.project = project
    }
    def getCompileDeps() {
        ['implementation', 'cordaCompile'].collect {
            try {
                project.configurations[it].dependencies.matching { it in ProjectDependency }.collect { projects[it.dependencyProject] }
            } catch (org.gradle.api.artifacts.UnknownConfigurationException e) {
                [] // The project doesn't have a cordaCompile configuration, so there aren't any cordaCompile dependencies.
            }
        }.flatten()
    }
}

class Graph {
    def arcs = new LinkedHashSet()
    def dotFile, imgFile, project
    Graph(graphsDir, project) {
        initArcs(project)
        dotFile = new File(graphsDir, "${project.safeName}.dot")
        imgFile = new File(graphsDir, "${project.safeName}.png")
        this.project = project
    }
    def initArcs(project) {
        project.compileDeps.each {
            arcs.add([project, it])
            initArcs(it)
        }
    }
    def output() {
        dotFile.text = ''
        dotFile << "digraph \"$project.nodeName\" {\n"
        dotFile << '    rankdir=LR;\n'
        arcs.collect { it.collect { it.nodeName } }.each {
            dotFile << "    \"${it[0]}\" -> \"${it[1]}\";\n"
        }
        dotFile << '}\n'
        project.project.exec {
            commandLine 'dot', '-Tpng', '-o', imgFile, dotFile
        }
    }
}

def walkProjects(project, block) {
    block(project)
    project.childProjects.each { walkProjects(it.value, block) }
}

task graphs {
    doLast {
        def projects = new LinkedHashMap()
        walkProjects(rootProject) { projects[it] = new GraphProject(projects, it) }
        def graphsDir = reporting.baseDir
        graphsDir.mkdirs()
        def graphs = projects.collect { new Graph(graphsDir, it.value) }
        graphs.each { graph ->
            if (!graph.arcs) {
                logger.info "$graph.project.nodeName is a leaf."
                return
            }
            for (def that : graphs) {
                if (that != graph && that.arcs + graph.arcs == that.arcs) {
                    logger.info "$graph.project.nodeName is included in: $that.imgFile"
                    return
                }
            }
            graph.output()
        }
        exec {
            commandLine 'eog', graphsDir
        }
    }
}

jar {
    manifest {
        attributes(
                'Automatic-Module-Name': 'net.corda.tools.graphs'
        )
    }
}
