/*
* 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.nio.charset.Charset

import com.urbancode.air.AirPluginTool
import com.urbancode.air.FileSet
import java.nio.file.*
import java.nio.file.attribute.AclFileAttributeView

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

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

def propFileName = props['propFile']
def dirOffset = props['dir']?:'.'
File offsetFolder = new File(workDir, dirOffset)
if (!offsetFolder.isDirectory()) {
    println "[Ok] Creating temporary offset directory..."
    offsetFolder.mkdir()
    offsetFolder.deleteOnExit()
}
workDir = offsetFolder.canonicalPath
//using fileset utility to include and exclude file pattern
//assume the user meant it to be a path separator
//no need to replace with commas using replaceAll("\r\n|\n|\n\r|\r", ",");
def includes = props['includes'].replaceAll(",", "\n").replaceAll(" ", "\n");
def excludes = props['excludes'].replaceAll(",", "\n").replaceAll(" ", "\n");
def startDelimiter = props['startDelimiter']?:''
def endDelimiter = props['endDelimiter']?:''
def propertyPrefix = props['propertyPrefix']
def envPropValues = props['envPropValues']
def explicitTokens = props['explicitTokens']
def customEncoding = props['customEncoding']
def propFile = new File(workDir, propFileName)
def propFileExists = false

def getPerms(Path path) {
    def perms = null;
    // try posix
    try {
        perms = Files.getPosixFilePermissions(path);
    }
    catch (UnsupportedOperationException e) {
        // swallow - this is thrown if we are not on a posix supported system(e.g. windows)
    }

    // try windows
    if (perms == null) {
        // should return null if not a valid file view(i.e. not windows)
        def view = Files.getFileAttributeView(path, AclFileAttributeView.class);
        perms = view?.getAcl();
    }
    return perms;
}

def setPerms(Path path, def perms) {
    if (perms != null) {
        if (perms instanceof Set) {
            // posix file permissions is represented as a set of PosixFilePermission
            println "Resetting posix file permissions for file : ${path}";
            Files.setPosixFilePermissions(path, perms);
        }
        else if (perms instanceof List) {
            // windows returns a list of AclEntry
            def view = Files.getFileAttributeView(path, AclFileAttributeView.class);
            println "Resetting file acl for file : ${path}";
            view?.setAcl(perms);
        }
    }
}

def encoding
if (customEncoding) {
    try {
        encodingSupported = Charset.isSupported(customEncoding)
    }
    catch (IllegalArgumentException iae) {
        println ("[error]  Encoding type ${customEncoding} not valid.")
        println ('[possible solution]  Please update the step configuration with a valid encoding type.')
        System.exit(1)
    }
    if (!encodingSupported) {
        println ("[error]  Encoding type ${customEncoding} not supported.")
        println ('[possible solution]  Please update the step configuration with a supported encoding type.')
        System.exit(1)
    }
    else {
        encoding = customEncoding
    }
}
else {
    File AGENT_HOME;
    if (System.getenv().get("AGENT_HOME")){
        AGENT_HOME = new File(System.getenv().get("AGENT_HOME"))
    }
    if (AGENT_HOME) {
        def agentInstalledProps = new File(AGENT_HOME, "conf/agent/installed.properties")
        def agentProps = new Properties();
        def agentInputStream = null;
        try {
            agentInputStream = new FileInputStream(agentInstalledProps);
            agentProps.load(agentInputStream);
        }
        catch (IOException e) {
            throw new RuntimeException(e);
        }
        encoding = agentProps['system.default.encoding']
    }
    else {
        encoding = Charset.defaultCharset().name()
    }
}

try {

    def Properties properties = new Properties()
    if (propFile.exists() && propFile.isFile()) {
        propFileExists = true
        println "Found existing input property file: ${propFile.canonicalPath}"
        def tempProps = new Properties()
        propFile.withInputStream { stream ->
            tempProps.load(stream)
        }
        tempProps.each { k,v ->
            String name = k;
            // assume that if the property starts and endswith the delimiters, it
            // does not need to have them added
            if (!(name.startsWith(startDelimiter) && name.endsWith(endDelimiter))) {
                name = startDelimiter + k + endDelimiter;
            }
            properties.setProperty(name, v)
        }
    }
    if(envPropValues) {
       if (propertyPrefix) {
            println "Looking for properties starting with $propertyPrefix"
        }
        //this is jeffs magic regex to split on ,'s preceded by even # of \ including 0
        envPropValues.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 ((!propertyPrefix || propName.startsWith(propertyPrefix))) {
                if (propName) {
                    properties.setProperty(startDelimiter + propName + endDelimiter, propValue)
                }
            }
        }
    }

    if (explicitTokens) {
        explicitTokens.eachLine {
            if (it && it.indexOf('->') > 0) {
                def index = it.indexOf('->')
                def propName = it.substring(0, index).trim()
                def propValue = index < (it.length() - 2) ? it.substring(index + 2) : ""
                properties.setProperty(propName, propValue)
            }
            else if (it) {
                println "Found invalid explicit token $it - missing -> separator"
            }
        }
    }

    if (!propFileName) {
        println "Creating temporary property file. Results will display one additional replacement per token due to this file."
        propFile = File.createTempFile("tmp", ".properties", new File(workDir))
        propFileName = propFile.getName()
    }

    propFile.withOutputStream { outStream ->
        properties.store(outStream, 'Auto generated property file')
    }

    properties.each { k,v ->
        println "added: $k:$v"
    }

    def ant = new AntBuilder()
    if (properties.size() > 0) {
        println "Replacing tokens in files located in ${workDir}";
        FileSet fileSet = new FileSet(workDir);
        fileSet.include(includes);
        if (excludes) {
            fileSet.exclude(excludes);
        }
        List files = fileSet.files();
        files.each { file ->
            Path filePath = file.toPath();
            if (!Files.isDirectory(filePath) &&
                !file.getCanonicalFile().equals(propFile.getCanonicalFile()))
            {
                def perms = getPerms(filePath);
                println "Replacing tokens in file : ${file}";
                ant.replace(
                        file: file,
                        replacefilterfile: propFile.canonicalPath,
                        summary: 'true',
                        encoding: encoding,
                        defaultexcludes: 'no')
                setPerms(filePath, perms);
            }
        }
    }
    else {
        println 'Did not find any properties or explicit tokens for replacement.'
    }
}
catch (Exception e) {
    e.printStackTrace()
    println "Error replacing tokens!"
    if (propFile != null && !propFileExists) {
        propFile.delete()
    }
    System.exit(1)
}
finally {
    if (propFile != null && !propFileExists) {
        propFile.delete()
    }
}

if (!propFileExists) {
    println "Temporary property file deleted."
}
System.exit(0)
