/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Deploy
 * IBM Urbancode Release
 * (c) Copyright IBM Corporation 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.marathon

import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpDelete
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpPut
import org.apache.http.client.methods.HttpUriRequest
import org.apache.http.entity.StringEntity
import org.apache.http.HttpResponse
import org.apache.http.util.EntityUtils
import java.io.File
import groovy.json.JsonSlurper
import com.urbancode.air.XTrustProvider
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder

public class MarathonRestHelper {
    def app
    def baseUrl
    def client
    def disableCerts
    def slurper

    // Scale parameters
    def instances

    public MarathonRestHelper(props) {
        this.app = props['app']
        this.baseUrl = props['baseUrl']
        this.disableCerts = props['disableCerts']
        this.slurper = new JsonSlurper()
        this.instances = props['instances']

        if (!baseUrl.substring(baseUrl.length() - 1).equals("/")) {
            baseUrl += "/"
        }

        HttpClientBuilder builder = new HttpClientBuilder()

        if (disableCerts) {
            XTrustProvider.install()
            builder.setTrustAllCerts(true)
        }
        builder.setPreemptiveAuthentication(true)

        this.client = builder.buildClient()

        System.setProperty("https.protocols", "TLSv1")
    }

    private void killAndScale() {
        HttpDelete killRequest = new HttpDelete(baseUrl + "v2/apps/${app}/tasks")
        HttpResponse response = doRequest(killRequest)
        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 200) {
            println("Task kill failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.text)
        } else {
            println("Tasks from ${app} successfully killed and scaled.")
        }
    }

    private void launchNewApplication() {
        String jsonString = new File(app).text

        HttpPost launchRequest = new HttpPost(baseUrl + "v2/apps")
        HttpResponse response = doRequest(launchRequest, jsonString)
        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 201) {
            println("Launch failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.text)
        } else {
            def id = (slurper.parseText(EntityUtils.toString(response.getEntity()))).id
            println("New Application ${id} was successfully created and started.")
        }
    }

    private void removeApplication() {
        HttpDelete removeRequest = new HttpDelete(baseUrl + "v2/apps/${app}")
        HttpResponse response = doRequest(removeRequest)
        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 200) {
            println("Removal of ${app} failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.text)
        } else {
            println("${app} removed successfully.")
        }
    }

    private void scaleApplication() {
        HttpPut scaleRequest = new HttpPut(baseUrl + "v2/apps/" + app)
        HttpResponse response = doRequest(scaleRequest, "{\"instances\": ${instances}}")
        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 200) {
            println("Scale failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.text)
        } else {
            println("Success, ${app} scaled by ${instances} instance(s).")
        }
    }

    // Execute a general http request
    private HttpResponse doRequest(HttpUriRequest request) {
        return doRequest(request, null)
    }

    // Specify a json string to provide a string entity to the http request
    private HttpResponse doRequest(HttpUriRequest request, String contentString) {
        request.addHeader("Content-Type", "application/json")
        request.addHeader("Accept", "application/json,application/xml")

        if (contentString) {
            StringEntity input

            try {
                input = new StringEntity(contentString)
            }
            catch (UnsupportedEncodingException ex) {
                println("Unsupported characters in http request content: ${contentString}")
                System.exit(1)
            }

            request.setEntity(input)
        }

        HttpResponse response = client.execute(request)

        return response
    }
}