import groovy.util.*
import static groovy.io.FileType.*

buildscript {
    repositories {
        maven {
            credentials {
                username mavenUsername
                password mavenPassword
            }
            url mavenRepository
        }
    }
    dependencies {
        classpath libs.asciidoctorj.diagram
    }
}
repositories {
    maven {
        credentials {
            username depsMavenUsername
            password depsMavenPassword
        }
        url depsMavenRepository
    }
}
dependencies {
    jbake libs.asciidoctorj.diagram
    jbake libs.pebble
    config.jbake.plugins.each { plugin ->
        jbake plugin
    }
}

apply plugin: 'org.jbake.site'

def color = { color, text ->
    def colors = [black: 30, red: 31, green: 32, yellow: 33, blue: 34, magenta: 35, cyan: 36, white: 37]
    return new String((char) 27) + "[${colors[color]}m${text}" + new String((char) 27) + "[0m"
}

jbake {
    version = '2.6.7'
    srcDirName = "${targetDir}/microsite/tmp/site"
    destDirName = "${targetDir}/microsite/output"
    configuration['asciidoctor.option.requires'] = "asciidoctor-diagram"
    config.microsite.each { key, value ->
        configuration['site.'+key-'config.microsite.'] = value?:''
        //println 'site.'+key-'config.microsite.' +" = "+ value
    }

    def micrositeContextPath = config.microsite.contextPath?:'/'

    configuration['asciidoctor.attributes'] = [
        "sourceDir=${targetDir}",
        'source-highlighter=prettify@',
        //'imagesDir=../images@',
        "imagesoutDir=${targetDir}/microsite/output/images@",
        "imagesDir=${micrositeContextPath.endsWith('/') ? micrositeContextPath : micrositeContextPath.concat('/')}images@",
        "targetDir=${targetDir}",
        "docDir=${docDir}",
        "projectRootDir=${new File(docDir).canonicalPath}@",
    ]
    if(config.jbake.asciidoctorAttributes) {
        config.jbake.asciidoctorAttributes.each { entry ->
            configuration['asciidoctor.attributes'] << entry
        }
    }

}

def prepareAndCopyTheme = {
    //copy internal theme
    println "copy internal theme ${new File(projectDir, 'src/site').canonicalPath}"
    copy {
        from('src/site')
        into("${targetDir}/microsite/tmp/site")
    }
    //check if a remote pdfTheme is defined
    def siteTheme = System.getenv('DTC_SITETHEME')?:""
    def themeFolder = new File(projectDir, "../themes/" + siteTheme.md5())
    try {
        if (siteTheme) {
            println "use siteTheme $siteTheme"
            //check if it is already installed
            if (!themeFolder.exists()) {
                if (System.getenv('DTC_HEADLESS')) {
                    ant.yesno = "y"
                } else {
                    println "${color 'green', """\nTheme '$siteTheme' is not installed yet. """}"
                    def input = ant.input(message: """
${color 'green', 'do you want me to download and install it to '}
${color 'green', '   ' + themeFolder.canonicalPath}
${color 'green', 'for you?'}\n""",
                        validargs: 'y,n', addproperty: 'yesno')
                }
                if (ant.yesno == "y") {
                    themeFolder.mkdirs()
                    download.run {
                        src siteTheme
                        dest new File(themeFolder, 'siteTheme.zip')
                        overwrite true
                    }
                    copy {
                        from zipTree(new File(themeFolder, 'siteTheme.zip'))
                        into themeFolder
                    }
                    delete {
                        delete new File(themeFolder, 'siteTheme.zip')
                    }

                } else {
                    println "${color 'green', """\nI will continue without the theme for now... """}"
                    siteTheme = ""
                }

            }
            //copy external theme
            if (siteTheme) {
                copy {
                    from(themeFolder) {}
                    into("${targetDir}/microsite/tmp/")
                }
                //check if the config has to be updated
                // check if config still contains /** microsite **/
                def configFile = new File(docDir, mainConfigFile)
                def configFileText = configFile.text
                if (configFileText.contains("/** start:microsite **/")) {
                    def configFragment = new File(targetDir,'/microsite/tmp/site/configFragment.groovy')
                    if (configFragment.exists()) {
                        println "${color 'green', """
    It seems that this theme is used for the first time in this project.
    Let's configure it!
    If you are unsure, change these settings later in your config file
    $configFile.canonicalPath
    """}"
                        def comment = ""
                        def conf = ""
                        def example = ""
                        def i = 0
                        configFragment.eachLine { line ->
                            if (line.trim()) {
                                if (line.startsWith("//")) {
                                    conf += "    " + line + "\n"
                                    def tmp = line[2..-1].trim()
                                    comment += color('green', tmp) + "\n"
                                    if (tmp.toLowerCase().startsWith("example")) {
                                        example = tmp.replaceAll("[^ ]* ", "")
                                    }
                                } else {
                                    //only prompt if there is something to prompt
                                    if (line.contains("##")) {
                                        def property = line.replaceAll("[ =].*", "")
                                        if (!example) {
                                            example = config.microsite[property]
                                        }
                                        comment = color('blue', "$property") + "\n" + comment
                                        if (example) {
                                            ant.input(message: comment,
                                                addproperty: 'res' + i, defaultvalue: example)
                                        } else {
                                            ant.input(message: comment,
                                                addproperty: 'res' + i)
                                        }
                                        (comment, example) = ["", ""]
                                        line = line.replaceAll("##.+##", ant['res' + i])
                                        conf += "    " + line + "\n"
                                        i++
                                    } else {
                                        conf += "    " + line + "\n"
                                    }
                                }
                            } else {
                                conf += "\n"
                            }
                        }
                        configFile.write(configFileText.replaceAll("(?sm)/[*][*] start:microsite [*][*]/.*/[*][*] end:microsite [*][*]/", "%%marker%%").replace("%%marker%%", conf))
                        println color('green', "config written\nopen ${targetDir}/microsite/output/index.html in your browser\nto see your microsite!")
                    }
                    //copy the dummy docs (blog, landing page) to the project repository
                    copy {
                        from(new File(themeFolder, 'site/doc')) {}
                        into(new File(docDir, inputPath))
                    }
                }
            }
        }
    } catch (Exception e) {
        println color('red', e.message)
        if (e.message.startsWith("Not Found")) {
            themeFolder.deleteDir()
            throw new GradleException("Couldn't find theme. Did you specify the right URL?\n"+e.message)
        } else {
            throw new GradleException(e.message)
        }
    }
    //copy project theme
    if (config.microsite.siteFolder) {
        def projectTheme = new File(new File(docDir, inputPath), config.microsite.siteFolder)
        println "copy project theme ${projectTheme.canonicalPath}"
        copy {
            from(projectTheme) {}
            into("${targetDir}/microsite/tmp/site")
        }
    }

}

def convertAdditionalFormats = {
    if (config.microsite.additionalConverters) {
        File sourceFolder = new File(targetDir, '/microsite/tmp/site/doc')
        sourceFolder.traverse(type: FILES) { file ->
            def extension = '.' + file.name.split("[.]")[-1]
            if (config.microsite.additionalConverters[extension]) {
                def command = config.microsite.additionalConverters[extension].command
                def type = config.microsite.additionalConverters[extension].type
                def binding = new Binding([
                    file  : file,
                    config: config
                ])
                def shell = new GroovyShell(getClass().getClassLoader(), binding)
                switch (type) {
                    case 'groovy':
                        shell.evaluate(command)
                        break
                    case 'groovyFile':
                        shell.evaluate(new File(docDir, command).text)
                        break
                    case 'bash':
                        if (command=='dtcw:rstToHtml.py') {
                            // this is an internal script
                            command = projectDir.canonicalPath+'/scripts/rstToHtml.py'
                        }
                        command = ['bash', '-c', command + ' "' + file + '"']
                        def process = command.execute([], new File(docDir))
                        process.waitFor()
                        if (process.exitValue()) {
                            def error = process.err.text
                            println """
can't convert '${file.canonicalPath-docDir-'/build/microsite/tmp/site/doc'}':
${error}
"""
                            throw new Exception("""
can't convert '${file.canonicalPath-docDir-'/build/microsite/tmp/site/doc'}':
${error}
""")
                        }
                }
            }
        }
    }

}

def parseAsciiDocAttribs = { origText, jbake ->
    def parseAttribs = true
    def text = ""
    def beforeToc = ""
    origText.eachLine { line ->
        if (parseAttribs && line.startsWith(":jbake")) {
            def parsedJbakeAttribute = (line - ":jbake-").split(": +", 2)
            if(parsedJbakeAttribute.length != 2) {
                logger.warn("jbake-attribute is not valid or Asciidoc conform: $line")
                logger.warn("jbake-attribute $line will be ignored, trying to continue...")
            } else {
                jbake[parsedJbakeAttribute[0]] = parsedJbakeAttribute[1]
            }
        } else {
            if (line.startsWith("[")) {
                // stop parsing jBake-attribs when a [source] - block starts which might contain those attribs as example
                parseAttribs = false
            }
            text += line+"\n"
            //there are some attributes which have to be set before the toc
            if (line.startsWith(":toc") ) {
                beforeToc += line+"\n"
            }
        }
    }
    return [text, beforeToc]
}

def parseOtherAttribs = { origText, jbake ->
    if (origText.contains('~~~~~~')) {
        def parseAttribs = true
        def text = ""
        origText.eachLine { line ->
            if (parseAttribs && line.contains("=")) {
                line = (line - "jbake-").split("=", 2)
                jbake[line[0]] = line[1]
            } else {
                if (line.startsWith("~~~~~~")) {
                    // stop parsing jBake-attribs when delimiter shows up
                    parseAttribs = false
                } else {
                    text += line + "\n"
                }
            }
        }
        return text
    } else {
        return origText
    }
}

def renderHeader = { fileName, jbake ->
    def header = ''
    if (fileName.toLowerCase() ==~ '^.*(html|md)$') {
        jbake.each { key, value ->
            if (key == 'order') {
                header += "jbake-${key}=${(value ?: '1') as Integer}\n"
            } else {
                if (key in ['type', 'status']) {
                    header += "${key}=${value}\n"
                } else {
                    header += "jbake-${key}=${value}\n"
                }
            }
        }
        header += "~~~~~~\n\n"

    } else {
        jbake.each { key, value ->
            if (key == 'order') {
                header += ":jbake-${key}: ${(value ?: '1') as Integer}\n"
            } else {
                header += ":jbake-${key}: ${value}\n"
            }
        }
    }
    return header
}
def fixMetaDataHeader = {
    //fix MetaData-Header
    File sourceFolder = new File(targetDir, '/microsite/tmp/site/doc')
    logger.info("sourceFolder: " + sourceFolder.canonicalPath)
    sourceFolder.traverse(type: FILES) { file ->
        if (file.name.toLowerCase() ==~ '^.*(ad|adoc|asciidoc|html|md)$') {
            if (file.name.startsWith("_") || file.name.startsWith(".")) {
                //ignore
            } else {
                def origText = file.text
                //parse jbake attributes
                def text = ""
                def jbake = [
                    status: "published",
                    order: -1,
                    type: 'page_toc'
                ]
                if (file.name.toLowerCase() ==~ '^.*(md|html)$') {
                    // we don't have a toc for md or html
                    jbake.type = 'page'
                }
                def beforeToc = ""
                if (file.name.toLowerCase() ==~ '^.*(ad|adoc|asciidoc)$') {
                    (text, beforeToc) = parseAsciiDocAttribs(origText, jbake)
                } else {
                    text = parseOtherAttribs(origText, jbake)
                }
                def name = file.canonicalPath - (sourceFolder.canonicalPath+File.separator)
                if (File.separator=='\\') {
                    name = name.split("\\\\")
                } else {
                    name = name.split("/")
                }
                if (name.size()>1) {
                    if (!jbake.menu) {
                        jbake.menu = name[0]
                        if (jbake.menu ==~ /[0-9]+[-_].*/) {
                            jbake.menu = jbake.menu.split("[-_]", 2)[1]
                        }
                    }
                    def docname = name[-1]
                    if (docname ==~ /[0-9]+[-_].*/) {
                        jbake.order = docname.split("[-_]",2)[0]
                        docname     = docname.split("[-_]",2)[1]
                    }
                    if (name.size() > 2) {
                        if ((jbake.order as Integer)==0) {
                            // let's take the order from the second level dir or file and not the file
                            def secondLevel = name[1]
                            if (secondLevel ==~ /[0-9]+[-_].*/) {
                                jbake.order = secondLevel.split("[-_]",2)[0]
                            }
                        } else {
                            if (((jbake.order?:'1') as Integer) > 0) {
                                //
                            } else {
                                jbake.status = "draft"
                            }
                        }
                    }
                    if (jbake.order==-1 && docname.startsWith('index')) {
                        jbake.order = -987654321 // special 'magic value' given to index pages.
                        jbake.status = "published"
                    }
                    // news blog
                    if (jbake.order==-1 && jbake.type=='post') {
                        jbake.order = 0
                        try {
                            jbake.order = Date.parse("yyyy-MM-dd", jbake.date).time / 100000
                        } catch ( Exception e) {
                            System.out.println "unparsable date ${jbake.date} in $name"
                        }
                        jbake.status = "published"
                    }
                    def leveloffset = 0
                    if (file.name.toLowerCase() ==~ '^.*(ad|adoc|asciidoc)$') {
                        text.eachLine { line ->
                            if (!jbake.title && line ==~ "^=+ .*") {
                                jbake.title = (line =~ "^=+ (.*)")[0][1]
                                def level = (line =~ "^(=+) .*")[0][1]
                                if (level == "=") {
                                    leveloffset = 1
                                }
                            }
                        }
                    } else {
                        if (file.name.toLowerCase() ==~ '^.*(html)$') {
                            if (!jbake.title) {
                                text.eachLine { line ->
                                    if (!jbake.title && line ==~ "^<h[1-9]>.*</h.*") {
                                        jbake.title = (line =~ "^<h[1-9]>(.*)</h.*")[0][1]
                                    }
                                }
                            }
                        } else {
                            // md
                            if (!jbake.title) {
                                text.eachLine { line ->
                                    if (!jbake.title && line ==~ "^#+ .*") {
                                        jbake.title = (line =~ "^#+ (.*)")[0][1]
                                    }
                                }
                            }
                        }
                    }
                    if (!jbake.title) {
                        jbake.title = docname
                    }
                    if (leveloffset==1) {
                        //leveloffset needed
                        // we always start with "==" not with "="
                        // only used for adoc
                        text = text.replaceAll("(?ms)^(=+) ", '$1= ')
                    }
                    if (config.microsite.customConvention) {
                        def binding = new Binding([
                            file  : file,
                            sourceFolder : sourceFolder,
                            config: config,
                            headers : jbake
                        ])
                        def shell = new GroovyShell(getClass().getClassLoader(), binding)
                        shell.evaluate(config.microsite.customConvention)
                        System.out.println jbake

                    }
                    def header = renderHeader(file.name, jbake)
                    if (file.name.toLowerCase() ==~ '^.*(ad|adoc|asciidoc)$') {
                        file.write(header + "\nifndef::dtc-magic-toc[]\n:dtc-magic-toc:\n$beforeToc\n\n:toc: left\n\n++++\n<!-- endtoc -->\n++++\nendif::[]\n" + text, "utf-8")
                    } else {
                        file.write(header + "\n" + text, "utf-8")
                    }
                }
            }
        }
    }

}

task generateSite(
    group: 'docToolchain',
    description: 'generate a microsite using jBake.') {
    doLast {
        new File("${targetDir}/microsite/tmp").mkdirs()
        println new File("${targetDir}/microsite/tmp/").canonicalPath

        prepareAndCopyTheme()

        //copy docs
        copy {
            from(new File(docDir, inputPath)) {}
            into("${targetDir}/microsite/tmp/site/doc")
        }

        // if configured, convert restructuredText or anything else
        convertAdditionalFormats()

        // convention over configuration
        fixMetaDataHeader()

    }
}

task previewSite(
    group: 'docToolchain',
    dependsOn: [],
    description: 'preview your Microsite',
) {
    doLast {
        println("previewSite command has been deprecated.")
        println("To preview your site, open ${targetDir}/microsite/output/index.html in your browser.")
        println("To read alternative ways to preview your site, please consult the documentation.")
    }
}
previewSite.dependsOn(generateSite)
previewSite.mustRunAfter(bake)

task copyImages(type: Copy) {
    config.imageDirs.each { imageDir ->
        from(new File (new File(docDir, inputPath),imageDir)) {}
        logger.info ('imageDir: '+imageDir)
        into("${targetDir}/microsite/output/images")
    }
    config.resourceDirs.each { resource ->
        from(new File(file(srcDir),resource.source))
        logger.info ('resource: '+resource.source)
        into("${targetDir}/microsite/output/" + resource.target)
    }
}

bake.dependsOn copyImages
generateSite.finalizedBy bake
