/*
* Copyright 2013 The Android Open Source Project
*
* 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.
*/

// The SampleGenPlugin source is in the buildSrc directory.
import com.example.android.samples.build.SampleGenPlugin
apply plugin: SampleGenPlugin

// Add a preflight task that depends on the "refresh" task that gets
// added by the SampleGenPlugin.
task preflight {
    project.afterEvaluate({preflight.dependsOn(project.refresh)})
}

String outPath(String buildType) {
/*
    def repoInfo = "repo info platform/developers/build".execute().text
    def buildPath = (repoInfo =~ /Mount path: (.*)/)[0][1]
*/
    return "${samplegen.pathToBuild}/out/${buildType}/${samplegen.targetSampleName()}";
}

/**
 * Collapse a path "IntelliJ-style" by putting dots rather than slashes between
 * path components that have only one child. So the two paths
 *
 * com/example/android/foo/bar.java
 * com/example/android/bar/foo.java
 *
 * Become
 * com.example.android/foo/bar.java
 * com.example.android/bar/foo.java
 *
 * @param path
 * @param roots
 * @return
 */
Map<String,String> collapsePaths(FileTree path, List<String> roots) {
    Map result = new HashMap<String,String>();

    println ("******************** Collapse *************************")

    path.visit { FileVisitDetails f ->
        if (f.isDirectory()) return;
        StringBuilder collapsedPath = new StringBuilder("${f.name}");
        File current = f.file;

        //
        // Starting at this file, walk back to the root of the path and
        // substitute dots for any directory that has only one child.
        //

        // Don't substitute a dot for the separator between the end of the
        // path and the filename, even if there's only one file in the directory.
        if (!f.isDirectory()) {
            current = current.parentFile;
            collapsedPath.insert(0, "${current.name}/")
        }

        // For everything else, use a dot if there's only one child and
        // a slash otherwise. Filter out the root paths, too--we only want
        // the relative path. But wait, Groovy/Gradle is capricious and
        // won't return the proper value from a call to roots.contains(String)!
        // I'm using roots.sum here instead of tracking down why a list of
        // strings can't return true from contains() when given a string that
        // it quite obviously does contain.
        current = current.parentFile;
        while((current != null)
                && (roots.sum {String r-> return r.equals(current.absolutePath) ? 1 : 0 } == 0)) {

            char separator = current.list().length > 1 ? '/' : '.';
            collapsedPath.insert(0, "${current.name}${separator}");
            current = current.parentFile;
        }
        result.put(f.file.path, collapsedPath.toString());
    }

    println ("******************** Collapse results *********************")

    result.each {entry -> println("- ${entry}");}
    return result
}


task emitAnt(type:Copy) {
    def outputPath = outPath("ant");
    def inputPath = "${project.projectDir}/${samplegen.targetSampleModule()}"
    into outputPath
    includeEmptyDirs
    ["main", "common", "template"].each { input ->
        [[ "java", "src"], ["res", "res"]].each { filetype ->
            def srcPath = "${inputPath}/src/${input}/${filetype[0]}"
            into("${filetype[1]}") {
                from(srcPath)
            }
        }
    }
    from("${inputPath}/src/main") { include "AndroidManifest.xml" }
    from("${inputPath}/src/template") { include "project.properties" }
}

task emitGradle(type:Copy) {
    dependsOn(preflight)
    def outputPath = outPath("gradle")
    def inputPath = "${project.projectDir}"
    // Copy entire sample into output -- since it's already in Gradle format, we'll explicitly exclude content that
    // doesn't belong here.
    into outputPath
    from("${inputPath}") {
        // Paths to exclude from output
        exclude ".gradle"
        exclude "_index.jd"
        exclude "bin"
        exclude "buildSrc"
        exclude "local.properties"
        exclude "template-params.xml"
        exclude "*.iml"
        exclude "**/.idea"
        exclude "**/build"
        exclude "**/proguard-project.txt"
        exclude "${samplegen.targetSampleModule()}/**/README*.txt"
        exclude "**/README-*.txt"

        // src directory needs to be consolidated, will be done in next section
        exclude "${samplegen.targetSampleModule()}/src/"
    }

    // Consolidate source directories
    ["main", "common", "template"].each { input ->
        ["java", "res", "assets", "rs"].each { filetype ->
            def srcPath = "${inputPath}/${samplegen.targetSampleModule()}/src/${input}/${filetype}"
            into("${samplegen.targetSampleModule()}/src/main/${filetype}") {
                from(srcPath)
            }
        }
    }

    // Copy AndroidManifest.xml
    into ("${samplegen.targetSampleModule()}/src/main") {
        from("${inputPath}/${samplegen.targetSampleModule()}/src/main/AndroidManifest.xml")
    }

    // Remove BEGIN_EXCLUDE/END_EXCLUDE blocks from source files
    eachFile { file ->
        if (file.name.endsWith(".gradle") || file.name.endsWith(".java")) {
            // TODO(trevorjohns): Outputs a blank newline for each filtered line. Replace with java.io.FilterReader impl.
            boolean outputLines = true;
            def removeExcludeBlocksFilter = { line ->
                if (line ==~ /\/\/ BEGIN_EXCLUDE/) {
                    outputLines = false;
                } else if (line ==~ /\/\/ END_EXCLUDE/) {
                    outputLines = true;
                } else if (outputLines) {
                    return line;
                }
                return ""
            }
            filter(removeExcludeBlocksFilter)
        }
    }
}

task emitBrowseable(type:Copy) {
    def outputPathRoot = outPath("browseable")
    def modules = project.childProjects.keySet()
    def hasMultipleModules = modules.size() > 1
    println "---------------- modules found in sample: ${modules}"
    into outputPathRoot
    from("${project.projectDir}/_index.jd")

    modules.each { moduleName ->
        // For single module samples (default), we emit the module contents
        // directly to the root of the browseable sample:
        def outputPath = "."
        if (hasMultipleModules) {
          // For multi module samples, we need an extra directory level
          // to separate modules:
          outputPath = "${moduleName}"
        }
        println "\n---------------- processing MODULE ${moduleName} to outputPath ${outputPath}"
        def inputPath = "${project.projectDir}/${moduleName}"

        def srcDirs = ["main", "common", "template"].collect {input -> "${inputPath}/src/${input}" };
        def javaDirs = srcDirs.collect { input -> "${input}/java"}
        FileTree javaTree = null;
        javaDirs.each { dir ->
            FileTree tree = project.fileTree("${dir}")
            javaTree = (javaTree == null) ? tree : javaTree.plus(tree)}
        Map collapsedPaths = collapsePaths(javaTree, javaDirs)

        srcDirs.each { srcPath ->
            print "** Copying source ${srcPath}...";
            duplicatesStrategy = 'fail'
            into("${outputPath}/src") {
                def javaPath = "${srcPath}/java";
                from(javaPath)
                include(["**/*.java", "**/*.xml"])
                eachFile { FileCopyDetails fcd ->
                    if (fcd.file.isFile()) {
                        def filename = fcd.name;
                        String collapsed = collapsedPaths.get(fcd.file.path);
                        fcd.path = "${outputPath}/src/${collapsed}";
                    } else {fcd.exclude()}
                }
                println "done"
            }
            into("${outputPath}/res") {
                from("${srcPath}/res")
            }
            into("${outputPath}/src/rs") {
                from("${srcPath}/rs")
            }
            into("${outputPath}") {from("${srcPath}/AndroidManifest.xml")}
        }
    }
}

task emitGradleZip(dependsOn: [emitBrowseable, emitGradle], type:Zip) {
    def outputPath = "${samplegen.pathToBuild}/out/browseable"
    def folderName = "${samplegen.targetSampleName()}"
    archiveName = "${samplegen.targetSampleName()}.zip"
    def inputPath = outPath("gradle")
    from inputPath
    into folderName
    include "**"
    def outDir = project.file(outputPath)
    destinationDir = outDir
}