/*
* Licensed Materials - Property of IBM* and/or HCL**
* UrbanCode Deploy
* (c) Copyright IBM Corporation 2013, 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
*/
package com.urbancode.air.plugin.jboss.helper

import com.urbancode.air.CommandHelper
import com.urbancode.air.plugin.jboss.helper.StreamPrinter

public class JBossHelper {
    def pb = new ProcessBuilder(['echo'] as String[]).directory(new File('.').canonicalFile)
    def cmdArgs = []
    def scriptData
    def out = System.out
    def err = System.err

    public JBossHelper(def cmdArgsIn) {
        cmdArgs = cmdArgsIn
    }

    public JBossHelper(def cmdArgsIn, def scriptDataIn) {
        cmdArgs = cmdArgsIn
        scriptData = scriptDataIn
    }

    def runCommand(def message, Closure closure) {
        runCommand(message, null, closure)
    }

    def runCommand(def message, def timeout, Closure closure) {
        pb.command(cmdArgs as String[])
        pb.environment()['NOPAUSE'] = 'true'
        println()
        if (message) {
            println(message)
        }
        println("command: ${pb.command().join(' ')}")

        def outbuilder = new StringBuilder()
        def errbuilder = new StringBuilder()

        def proc = pb.start()

        // signal to the process to use StringBuilders to store the output and errout
        proc.consumeProcessOutput(outbuilder, errbuilder)


        if (timeout == null) {
            proc.waitFor()
        }
        else {
            proc.waitForOrKill(timeout)
        }

        // If we have some post-processing to do, do it now
        if (closure) {
            String output = outbuilder.toString() + errbuilder.toString()
            closure(proc, output)
        }

        if (outbuilder.toString().size() != 0) {
            println "\n${outbuilder}"
        }
        if (errbuilder.toString().size() != 0) {
            println "\n${errbuilder}"
        }

        return proc.exitValue()

    }

    def runStartCommand(def message, def timeout, def host, def port) {
        def exitCode = 0;
        def workDir = new File('.').canonicalFile
        CommandHelper helper = new CommandHelper(workDir)

        def s = new Socket()
        def addr = new InetSocketAddress(host, port)

        try {
            s.connect(addr)
        }
        catch (IOException e) {
            System.out.println("Server is not running. Attempting to start server now.")
        }
        finally {
            if (s != null) {
                if (s.isConnected()) {
                    println "The server is already running, exiting with success"
                    s.close()
                    System.exit(exitCode)
                }
                else {
                    s.close()
                }
            }
        }

        def startTime = System.currentTimeMillis()

        /* jboss startup script runs an interactive shell, continually waiting for output
         * stream reading must occur in a separate thread so the main thread isn't blocked
         */
        def readStreams = {
            it.out.close() // close stdin
            StreamPrinter outPrinter = new StreamPrinter(it.getInputStream())
            StreamPrinter errPrinter = new StreamPrinter(it.getErrorStream())
            outPrinter.start()
            errPrinter.start()

            def gotConnection = false
            s = new Socket()
            addr = new InetSocketAddress(host, port)

            while (!gotConnection
                && System.currentTimeMillis() - startTime < timeout
                && errPrinter.lineCount == 0)
            {
                try {
                    s.connect(addr)
                    gotConnection = s.isConnected()
                }
                catch (IOException e) {
                    //do nothing
                }
                finally {
                    if (s != null) {
                        s.close()
                        s = new Socket()
                    }
                }
            }

            if (errPrinter.lineCount != 0) {
                println("[ERROR] An error occurred during server startup process.")
                exitCode = 1
            }
            else if (!gotConnection) {
                println("[ERROR] Server not started in a timely manner.")
                exitCode = 1
            }
            else {
                println "[OK] Achieved a connection to the server. Server has been started"
            }

            outPrinter.interrupt()
            errPrinter.interrupt()
            System.exit(exitCode)
        }

        helper.runCommand("Starting JBoss server with timeout ${timeout}...", cmdArgs, readStreams)
    }

    def runUndeployCommand(def message) {
        def foundLines = false
        runCommand(message) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    foundLines = true
                }
            }
        }

        if (foundLines) {
            println "Error: The application was not undeployed"
            System.exit(1)
        }
        else {
            println "Undeployment successful"
        }
    }

    def runDeployCommand(def message) {
        def foundLines = false
        runCommand(message) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    foundLines = true
                }
            }
        }

        if (foundLines) {
            println "Error: The application was not deployed to the server"
            System.exit(1)
        }
        else {
            println "Deployment successful"
        }
    }

    def runStopCommand(def message) {
        def outputFile = new File("outputStopFile.txt")
        def outcomeHit = false

        runCommand(message) { Process proc, String output ->
            outputFile.write(output);
        }

        for (line in outputFile.readLines()) {
            if (line.contains("outcome")) {
                outcomeHit = true
                if (!line.contains("success")) {
                    println "Could not shut down server. Check to see if your server is in standalone or domain mode"
                    System.exit(1)
                }
                else {
                    println "JBoss Server shut down successfully"
                }
            }
        }
        if (!outcomeHit) {
            println "Could not shut down the server. The server may not have been running"
            System.exit(1)
        }
    }

    def runSourceCommand(def message) {
        def foundErrors = false
        def errorMessage = ''
        runCommand(message) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    if (line.startsWith("JBAS")) {
                        foundErrors = true
                        errorMessage = "Error creating data source. Exiting"
                    }
                    if (line.startsWith("Unrecognized argument")) {
                        foundErrors = true
                        errorMessage = "Error creating data source, bad argument. Exiting"
                    }
                }
            }
        }

        if (foundErrors) {
            println errorMessage
            System.exit(1)
        }
        else {
            println "Data source created"
        }
    }

    def runQueueCommand(def message) {
        def foundLines = false
        runCommand(message) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    foundLines = true
                }
            }
        }

        if (foundLines) {
            println "Error: The Queue/Topic could not be created"
            System.exit(1)
        }
        else {
            println "Queue/Topic creation successful"
        }
    }

    def runFactoryCommand(def message) {
        def foundLines = false
        runCommand(message) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    foundLines = true
                }
            }
        }

        if (foundLines) {
            println "Error: The factory could not be created/deleted"
            System.exit(1)
        }
        else {
            println "Factory management successful"
        }
    }

    def runServerCommand(def message) {
        def foundErrors = false
        def foundOutcome = false
        runCommand(message) { Process proc, String output ->
            if (output) {
                output.eachLine { line ->
                    if (line && line.trim().length() > 0) {
                        if (line.contains("outcome")) {
                            foundOutcome = true
                            if (!line.contains("success")) {
                                foundErrors = true
                            }
                        }
                    }
                }
            }
        }

        if (foundErrors || !foundOutcome) {
            println "Could not create server group/server."
            System.exit(1)
        }
        else {
            println "Server Group/Server created successfully."
        }
    }

    def runRestartServerGroupsCommand(def message, def timeout) {
        def foundErrors = false
        def foundOutcome = false
        def startTime = System.currentTimeMillis()

        runCommand(message, timeout) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    if (line.contains("outcome")) {
                        foundOutcome = true
                        if (!line.contains("success")) {
                            foundErrors = true
                        }
                    }
                    else if (line.contains("not a valid")) {
                        foundErrors = true
                    }
                }
            }
        }

        if (foundErrors || !foundOutcome) {
            println "Could not restart all specified server groups."
            System.exit(1)
        }
        else {
            println "Server Group restarted successfully."
        }
    }

    def runRestartServerCommand(def message, def timeout) {
        def foundErrors = false
        def foundOutcome = false
        def startTime = System.currentTimeMillis()
        runCommand(message, timeout) { Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    if (line.contains("outcome")) {
                        foundOutcome = true
                        if (!line.contains("success")) {
                            foundErrors = true
                        }
                    }
                    else if (line.contains("not a valid")) {
                        foundErrors = true
                    }
                }
            }
        }
        if (foundErrors || !foundOutcome) {
            throw new RuntimeException("Could not restart all specified server groups.")
        }
        else {
            println "Server Restarted Successfully"
        }
    }

    def runScriptCommand(def message) {
        runCommand(message, null)
    }

    def runDisableCommand(def message) {
        def foundLines = false
        runCommand(message) {Process proc, String output ->
            output.eachLine { line ->
                if (line && line.trim().length() > 0) {
                    foundLines = true
                }
            }
        }

        if (foundLines) {
            println "Error: The application was not disabled"
            System.exit(1)
        }
        else {
            println "Disabled successful"
        }
    }

    def createTempFile() {
        def tmpFile = File.createTempFile('ud-jboss-', '.cli')
        tmpFile.deleteOnExit()
        return tmpFile
    }

    void printScriptContents(File script) {
        println "================================"
        println "Script Contents:"
        println script.text
        println "================================"
    }
}
