package com.sap.piper

import com.cloudbees.groovy.cps.NonCPS

class WhitesourceConfigurationHelper implements Serializable {

    static def extendUAConfigurationFile(script, utils, config, path) {
        def mapping = []
        def parsingClosure = { fileReadPath -> return script.readProperties (file: fileReadPath) }
        def serializationClosure = { configuration -> serializeUAConfig(configuration) }
        def inputFile = config.whitesource.configFilePath.replaceFirst('\\./', '')
        def suffix = utils.generateSha1("${path}${inputFile}")
        def targetFile = "${inputFile}.${suffix}"
        if(config.whitesource.productName.startsWith('DIST - ')) {
            mapping += [
                [name: 'checkPolicies', value: false, force: true],
                [name: 'forceCheckAllDependencies', value: false, force: true]
            ]
        } else {
            mapping += [
                [name: 'checkPolicies', value: true, force: true],
                [name: 'forceCheckAllDependencies', value: true, force: true]
            ]
        }
        if(config.verbose)
            mapping += [name: 'log.level', value: 'debug']

        mapping += [
            [name: 'apiKey', value: config.whitesource.orgToken, force: true],
            [name: 'productName', value: config.whitesource.productName, force: true],
            [name: 'productVersion', value: config.whitesource.productVersion?:'', force: true],
            [name: 'projectName', value: config.whitesource.projectName, force: true],
            [name: 'projectVersion', value: config.whitesource.productVersion?:'', force: true],
            [name: 'productToken', value: config.whitesource.productToken, omitIfPresent: 'projectToken', force: true],
            [name: 'userKey', value: config.whitesource.userKey, force: true],
            [name: 'forceUpdate', value: true, force: true],
            [name: 'offline', value: false, force: true],
            [name: 'ignoreSourceFiles', value: true, force: true],
            [name: 'resolveAllDependencies', value: false, force: true],
            [name: 'failErrorLevel', value: 'ALL', force: true],
            [name: 'case.sensitive.glob', value: false],
            [name: 'followSymbolicLinks', value: true]
        ]

        switch (config.scanType) {
            case 'pip':
                mapping += [
                    [name: 'python.resolveDependencies', value: true, force: true],
                    [name: 'python.ignoreSourceFiles', value: true, force: true],
                    [name: 'python.ignorePipInstallErrors', value: false],
                    [name: 'python.installVirtualenv', value: true],
                    [name: 'python.resolveHierarchyTree', value: true],
                    [name: 'python.requirementsFileIncludes', value: 'requirements.txt'],
                    [name: 'python.resolveSetupPyFiles', value: true],
                    [name: 'python.runPipenvPreStep', value: true],
                    [name: 'python.pipenvDevDependencies', value: true],
                    [name: 'python.IgnorePipenvInstallErrors', value: false],
                    [name: 'includes', value: '**/*.py **/*.txt'],
                    [name: 'excludes', value: '**/*sources.jar **/*javadoc.jar']
                ]
                break
            case 'sbt':
                mapping += [
                    [name: 'sbt.resolveDependencies', value: true, force: true],
                    [name: 'sbt.ignoreSourceFiles', value: true, force: true],
                    [name: 'sbt.aggregateModules', value: false, force: true],
                    [name: 'sbt.runPreStep', value: true],
                    [name: 'includes', value: '**/*.jar'],
                    [name: 'excludes', value: '**/*sources.jar **/*javadoc.jar']
                ]
                break
            case 'golang':
                mapping += [
                    [name: 'go.resolveDependencies', value: true, force: true],
                    [name: 'go.ignoreSourceFiles', value: true, force: true],
                    [name: 'go.collectDependenciesAtRuntime', value: false],
                    [name: 'go.dependencyManager', value: 'dep'],
                    [name: 'includes', value: '**/*.lock'],
                    [name: 'excludes', value: '**/*sources.jar **/*javadoc.jar']
                ]
                break
            case 'dub':
                mapping += [
                    [name: 'includes', value: '**/*.d **/*.di']
                ]
                break
            default:
                script.echo "[Warning][Whitesource] Configuration for scanType: '${config.scanType}' is not yet hardened, please do a quality assessment of your scan results."
        }

        rewriteConfiguration(script, utils, config, mapping, suffix, path, inputFile, targetFile, parsingClosure, serializationClosure)
    }

    static private def rewriteConfiguration(script, utils, config, mapping, suffix, path, inputFile, targetFile, parsingClosure, serializationClosure) {
        def inputFilePath = "${path}${inputFile}"
        def outputFilePath = "${path}${targetFile}"
        def moduleSpecificFile = parsingClosure(inputFilePath)
        if (!moduleSpecificFile && inputFilePath != config.whitesource.configFilePath)
            moduleSpecificFile = parsingClosure(config.whitesource.configFilePath)
        if (!moduleSpecificFile)
            moduleSpecificFile = [:]

        mapping.each {
            entry ->
                def dependentValue = entry.omitIfPresent ? moduleSpecificFile[entry.omitIfPresent] : null
                if ((entry.omitIfPresent && !dependentValue || !entry.omitIfPresent) && (entry.force || moduleSpecificFile[entry.name] == null) && entry.value != 'null')
                    moduleSpecificFile[entry.name] = entry.value.toString()
        }

        def output = serializationClosure(moduleSpecificFile)

        if(config.verbose)
            script.echo "Writing config file ${outputFilePath} with content:\n${output}"
        script.writeFile file: outputFilePath, text: output
        if(config.stashContent && config.stashContent.size() > 0) {
            def stashName = "modified whitesource config ${suffix}".toString()
            utils.stashWithMessage (
                stashName,
                "Stashing modified Whitesource configuration",
                outputFilePath.replaceFirst('\\./', '')
            )
            config.stashContent += [stashName]
        }
        config.whitesource.configFilePath = outputFilePath
    }

    @NonCPS
    static private def serializeUAConfig(configuration) {
        Properties p = new Properties()
        p.putAll(configuration)

        new StringWriter().with{ w -> p.store(w, null); w }.toString()
    }
}
