/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM UrbanCode Deploy
* IBM UrbanCode Release
* IBM AnthillPro
* (c) Copyright IBM Corporation 2002, 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.servicenow

import com.urbancode.air.AirPluginTool
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import com.urbancode.commons.httpcomponentsutil.PreemptiveAuthHttpClient

import groovyx.net.http.*

import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.Header
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.util.EntityUtils

import groovy.util.slurpersupport.GPathResult
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder

public class HelperRestClientJsonOld {

    def airPluginTool
    def auth
    String changeRequestId
    HttpClientBuilder clientBuilder
    DefaultHttpClient client
    def password
    def props = []
    def proxyHost
    def proxyPort
    def proxyUser
    def proxyPass
    def serverUrl
    def username

    public HelperRestClientJsonOld(def airPluginToolIn) {
        airPluginTool = airPluginToolIn
        props = airPluginTool.getStepProperties()

        changeRequestId = props['changeRequestId']
        password = props['password']
        proxyHost = props['proxyHost']
        serverUrl = props['serverUrl']
        username = props['username']

        println "Using serverUrl ${serverUrl}"
        println "Using username ${username}"

        while (serverUrl.endsWith('/')) {
            serverUrl = serverUrl.substring(0, serverUrl.length() - 1);
        }

        if (!serverUrl.toLowerCase().startsWith("http")) {
            serverUrl = "https://" + serverUrl
        }

        clientBuilder = new HttpClientBuilder()
        clientBuilder.setUsername(username)
        clientBuilder.setPassword(password)
        clientBuilder.setPreemptiveAuthentication(true)

        if (proxyHost != null && !proxyHost.isEmpty()) {
            proxyPort = props['proxyPort']
            proxyUser = props['proxyUser']
            proxyPass = props['proxyPass']

            println "Using Proxy Host ${proxyHost}"
            println "Using Proxy Port ${proxyPort}"
            println "Using Proxy User ${proxyUser}"
            clientBuilder.setProxyHost(proxyHost)
            clientBuilder.setProxyPassword(proxyPass)
            clientBuilder.setProxyPort(Integer.valueOf(proxyPort))
            clientBuilder.setProxyUsername(proxyUser)
        }

        client = clientBuilder.buildClient()
    }


    def String getApproval() {
        def parsedJson = getRecords('/change_request.do?JSON&sysparm_query=number=' + changeRequestId)

        if (!parsedJson?.records) {
            println "No Change Request found with ID ${changeRequestId}. Exiting failure."
            System.exit(1)
        }
        return parsedJson.records[0].approval
    }

    def Integer getStatus() {
        def parsedJson = getRecords('/change_request.do?JSON&sysparm_query=number=' + changeRequestId)

        if (parsedJson.records.size() == 0) {
            println "No Change Request found with ID ${changeRequestId}. Exiting failure."
            System.exit(1)
        }
        return Integer.valueOf(parsedJson.records[0].state)
    }

    def String getChangeRequestSysId() {
        def parsedJson = getRecords('/change_request.do?JSON&sysparm_query=number=' + changeRequestId)

        if (parsedJson.records.size() == 0) {
            println "No Change Request found with ID ${changeRequestId}. Exiting failure."
            System.exit(1)
        }
        return parsedJson.records[0].sys_id
    }

    def getTaskList(String changeRequestSysId) {
        return getRecords('/change_task.do?JSON&sysparm_query=change_request=' + changeRequestSysId)
    }

    def setTaskStatus(String taskId, String status) {
        HttpPost post = new HttpPost(serverUrl + '/change_task.do?JSON&sysparm_query=sys_id=' + taskId +
            '&sysparm_action=update')
        String updateInfo = '{"state":"' + status + '"}'
        StringEntity postEntity = new StringEntity(updateInfo)
        post.setEntity(postEntity)
        println "Setting task ${taskId} with status ${status}"

        def resp = client.execute(post)

        def statusCode = resp.getStatusLine().getStatusCode()
        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}. Exiting Failure."
            System.exit(1)
        }

        def newStatus = getTaskStatus(taskId)
        if (newStatus != Integer.valueOf(status)) {
            println "Status was not updated. Exiting Failure"
            System.exit(1)
        }
    }

    def Integer getTaskStatus(String taskId) {
        def parsedJson = getRecords('/change_task.do?JSON&sysparm_query=sys_id=' + taskId)

        if (parsedJson.records.size() == 0) {
            println "No Change Request found with ID ${changeRequestId}. Exiting failure."
            System.exit(1)
        }
        return Integer.valueOf(parsedJson.records[0].state)
    }

    def setStatus(String status) {
        HttpPost post = new HttpPost(serverUrl + '/change_request.do?JSON&sysparm_query=number='+
            changeRequestId + '&sysparm_action=update')
        String updateInfo = '{"state":"' + status + '"}'
        StringEntity postEntity = new StringEntity(updateInfo)
        post.setEntity(postEntity)
        def resp = client.execute(post)
        def statusCode = resp.getStatusLine().getStatusCode()
        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}. Exiting Failure."
            System.exit(1)
        }

        def newStatus = getStatus()
        if (newStatus != Integer.valueOf(status)) {
            println "Status was not updated. Exiting Failure"
            System.exit(1)
        }
    }

    def insertRow() {
        def tableName = props['table']
        def unparsedFields = props['fields']
        def fields = [:]

        if(!tableName) {
            throw new IllegalArgumentException("no table name was specified!")
        }
        HttpPost post = new HttpPost(serverUrl + "/" + tableName + ".do?JSON&sysparm_action=insert")

        def nameValuePairs = unparsedFields.split("\n")
        nameValuePairs.each { nameValue ->
            try {
                def delim = nameValue.indexOf(":")
                def name = nameValue.substring(0, delim)
                def value = nameValue.substring(delim+1)
                fields[name] = value
            } catch (IndexOutOfBoundsException e) {
                throw new IllegalArgumentException("The syntax of your input field was incorrect for field $nameValue")
            }
        }

        def jsonMap = new JsonBuilder(fields)
        StringEntity postEntity = new StringEntity(jsonMap.toString())
        post.setEntity(postEntity)
        def resp = client.execute(post)
        def statusCode = resp.getStatusLine().getStatusCode()

        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}. Exiting Failure."
            System.exit(1)
        }
    }

    def deleteRow() {
        def tableName = props['table']
        def id = props['id']

        if(!tableName) {
            throw new IllegalArgumentException("no table name was specified!")
        }
        if(!id) {
            throw new IllegalArgumentException("no ID was specified!")
        }

        println "Deleting row from table ${tableName}"
        println "Deleting row with Id ${id}"

        String bodyToSend = '{"sysparm_sys_id":"' + id + '"}'
        HttpPost post = new HttpPost(serverUrl + "/" + tableName + ".do?JSON&sysparm_action=deleteRecord")

        StringEntity postEntity = new StringEntity(bodyToSend)
        post.setEntity(postEntity)
        def resp = client.execute(post)
        def statusCode = resp.getStatusLine().getStatusCode()

        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}. Exiting Failure."
            System.exit(1)
        }
    }

    def deleteMultipleRows() {
        def tableName = props['table']
        def condition = props['condition']

        if(!tableName) {
            throw new IllegalArgumentException("no table name was specified!")
        }
        if(!condition) {
            throw new IllegalArgumentException("no condition was specified!")
        }

        println "Deleting row from table ${tableName}"
        println "Deleting row with condition ${condition}"

        String bodyToSend = '{"sysparm_query":"' + condition + '"}'
        HttpPost post = new HttpPost(serverUrl + "/" + tableName + ".do?JSON&sysparm_action=deleteMultiple")

        StringEntity postEntity = new StringEntity(bodyToSend)
        post.setEntity(postEntity)
        def resp = client.execute(post)
        def statusCode = resp.getStatusLine().getStatusCode()

        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}. Exiting Failure."
            System.exit(1)
        }
    }

//////////////////////////////// HELPER METHODS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

    // Accepts any string compatible with ServiceNow's API GET Retreive Record appended to serverUrl + '/api/now/v1/table/'
    def getRecords(String query) {
        def parsedJson

        HttpGet get = new HttpGet(serverUrl + query)
        get.addHeader("Accept", "application/json")
        def resp = client.execute(get)

        def statusCode = resp.getStatusLine().getStatusCode()
        if (statusCode < 200 || statusCode >= 300) {
            println "Request failed with status ${statusCode}."
            System.exit(1)
        }

        def entity = EntityUtils.toString(resp.getEntity())
        def slurper = new JsonSlurper()
        try {
            parsedJson = slurper.parseText(entity)
        }
        catch (groovy.json.JsonException e) {
            println ""
            println "Failed to parse response body. Printing useful debugging information and exiting."
            println ""
            println "Response status code: ${statusCode}."
            println ""
            println "Header:"
            Header[] headers = resp.getAllHeaders()
            for (Header header : headers) {
                System.out.println(header.getName() + ":"+ header.getValue())
                }
            println ""
            println "Body:"
            println entity
            println ""
            println "Stacktrace:"
            e.printStackTrace()
            System.exit(1)
        }
        return parsedJson
    }
}
