/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Deploy
 * (c) Copyright IBM Corporation 2014, 2016. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */

 package com.urbancode.air.plugin.websphere.bpm

import java.io.File
import java.io.BufferedWriter
import java.io.FileWriter
import java.text.SimpleDateFormat
import java.util.Date

class WebSphereBPMHelper {

    static def verbose = false // Added for extra output during runWsadmin() calls

    /**
     * @param verbose Boolean for extra output setting
     * @return Sets the static verbose variable to display extra output
     */
    public static setVerbose(def verbose) {
        this.verbose = verbose
    }

    /**
     * @param props Contains the port, user, host, password, connType, profileRoot,
     *        and useSOAPProps properties specified by the user
     * @param isWindows Boolean determining whether the agent is windows or not
     * @return The result String List used to connect and run a BPM command on the BPM server
     */
    public static ArrayList createCommandArgs(def props, def isWindows) {
        setVerbose(Boolean.valueOf(props['verbose']))

        def wsadmin = isWindows ? "wsadmin.bat" : "wsadmin.sh"
        def port = props['port']
        def user = props['user']
        def host = props['host']
        def password = props['password']
        def connType = props['connType']
        def profHome = props['profileRoot']
        if (!(profHome.endsWith("\\") || profHome.endsWith("/"))) {
            profHome = profHome + File.separator
        }
        def commandPath = profHome + "bin" + File.separator + wsadmin
        def result = [
            commandPath,
            "-lang",
            "jython"
        ];
        result << "-conntype"
        result << connType.trim()
        result << "-port"
        result << port;
        if (!props['useSOAPProps'].equals("true")) {
            result << "-user"
            result <<  user
            result << "-password"
            result << password
        }

        if (host) {
            result << "-host"
            result << host
        }

        result << "-f"
        result << "temp.py"

        return result
    }

    /**
     * @param invoke The BPMCommand to be run
     * @param commandArgs Connect to the BPM server and run the BPMCommand
     * @param isWindows Add specific Windows variable is necessary
     * @param ch Command Helper object used to run the BPMCommand
     * @return The success or failure status of the step
     */
    public static int invokeCommand(String invoke, def commandArgs, def isWindows, def ch) {
        int result = 0

        try {
            File tempFile = new File("temp.py")
            tempFile.deleteOnExit()
            BufferedWriter temp = new BufferedWriter(new FileWriter(tempFile))
            temp.write(invoke, 0, invoke.length())
            println "invoke: " + invoke
            temp.close()
            if (isWindows) {
                ch.addEnvironmentVariable("PROFILE_CONFIG_ACTION", "true")
            }
            ch.runCommand(invoke, commandArgs)
        }
        catch (IOException ioe) {
            result = 1
            ioe.printStackTrace()
        }
        catch (Exception e) {
            e.printStackTrace()
            result = -1
        }

        return result
    }

    /**
     * @param val The string in question of being empty
     * @return True if string contains characters, otherwise false
     */
    public static boolean isEmpty(String val) {
        return val == null || val.equals("")
    }

    /**
     * @param container The name of the process application
     * @param commandArgs The args for the wsadmin command
     * @return The acronym/short name of the application
     *         If the acronym itself is passed to the method, it is returned as is.
     */
    public static String getContainerAcronym(def container, def commandArgs) {
        def command = "AdminTask.BPMListProcessApplications()"
        return getAcronym(command, commandArgs, container)
    }

    /**
     * @param snapshot The name of the process application snapshot/track
     * @param container The name of the process application
     * @param commandArgs The args for the wsadmin command
     * @return The acronym/short name of the application snapshot/track.
     *         If the acronym itself is passed to the method, it is returned as is.
     */
    public static String getSnapshotTrackAcronym(def snapshot, def container, def commandArgs) {
        def command = "AdminTask.BPMShowProcessApplication('[-containerAcronym " + container + "]')"
        return getAcronym(command, commandArgs, snapshot)
    }

    /**
     * @param command The wsadmin command to invoke to find the acronym
     * @param commandArgs The args for the wsadmin command
     * @param name The name of the process application/snapshot/track
     * @return The acronym/short name of the application/snapshot/track.
     *         If the acronym itself is passed to the method, it is returned as is.
     */
    private static String getAcronym(def command, def commandArgs, def name) {
        println "[Action] Searching for '${name}'..."
        def wsadminOutput = runWsadmin(command, commandArgs)
        def pattern = "(Track\\s+)?(Name|Acronym)\\s*:\\s*(" + name + ")[\\\\n\\s\\t]+((Track\\s+)?Acronym\\s*:\\s*(.+?)(?=\\\\n))*"
        def matcher = wsadminOutput =~ pattern
        if (matcher.find()) {
            if (matcher[0][2] == "Name") {
                return matcher[0][6]
            }
            return name.toString()
        }
        return ""
    }

    /**
     *
     * @param command The wsadmin command to invoke to find the acronym
     * @param commandArgs The args for the wsadmin command
     * @return Runs the wsadmin command and returns its output logs
     */
    private static String runWsadmin(def command, def commandArgs) {
        File tempFile = new File("temp.py")
        tempFile.deleteOnExit();
        BufferedWriter temp = new BufferedWriter(new FileWriter(tempFile))
        temp.writeLine("print " + command)
        temp.close()

        def procBuilder = new ProcessBuilder(commandArgs)
        def statusProc = procBuilder.start()
        def reader = new BufferedReader(new InputStreamReader(statusProc.getInputStream()))
        def outputLines = ""
        def line = reader.readLine()
        while (line != null) {
            outputLines = outputLines + line + "\\n"
            line = reader.readLine()
        }
        if (verbose) {
            println "=========================================="
            println "[Verbose Output] wsadmin.sh Call... " + commandArgs.join(" ").toString()
            println "=========================================="
            println "[Verbose Output] temp.py Contents... " + tempFile.text
            println "=========================================="
            println "[Verbose Output] Command Line Output... " + outputLines.toString()
            println "=========================================="
        }
        tempFile.delete()
        return outputLines.toString()
    }

    /**
     * @param inputFile User input for the location of file
     * @param workDir The specified working directory
     * @return Full path of where the File exists, else return empty string
     */
    private static String getFilePath(def inputFile, def workDir) {
        def result = ""

        def workDirString = workDir.toString() + File.separator + inputFile
        File workDirFile = new File(workDirString)

        File absFile = new File(inputFile)

        if (workDirFile.isFile()) {
            result = workDirString
            println "${inputFile} found in the working directory."
        }
        else if (absFile.isFile()) {
            result = inputFile
            println "${inputFile} found using the absolute path."
        }
        else {
            println "${inputFile} as not found in the working directory nor using its absolute path."
        }
        return result
    }

    /**
     * @param inputFile User input for the file name
     *        Assumes file is located in working directory
     * @param workDir The specified working directory
     * @return Full path of where the file may have been
     */
    private static String removeFileReturnPath(def inputFile, def workDir) {
        File f = new File(inputFile)
        if (f.isFile()) {
            f.delete()
        }
        return f.getCanonicalPath()
    }

    /**
     * @param inputFile User input for the file name
     *        Assumes file is being placed in working directory
     * @param workDir The specified working directory
     * @return Full inputFile path with date appended
     */
    private static String createUniqueFileName(def inputFile, def workDir) {
        Date d = new Date()
        SimpleDateFormat format = new SimpleDateFormat("MM-dd-YYYY_hh:mm:ss")
        def path = workDir.toString() + File.separator + inputFile + "_" + format.format(d)
        return path
    }
}
