import java.net.URLEncoder
import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.auth.AuthScope;
import com.google.gson.JsonParser

/**
 * @author Varban Vassilev (vvv@urbancode.com)
 * @author Mike Samano (mss2@urbancode.com)
 */

public class NetScalerRestHelper {

    //def private SOAPClient client
    def private sessionId
    def private JsonParser jsonParser
    //def private RESTClient client
    def private HttpClient client
    def private restUrl
    def private baseUrl
    def private cookie


    def public NetScalerRestHelper(serverUrl) {
        // fix URL formatting and remove trailing slashes
        serverUrl = serverUrl?.replaceAll('\\\\', '/')
        while (serverUrl?.endsWith('/')) {
            serverUrl = serverUrl[0..-2]
        }

        restUrl = serverUrl + "/nitro/v1"

        jsonParser = new JsonParser()
        client = new HttpClient()
    }

    def public login = { username, password ->
        println "Login to server"

        def loginJson = '{\"login\":{\"username\":\"'
        loginJson += username
        loginJson += '\",\"password\":\"'
        loginJson += password
        loginJson += '\"}}'

        def body = URLEncoder.encode("object=" + loginJson)

        def responseJson = executePostMethod(loginJson)

        sessionId = responseJson.'sessionid'

        def errorCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (errorCode != 0) {
            throw new Exception("Error logging in: $errorCode - $message")
        }
    }

    def private executePostMethod = { requestJson ->
        HttpMethod method = new PostMethod(restUrl + "/config")
        method.addRequestHeader("ContentType", "application/x-www-form-urlencoded")
        method.addParameter("object", requestJson)


        def methodResult = client.executeMethod(method)
        def response = method.getResponseBodyAsString()
        def responseJson = null

        if (methodResult >= 200 && methodResult < 300) {
            responseJson = jsonParser.parse(response)
        }
        else {
            throw new Exception ("Received response ${methodResult}: ${response}")
        }

        return responseJson
    }

    def private executeGetMethod = { requestUrl, username, password ->
        HttpMethod method = new GetMethod(requestUrl)

        Credentials defaultcreds = new UsernamePasswordCredentials(username, password)
        client.getState().setCredentials(AuthScope.ANY, defaultcreds)
        client.getParams().setAuthenticationPreemptive(true)

        def methodResult = client.executeMethod(method)
        def response = method.getResponseBodyAsString()
        def responseJson = null

        if (methodResult >= 200 && methodResult < 300) {
            responseJson = jsonParser.parse(response)
        }
        else {
            throw new Exception ("Received response ${methodResult}: ${response}")
        }

        return responseJson
    }

    def public logout = { ->
        println "Logout from server"
        def logoutJson = '{\"logout\": {}, "sessionid": ' + sessionId + '}'
        def responseJson = executePostMethod(logoutJson)

        def errorCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (errorCode != 0) {
            throw new Exception("Error logging out: $errorCode - $message")
        }
    }

    def public enableService = { service ->
        println "Enable service $service"
        def requestObject = '{\"params\": {\"action\":\"enable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"service\": {\"name\":\"'
        requestObject += service
        requestObject += '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'
        if (returnCode != 0) {
            throw new Exception("Error enabling service: $returnCode - $message")
        }
    }

    def public enableServer = { server ->
        println "Enable server $server"
        def requestObject = '{\"params\": {\"action\":\"enable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"server\": {\"name\":\"'
        requestObject += server
        requestObject += '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'
        if (returnCode != 0) {
            throw new Exception("Error enabling server: $returnCode - $message")
        }
    }

    def public enableServiceGroup = { serviceGroup ->
        println "Enable service group $serviceGroup"
        def requestObject = '{\"params\": {\"action\":\"enable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"servicegroup\": {\"servicegroupname\":\"'
        requestObject += serviceGroup
        requestObject += '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (returnCode != 0) {
            throw new Exception("Error enabling service group: $returnCode - $message")
        }
    }

    def public getServiceGroupBindings = { serviceGroup, username, password ->
        def serviceGroupPath = "/config/servicegroup_binding/" + URLEncoder.encode(serviceGroup)

        def responseJson = executeGetMethod(restUrl + serviceGroupPath, username, password)

        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (returnCode != 0) {
            throw new Exception("Error retrieving service group: $returnCode - $message")
        }

        return responseJson
    }

    def public getServiceGroup = { serviceGroup, username, password ->
        println "Get service group '${serviceGroup}'"

        def serviceGroupPath = "/config/servicegroup/" + URLEncoder.encode(serviceGroup)

        def responseJson = executeGetMethod(restUrl + serviceGroupPath, username, password)

        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (returnCode != 0) {
            throw new Exception("Error retrieving service group: $returnCode - $message")
        }

        return responseJson
    }

    def public disableService = { service, timeout, isGraceful ->
        println "Disable service $service with timeout $timeout (s)"

        def gracefulString = isGraceful ? "YES" : "NO"
        def requestObject = '{\"params\": {\"action\":\"disable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"service\": {\"name\":\"'
        requestObject += service
        requestObject += '\", \"delay\":' + timeout
        requestObject += ', \"graceful\":\"' + gracefulString + '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'
        if (returnCode != 0) {
            throw new Exception("Error disabling service: $errorCode - $message")
        }
    }

    def public disableServiceGroup = { serviceGroup, timeout, isGraceful ->
        println "Disable service group $serviceGroup with timeout $timeout (s)"

        def gracefulString = isGraceful ? "YES" : "NO"
        def requestObject = '{\"params\": {\"action\":\"disable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"servicegroup\": {\"servicegroupname\":\"'
        requestObject += serviceGroup
        requestObject += '\", \"delay\":' + timeout
        requestObject += ', \"graceful\":\"' + gracefulString + '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'

        if (returnCode != 0) {
            throw new Exception("Error disabling service group: $returnCode - $message")
        }
    }

    def public disableServer = { server, timeout, isGraceful ->
        println "Disable server $server with timeout $timeout (s)"

        def gracefulString = isGraceful ? "YES" : "NO"
        def requestObject = '{\"params\": {\"action\":\"disable\"},\"sessionid\":'
        requestObject += sessionId
        requestObject += ', \"server\": {\"name\":\"'
        requestObject += server
        requestObject += '\", \"delay\":' + timeout
        requestObject += ', \"graceful\":\"' + gracefulString + '\"}}'

        def responseJson = executePostMethod(requestObject)
        def returnCode = responseJson.'errorcode'.getAsInt()
        def message = responseJson.'message'
        if (returnCode != 0) {
            throw new Exception("Error disabling server: $returnCode - $message")
        }
    }
}
