/*
* Licensed Materials - Property of IBM* and/or HCL**
* UrbanCode Deploy
* UrbanCode Build
* UrbanCode Release
* AnthillPro
* (c) Copyright IBM Corporation 2011, 2017. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2018. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*
* * Trademark of International Business Machines
* ** Trademark of HCL Technologies Limited
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.Charset;

import com.urbancode.LayoutPreservingProperties
import com.urbancode.air.AirPluginTool

final AirPluginTool airTool = new AirPluginTool(args[0], args[1])
final Properties props = airTool.getStepProperties()

final def workDir = new File('.').canonicalFile

updateProps = props['updateProps']?.trim()
deleteProps = props['deleteProps']?.trim()
additionalProps = props['additionalProps']?.trim()
additionalPropsPrefix = props['additionalPropsPrefix']
def dirOffset = props['dir']
def includes = props['includes']
def excludes = props['excludes']
def useSystemEncoding = props['useSystemEncoding']?.toBoolean()
def customEncoding = props['customEncoding']?.trim()

// Determine which encoding to use, if no encoding is specified we will instead read using I/O Streams
def charset = null
def systemEncoding = System.getenv("DS_SYSTEM_ENCODING")
if (customEncoding) {
    charset = Charset.forName(customEncoding)
}
else if (useSystemEncoding && systemEncoding) {
    charset = Charset.forName(System.getenv("DS_SYSTEM_ENCODING"))
    println "Using Readers/Writers with the following encoding ${charset} to read the properties files."
}
else {
    println "Using Input/Output Streams to read the properties file."
}

if (dirOffset) {
    workDir = new File(workDir, dirOffset).canonicalFile
}

println "Working directory: ${workDir.canonicalPath}"
println "File Includes: ${includes}"
println "File Excludes: ${excludes}"

def ant = new AntBuilder()

def scanner = ant.fileScanner {
    fileset(dir:workDir.canonicalPath) {
        includes.split('\n').each {
            if (it && it.trim().length() > 0) {
                if (!it.contains("*") && !it.contains("?")) {
                    // Create a new property file if one is specified and it does not yet exist:
                    File propFile = new File(workDir.toString(), it.toString().trim())
                    File parent = propFile.getParentFile()
                    if (parent.exists()) {
                        propFile.createNewFile()
                    } else {
                        throw new FileNotFoundException(String.format("Parent directory does not exist for file: %s", it.toString().trim()));
                    }
                }
                include(name:it.trim())
            }
        }

        if(excludes) {
            excludes.split('\n').each {
                if (it && it.trim().length() > 0) {
                    exclude(name:it.trim())
                }
            }
        }
    }
}

def getNameValuePair(String str) {
    String name = null
    String value = null
    int firstEq = str.indexOf('=')
    if (firstEq > 0) {
        name = str.substring(0, firstEq)
        if (str.length() > firstEq+1) {
            value = str.substring(firstEq+1, str.length())
        }
        else {
            value = ""
        }
    }
    return [name, value]
}

def updateProperties(Properties properties) {
    if(additionalProps) {
        if (additionalPropsPrefix) {
            println "Looking for properties starting with $additionalPropsPrefix"
        }
        //this is jeffs magic regex to split on ,'s preceded by even # of \ including 0
        additionalProps.split("(?<=(^|[^\\\\])(\\\\{2}){0,8}),").each { prop ->
            //split out the name
            def parts = prop.split("(?<=(^|[^\\\\])(\\\\{2}){0,8})=",2);
            def propName = parts[0];
            def propValue = parts.size() == 2 ? parts[1] : "";
            //replace \, with just , and then \\ with \
            propName = propName.replace("\\=", "=").replace("\\,", ",").replace("\\\\", "\\")
            propValue = propValue.replace("\\=", "=").replace("\\,", ",").replace("\\\\", "\\")

            if (additionalPropsPrefix && propName.startsWith(additionalPropsPrefix)) {
                propName = propName.substring(additionalPropsPrefix.length())
                properties.setProperty(propName, propValue)
                println 'additional property: ' + propName + '=' + propValue
            }
            else if (!additionalPropsPrefix) {
                properties.setProperty(propName, propValue)
                println 'additional property: ' + propName + '=' + propValue
            }
        }
    }
    updateProps?.split('\n')?.each {
        if (it) {
            properties.setProperty(getNameValuePair(it))
        }
    }
    deleteProps?.split('\n')?.each {
        def name = it.trim()
        if (name) {
            properties.remove(name)
        }
    }
}

def updateWithStreams(File file, Charset charset) {
    Properties props
    if (charset) {
        props = new LayoutPreservingProperties(charset.toString(), false)
    }
    else {
        props = new LayoutPreservingProperties()
    }
    InputStream inStream = null
    try {
        inStream = new FileInputStream(file);
        props.load(inStream)
    }
    finally {
        inStream?.close()
    }
    updateProperties(props)
    OutputStream outStream = null
    try {
        outStream = new FileOutputStream(file)
        props.store(outStream, "")
    }
    finally {
        outStream?.close()
    }
}

for(propFile in scanner) {
    println "Property File: ${propFile.canonicalPath}"
    println "Update Properties:\n${updateProps?:''}\n"
    println "Additional Update Properties:\n${additionalProps?:''}\n"
    println "Additional Update Properties Prefix:${additionalPropsPrefix?:''}\n"
    println "Delete Properties:\n${deleteProps?:''}\n"

    try {
            updateWithStreams(propFile, charset)
    }
    catch (Exception e) {
        println "Error updating property file ${propFile.canonicalPath}: ${e.message}"
        e.printStackTrace()
        System.exit(1)
    }
}
System.exit(0)
