/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM UrbanCode Deploy
* IBM UrbanCode Release
* IBM AnthillPro
* (c) Copyright IBM Corporation 2016. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2020. 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.openshift

import com.urbancode.air.CommandHelper

class OpenShiftHelper {

    private CommandHelper ch
    private String script

    /**
    *  @param workDir The working directory for the CommandHelper CLI
    *  @param scriptPath The full path to the OpenShift CLI script
    */
    public OpenShiftHelper(File workDir, String scriptPath) {
        if (scriptPath) {
            this.script = scriptPath
        }
        else {
            this.script = 'oc'
        }
        ch = new CommandHelper(workDir)
    }

    /**
    *  @param proc The process to retrieve the standard output and standard error from
    *  @return An array containing the standard output and standard error of the process
    */
    public String[] captureCommand(Process proc) {
        StringBuffer stdOut = new StringBuffer()
        StringBuffer stdErr = new StringBuffer()
        proc.waitForProcessOutput(stdOut, stdErr)
        proc.out.close()
        return [stdOut.toString(), stdErr.toString()]
    }

    /**
    *  @param server The url of the OpenShift server
    *  @param username The username to authenticate with the OpenShift server
    *  @param password The password to authenticate with the OpenShift server
    *  @param token The authorization token to authenticate with the OpenShift server in place of username/password
    *  @param insecure True to ignore certificate validation (allows for untrusted certs)
    *  @param certificateAuthority Path to a cert file for the certificate authority.
    *  @param flags A newline-separated list of flags to set when running the login command.
    */
    public void login(String server,
                      String username,
                      String password,
                      String token,
                      boolean insecure,
                      String certificateAuthority,
                      String flags)
    {
        ArrayList args = []
        args << script
        args << 'login'
        args << server
        if (token) {
            args << '--token=' + token
        }
        else if (username) {
            args << '--username=' + username
            args << '--password=' + password
        }
        else {
            println ('[Error] No authentication provided.')
            println ('[Possible Solution] Please update the step configuration with either a username and password or access ' +
                     'token.')
            System.exit(1)
        }
        if (insecure) {
            args << '--insecure-skip-tls-verify'
        }
        if (certificateAuthority) {
            args << '--certificate-authority=' + certificateAuthority
        }
        if (flags) {
            setFlags(args, flags)
        }

        try {
            ch.runCommand('[Action] Logging into OpenShift server...', args) { Process proc ->
                def (String stdOut, String stdErr) = captureCommand(proc)
                if (stdErr) {
                    if (stdErr.contains('error: The token provided is invalid or expired.')) {
                        println('[Error] The token provided is invalid or expired.')
                        println('[Possible Solution] Please update the step configuration with a valid, unexpired Access Token.')
                    }
                    else if (stdErr.contains('error: x509')) {
                        println('[Error] Certificate signed by uknown authority (x509).')
                        println('[Possible Solution] If you wish to accept the certificate, update the step configuration by ' +
                                'checking "Skip TLS Verification".')
                    }
                    else if (stdErr.startsWith('Unable to connect to the server')) {
                        println('[Error] Could not connect to server')
                        println('[Possible Solution] Please update the step configuration with a valid Host.')
                    }
                    else {
                        println('[Error] Could not log in.')
                        println(stdErr)
                        println(stdOut)
                    }
                    System.exit(1)
                }
                else {
                    println('[Ok] Logged in.')
                    println(stdOut)
                }
            }
        }
        catch (IOException ioe) {
            if (ioe.getMessage().contains('Cannot run program "oc"')) {
                println ('[Error] Path variable oc not set.')
                println ('[Possible Solution] Please update step configuration with the full path to the oc script.')
            }
            else if (ioe.getMessage().contains('Cannot run program')) {
                println ("[Error] Cannot run program ${scriptPath}.")
                println ('[Possible Solution] Please update step configuration with the correct full path to the oc script.')
            }
            else {
                throw ioe
            }
            System.exit(1)
        }
    }

    /**
    *  @param project The name of the project to change to
    */
    public void setProject(String project, String flags) {
        ArrayList args = []
        args << script
        args << 'project'
        args << project

        if (flags) {
            setFlags(args, flags)
        }

        ch.runCommand("[Action] Switching to project ${project}...", args) { Process proc ->
            def (String stdOut, String stdErr) = captureCommand(proc)
            if (stdErr) {
                if (stdErr.contains("error: You are not a member of project \"${project}\".")) {
                    println ("[Error] You are not a member of project \"${project}\".")
                    println ('[Possible Solution] Please update the step configuration with a Project you are a member of.')
                }
                else {
                    println ('[Error] Could not switch project.')
                    println (stdErr)
                    println (stdOut)
                }
                System.exit(1)
            }
            else {
                println ('[Ok] Project switched.')
                println (stdOut)
            }
        }
    }

    /**
    *  @param args The list of arguments to add to the configuration options
    *  @param flags The list of flags to add to the args
    */
    public void setFlags(ArrayList args, String flags) {
        if (flags) {
            flags.split("[\r\n]+").each() { flag ->
                args << flag
            }
        }
    }

    /**
    *  @param message The message to output before running the command
    *  @param arguments An ArrayList of oc arguments to be executed by the command prompt
    *  @param closure The closure to interact with the Process IO
    */
    public void runCommand(String message, ArrayList args, Closure closure) {
        args.add(0, script)
        ch.runCommand(message, args, closure)
    }
}
