
/*
 * Copyright 2010 the original author or authors.
 *
 * 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.
 */
import org.gradle.build.docs.UserGuideTransformTask
import org.gradle.build.docs.ExtractSnippetsTask
import org.gradle.build.docs.AssembleSamplesDocTask
import org.gradle.build.docs.dsl.docbook.AssembleDslDocTask
import org.gradle.build.docs.dsl.ExtractDslMetaDataTask

apply plugin: 'base'

configurations {
    ftpAntTask
    userGuideStyleSheets
    userGuideTask
}

dependencies {
    ftpAntTask module("org.apache.ant:ant-commons-net:1.7.0") {
        module("commons-net:commons-net:1.4.1") {
            dependencies("oro:oro:2.0.8@jar")
        }
    }

    userGuideTask 'xalan:xalan:2.7.1', 'xerces:xercesImpl:2.9.1'
    userGuideTask module('xhtmlrenderer:xhtmlrenderer:R8rc1') {
        dependency 'itext:itext:2.0.8@jar'
    }
    userGuideTask 'xslthl:xslthl:2.0.1@jar'

    userGuideStyleSheets 'docbook:docbook-xsl:1.75.2@zip'
}

RemoteLocations remoteLocations = new RemoteLocations(version: version)

srcDocsDir = file('src/docs')
userguideSrcDir = new File(srcDocsDir, 'userguide')
cssSrcDir = new File(srcDocsDir, 'css')
dslSrcDir = new File(srcDocsDir, 'dsl')

docsDir = file("$buildDir/docs")
userguideDir = new File(docsDir, 'userguide')
distDocsDir = new File(buildDir, 'distDocs')
samplesDir = file("$buildDir/samples")
docbookSrc = new File(project.buildDir, 'src')
samplesSrcDir = file('src/samples')
websiteDocs = new File(buildDir, 'websiteDocs')

tasks.withType(Docbook2Xhtml).allObjects { task->
    task.dependsOn userguideStyleSheets
    task.classpath = configurations.userGuideTask
    task.stylesheetsDir = userguideStyleSheets.destinationDir
}
tasks.withType(UserGuideTransformTask).allObjects { task->
    task.classpath = configurations.userGuideTask
    task.dependsOn samples, dslDocbook
    task.snippetsDir = samples.snippetsDir
    task.linksFile = dslDocbook.linksFile
}
tasks.withType(AssembleDslDocTask).allObjects { task ->
    task.classpath = configurations.userGuideTask
    task.classDocbookDir = dslSrcDir
}

task samples(type: ExtractSnippetsTask) {
    source samplesSrcDir
    exclude 'userguideOutput/**'
    exclude 'userguide/tutorial/antChecksumFiles/**'
    exclude '**/readme.xml'
    destDir = samplesDir
    snippetsDir = new File(buildDir, 'snippets')
    doLast {
        copy {
            from samplesSrcDir
            into samplesDir
            include 'userguide/tutorial/antChecksumFiles/**'
        }
    }
}

task userguideStyleSheets(type: Copy) {
    File stylesheetsDir = new File(srcDocsDir, 'stylesheets')
    into new File(buildDir, 'stylesheets')
    from(stylesheetsDir) {
        include '*.xsl'
    }
    from(cssSrcDir) {
        include '*.css'
    }
    from(zipTree(configurations.userGuideStyleSheets.singleFile)) {
        // Remove the prefix
        eachFile { fcd -> fcd.path = fcd.path.replaceFirst('^docbook-xsl-[0-9\\.]+/', '') }
    }
}

task samplesDocbook(type: AssembleSamplesDocTask) {
    source samplesSrcDir
    include '**/readme.xml'
    destFile = new File(docbookSrc, 'samplesList.xml')
}

task samplesDocs(type: Docbook2Xhtml, dependsOn: samplesDocbook) {
    source samplesDocbook.destFile
    destFile = new File(samples.destDir, 'readme.html')
    stylesheetName = 'standaloneHtml.xsl'
}

task dslMetaData(type: ExtractDslMetaDataTask) {
    source { groovydoc.source }
    destFile = new File(docbookSrc, 'dsl-meta-data.bin')
}

task dslDocbook(type: AssembleDslDocTask, dependsOn: [dslMetaData]) {
    inputs.files fileTree(dir: dslSrcDir, includes: ['*.xml'])
    sourceFile = new File(dslSrcDir, 'dsl.xml')
    classMetaDataFile = dslMetaData.destFile
    pluginsMetaDataFile = new File(dslSrcDir, 'plugins.xml')
    destFile = new File(docbookSrc, 'dsl.xml')
    linksFile = new File(docbookSrc, 'api-links.bin')
}

task dslStandaloneDocbook(type: UserGuideTransformTask, dependsOn: [dslDocbook]) {
    inputs.files fileTree(dir: userguideSrcDir, includes: ['*.xml'])
    inputs.files fileTree(dir: docbookSrc, includes: ['*.xml'])
    sourceFile = dslDocbook.destFile
    destFile = new File(docbookSrc, 'dsl-standalone.xml')
    javadocUrl = '../javadoc'
    groovydocUrl = '../groovydoc'
    dsldocUrl = '.'
    websiteUrl = 'http://www.gradle.org'
}

task dslHtml(type: Docbook2Xhtml, dependsOn: dslStandaloneDocbook) {
    source dslStandaloneDocbook.destFile
    destDir = new File(docsDir, 'dsl')
    stylesheetName = 'dslHtml.xsl'
    resources = fileTree {
        from cssSrcDir
        include '*.css'
    } + fileTree {
        from dslSrcDir
        include '*.js'
    }
}

task userguideDocbook(type: UserGuideTransformTask, dependsOn: [samples, samplesDocbook]) {
    inputs.files fileTree(dir: userguideSrcDir, includes: ['*.xml'])
    inputs.files fileTree(dir: docbookSrc, includes: ['*.xml'])
    sourceFile = new File(userguideSrcDir, 'userguide.xml')
    destFile = new File(docbookSrc, 'userguide.xml')
    javadocUrl = '../javadoc'
    groovydocUrl = '../groovydoc'
    dsldocUrl = '../dsl'
    websiteUrl = 'http://www.gradle.org'
}

task remoteUserguideDocbook(type: UserGuideTransformTask, dependsOn: samples) {
    inputs.files fileTree(dir: userguideSrcDir, includes: ['*.xml'])
    inputs.files fileTree(dir: docbookSrc, includes: ['*.xml'])
    sourceFile = new File(userguideSrcDir, 'userguide.xml')
    destFile = new File(docbookSrc, 'remoteUserguide.xml')
    doFirst {
        javadocUrl = remoteLocations.javadocUrl
        groovydocUrl = remoteLocations.groovydocUrl
        dsldocUrl = remoteLocations.dsldocUrl
        websiteUrl = 'http://www.gradle.org'
    }
}

task userguideHtml(type: Docbook2Xhtml, dependsOn: userguideDocbook) {
    source userguideDocbook.destFile
    destDir = userguideDir
    stylesheetName = 'userGuideHtml.xsl'
    resources = fileTree {
        from userguideSrcDir
        include 'img/*.png'
    }
    resources += fileTree {
        from cssSrcDir
        include '*.css'
    }
}

task userguideSingleHtml(type: Docbook2Xhtml, dependsOn: userguideDocbook) {
    source userguideDocbook.destFile
    destFile = new File(userguideDir, 'userguide_single.html')
    stylesheetName = 'userGuideSingleHtml.xsl'
    resources = fileTree {
        from userguideSrcDir
        include 'img/*.png'
    }
    resources += fileTree {
        from cssSrcDir
        include '*.css'
    }
}

task userguideXhtml(type: Docbook2Xhtml, dependsOn: remoteUserguideDocbook) {
    source remoteUserguideDocbook.destFile
    destFile = new File(buildDir, 'tmp/userguidePdf/userguidePdf.html')
    stylesheetName = 'userGuidePdf.xsl'
    resources = fileTree {
        from userguideSrcDir
        include 'img/*.png'
    }
    resources += fileTree {
        from cssSrcDir
        include '*.css'
    }
}

task userguidePdf(type: Xhtml2Pdf, dependsOn: userguideXhtml) {
    inputs.dir cssSrcDir
    sourceFile = userguideXhtml.destFile
    destFile = new File(userguideDir, 'userguide.pdf')
    classpath = configurations.userGuideTask
}

task javadoc(type: Javadoc) {
    group = 'documentation'
    source groovyProjects().collect {project -> project.sourceSets.main.allJava }
    destinationDir = new File(docsDir, 'javadoc')
    classpath = files(groovyProjects().collect {project -> [project.sourceSets.main.compileClasspath, project.sourceSets.main.classes] })
    include 'org/gradle/api/**'
    include 'org/gradle/*'
    include 'org/gradle/external/javadoc/**'
    include 'org/gradle/process/**'
    include 'org/gradle/plugins/**'
    include 'org/gradle/testfixtures/**'
    exclude '**/internal/**'
    options.links("http://java.sun.com/j2se/1.5.0/docs/api", "http://groovy.codehaus.org/gapi/", "http://maven.apache.org/ref/2.2.1/maven-core/apidocs",
        "http://maven.apache.org/ref/2.2.1/maven-model/apidocs")
    doFirst {
        title = "Gradle API $version"
    }
}

task checkstyleApi(type: Checkstyle) {
    source javadoc.source
    configFile = file("$checkstyleConfigDir/checkstyle-api.xml")
    classpath = files()
    resultFile = file("$checkstyleResultsDir/checkstyle-api.xml")
}

task groovydoc(type: Groovydoc) {
    group = 'documentation'
    source groovyProjects().collect {project -> project.sourceSets.main.groovy + project.sourceSets.main.java }
    destinationDir = new File(docsDir, 'groovydoc')
    includes = javadoc.includes
    excludes = javadoc.excludes
    doFirst {
        title = "Gradle API $version"
    }
    groovyClasspath = project(':core').configurations.groovy
}

task userguideFragmentSrc(type: UserGuideTransformTask, dependsOn: [userguideStyleSheets, samples]) {
    tags << 'standalone'
    sourceFile = new File(userguideSrcDir, 'installation.xml')
    destFile = new File(docbookSrc, 'installation.xml')
    doFirst {
        javadocUrl = remoteLocations.javadocUrl
        groovydocUrl = remoteLocations.groovydocUrl
        dsldocUrl = remoteLocations.dsldocUrl
        websiteUrl = 'http://www.gradle.org'
    }
}

task distDocs(type: Docbook2Xhtml, dependsOn: userguideFragmentSrc) {
    source userguideFragmentSrc.destFile
    destFile = new File(distDocsDir, 'getting-started.html')
    stylesheetName = 'standaloneHtml.xsl'
}

task websiteUserguideSrc(type: UserGuideTransformTask, dependsOn: [userguideStyleSheets, samples, samplesDocbook]) {
    inputs.files fileTree(dir: userguideSrcDir, includes: ['*.xml'])
    inputs.files fileTree(dir: docbookSrc, includes: ['*.xml'])
    sourceFile = new File(userguideSrcDir, 'userguide.xml')
    destFile = new File(docbookSrc, 'website.xml')
    tags << 'website'
    doFirst {
        javadocUrl = remoteLocations.javadocUrl
        groovydocUrl = remoteLocations.groovydocUrl
        dsldocUrl = remoteLocations.dsldocUrl
        websiteUrl = ''
    }
}

task websiteUserguide(type: Docbook2Xhtml, dependsOn: websiteUserguideSrc) {
    source websiteUserguideSrc.destFile
    destFile = new File(websiteDocs, 'website.html')
    stylesheetName = 'websiteHtml.xsl'
    resources = fileTree {
        from userguideSrcDir
        include 'img/*.png'
    }
    resources += fileTree {
        from cssSrcDir
        include '*.css'
    }
}

task websiteProperties {
    def propertiesFile = new File(websiteDocs, 'version.properties')
    inputs.property 'version', { version.toString() }
    outputs.files propertiesFile
    doLast {
        def properties = new Properties()
        properties.version = version.toString()
        propertiesFile.parentFile.mkdirs()
        propertiesFile.withOutputStream { outputStream -> properties.store(outputStream, 'documentation version properties') }
    }
}

task websiteDocs {
    dependsOn websiteUserguide, websiteProperties
}

task userguide {
    dependsOn userguideHtml, userguideSingleHtml, userguidePdf
    description = 'Generates the userguide'
    group = 'documentation'
}

task docs {
    dependsOn javadoc, groovydoc, userguide, distDocs, samplesDocs, dslHtml
    description = 'Generates all documentation'
    group = 'documentation'
}

task uploadDocs(dependsOn: docs) << {
    ftp(action: 'mkdir', remotedir: remoteLocations.docsRemoteDir)
    ftp(action: 'delete', remotedir: remoteLocations.docsRemoteDir) {
        fileset() {
            include(name: '**/*')
        }
    }
    ftp(action: 'send', remotedir: remoteLocations.docsRemoteDir) {
        fileset(dir: docsDir)
    }
}

void ftp(Map args, Closure antFileset = {}) {
    ant {
        taskdef(name: 'ftp',
                classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
                classpath: configurations.ftpAntTask.asPath)
        Map ftpArgs = args + [
                server: 'ftp.gradle.org',
                userid: websiteFtpUserName,
                password: websiteFtpUserPassword
        ]
        delegate.ftp(ftpArgs) {
            antFileset.delegate = delegate
            antFileset()
        }
    }
}

class RemoteLocations {
    def version

    static final GRADLE_ORG_URL = "http://www.gradle.org"

    String getDistributionUploadUrl() {
        version.isRelease() ? 'https://dav.codehaus.org/dist/gradle' : 'https://dav.codehaus.org/snapshots.dist/gradle'
    }

    String getDocsRemoteDir() {
        (version.isRelease() ? version.toString() : 'latest') + '/docs'
    }

    String getJavadocUrl() {
        "$GRADLE_ORG_URL/${getDocsRemoteDir()}/javadoc"
    }

    String getGroovydocUrl() {
        "$GRADLE_ORG_URL/${getDocsRemoteDir()}/groovydoc"
    }

    String getDsldocUrl() {
        "$GRADLE_ORG_URL/${getDocsRemoteDir()}/dsl"
    }
}

class Docbook2Xhtml extends SourceTask {
    @InputFiles
    FileCollection classpath

    @OutputFile @Optional
    File destFile

    @OutputDirectory @Optional
    File destDir

    @InputDirectory
    File stylesheetsDir

    String stylesheetName

    @InputFiles @Optional
    FileCollection resources

    @TaskAction
    def transform() {
        if (!((destFile != null) ^ (destDir != null))) {
            throw new InvalidUserDataException("Must specify exactly 1 of output file or dir.")
        }

        source.visit { FileVisitDetails fvd ->
            if (fvd.isDirectory()) {
                return
            }

            ant.java(classname: 'org.apache.xalan.xslt.Process', failonerror: true, fork: true) {
                jvmarg(value: '-Xmx256m')
                arg(value: '-in')
                arg(value: fvd.file)
                if (destFile) {
                    arg(value: '-out')
                    arg(value: destFile)
                } else {
                    arg(value: '-out')
                    File outFile = fvd.relativePath.replaceLastName(fvd.file.name.replaceAll('.xml$', '.html')).getFile(destDir)
                    outFile.parentFile.mkdirs()
                    arg(value: outFile)
                }
                arg(value: '-xsl')
                arg(value: new File(stylesheetsDir, stylesheetName))
                if (destDir) {
                    arg(line: "-param base.dir ${destDir}/")
                }
                sysproperty(key: 'xslthl.config', value: new File("$stylesheetsDir/highlighting/xslthl-config.xml").toURI())
                sysproperty(key: 'org.apache.xerces.xni.parser.XMLParserConfiguration', value: 'org.apache.xerces.parsers.XIncludeParserConfiguration')
                classpath {
                    path(path: classpath.asPath)
                    path(location: new File(stylesheetsDir, 'extensions/xalan27.jar'))
                }
            }
        }

        if (resources) {
            project.copy {
                into this.destDir ?: destFile.parentFile
                from resources
            }
        }
    }
}

class Xhtml2Pdf extends DefaultTask {
    @InputFile
    File sourceFile

    @OutputFile
    File destFile

    @InputFiles
    FileCollection classpath

    def Xhtml2Pdf() {
        onlyIf { !OperatingSystem.current().isWindows() }
    }

    @TaskAction
    def transform() {
        def uris = classpath.files.collect {it.toURI().toURL()}
        def classloader = new URLClassLoader(uris as URL[], getClass().classLoader)
        def renderer = classloader.loadClass('org.xhtmlrenderer.pdf.ITextRenderer').newInstance()
        renderer.setDocument(sourceFile)
        renderer.layout()
        destFile.withOutputStream {
            renderer.createPDF(it)
        }
    }
}
