/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* IBM AnthillPro
* (c) Copyright IBM Corporation 207. 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.ubuild.ucbtool

import java.net.URLEncoder;

import org.apache.http.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpGet
import org.apache.http.entity.StringEntity

import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import com.urbancode.commons.util.IO

public class UCBTool {

    //**************************************************************************
    // CLASS
    //**************************************************************************
    private Integer requestTimeout = -1;

    //**************************************************************************
    // INSTANCE
    //**************************************************************************

    public UCBTool() {
    }

    public void addReports(String url, String authToken, String xml, String descBeforeSend) {
        def exceptionMsg = "Failed to upload report."
        postToServer(url, authToken, xml, descBeforeSend, exceptionMsg)
    }

    private void postProperties(String url, String authToken, String xml, String descBeforeSend) {
        def exceptionMsg = "Failed to add properties."
        postToServer(url, authToken, xml, descBeforeSend, exceptionMsg)
    }

    private void postToServer(String url, String authToken, String xml, String descBeforeSend, String exceptionMsg) {
        HttpPost postMethod = new HttpPost(url)
        if (authToken) {
            postMethod.addHeader("Authorization-Token", authToken)
            postMethod.addHeader("Content-Type", "application/xml")
        }

        if (descBeforeSend) {
            println descBeforeSend
        }

        println xml
        postMethod.setEntity(new StringEntity(xml))

        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        if (requestTimeout != null && requestTimeout > 0) {
            builder.setTimeoutMillis(requestTimeout)
        }
        HttpClient client = builder.buildClient()

        HttpResponse response = client.execute(postMethod)
        def responseCode = response.statusLine.statusCode
        InputStream responseStream = response.entity.content
        if (isGoodResponseCode(responseCode)) {
            IO.copy(responseStream, System.out)
            println ""
        }
        else {
            IO.copy(responseStream, System.err)
            throw new RuntimeException(exceptionMsg + " StatusCode: ${responseCode}")
        }
    }

    public void addTestReports(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String reportName,
        String xml,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        def name = URLEncoder.encode(reportName, "UTF-8")

        String url = baseUrl + "rest/buildlife/${buildLifeId}/tests?reportName=${name}"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public void addSourceAnalyticsReports(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String reportName,
        String xml,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        def name = URLEncoder.encode(reportName, "UTF-8")

        String url = baseUrl + "rest/buildlife/${buildLifeId}/sourceanalytics?reportName=${name}"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public void addSourceAnalyticSummariesReports(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String reportName,
        String xml,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        def name = URLEncoder.encode(reportName, "UTF-8")

        String url = baseUrl + "rest/buildlife/${buildLifeId}/sourceanalyticsummaries?reportName=${name}"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public void addTestCoverageReports(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String reportName,
        String xml,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        def name = URLEncoder.encode(reportName, "UTF-8")

        String url = baseUrl + "rest/buildlife/${buildLifeId}/testcoverage?reportName=${name}"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public void addSourceChanges(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String xml,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/sourcechanges"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public String getSourceChanges(String baseUrl, String authToken, String buildLifeId) {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/sourcechanges"
        println "Sending request to $url"
        return getFromServer(url, authToken, "source changes")
    }

    public void addIssues(String baseUrl, String authToken, String buildLifeId, String xml, String descBeforeSend) {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/issues"
        println "Sending request to $url"
        addReports(url, authToken, xml, descBeforeSend)
    }

    public String getIssues(String baseUrl, String authToken, String buildLifeId) {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/issues"
        println "Sending request to $url"
        return getFromServer(url, authToken, "issues")
    }

    public void addProperties(
        String baseUrl,
        String authToken,
        String id,
        String scope,
        String propertiesXML,
        String descBeforeSend)
    {
        if ("buildlife".equals(scope)) {
            addBuildLifeProperties(baseUrl, authToken, id, propertiesXML, descBeforeSend)
        }
        else if ("job".equals(scope)) {
            addJobProperties(baseUrl, authToken, id, propertiesXML, descBeforeSend)
        }
        else if ("buildrequest".equals(scope)) {
            addRequestProperties(baseUrl, authToken, id, propertiesXML, descBeforeSend)
        }
        else if ("system".equals(scope)) {
            addSystemProperties(baseUrl, authToken, propertiesXML, descBeforeSend)
        }
        else {
            println "The scope should be one of 'buildlife','job','buildrequest',system', but it is '$scope'."
        }
    }

    private void addBuildLifeProperties(
        String baseUrl,
        String authToken,
        String buildLifeId,
        String propertiesXML,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/properties"
        println "Sending request to $url"
        postProperties(url, authToken, propertiesXML, descBeforeSend)
    }

    private void addJobProperties(
        String baseUrl,
        String authToken,
        String jobId,
        String propertiesXML,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/job/${jobId}/properties"
        println "Sending request to $url"
        postProperties(url, authToken, propertiesXML, descBeforeSend)
    }

    private void addRequestProperties(
        String baseUrl,
        String authToken,
        String buildRequestId,
        String propertiesXML,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/request/${buildRequestId}/properties"
        println "Sending request to $url"
        postProperties(url, authToken, propertiesXML, descBeforeSend)
    }

    private void addSystemProperties(
        String baseUrl,
        String authToken,
        String propertiesXML,
        String descBeforeSend)
    {
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/system/properties/properties"
        println "Sending request to $url"
        postProperties(url, authToken, propertiesXML, descBeforeSend)
    }

    private String getFromServer(String url, String authToken, String type) {
         println "\nGetting $type from server"

        HttpGet getMethod = new HttpGet(url)
        if (authToken) {
            getMethod.addHeader("Authorization-Token", authToken)
        }

        String contentXML
        try {
            HttpClientBuilder builder = new HttpClientBuilder()
            builder.setTrustAllCerts(true)
            if (requestTimeout != null && requestTimeout > 0) {
                builder.setTimeoutMillis(requestTimeout);
            }
            def client = builder.buildClient()

            HttpResponse response = client.execute(getMethod)
            def responseCode = response.statusLine.statusCode
            InputStream responseStream = response.entity.content

            contentXML = IO.readText(responseStream)
            if (!isGoodResponseCode(responseCode)) {
                throw new Exception("Failed to get build life $type from the server: $contentXML")
            }
        }
        finally {
            getMethod.releaseConnection()
        }

        return contentXML
    }

    public boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }

    public void setRequestTimeout(Integer requestTimeout) {
        this.requestTimeout = requestTimeout;
    }
}

