/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* (c) Copyright IBM Corporation 2012, 2014. 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.automation;

import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.methods.*
import org.apache.commons.httpclient.protocol.*
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpGet
import org.codehaus.jettison.json.JSONObject

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

public class AutomationBase {
    //**************************************************************************
    // CLASS
    //**************************************************************************

    //**************************************************************************
    // INSTANCE
    //**************************************************************************
    String url
    String user
    String password
    String proxyHost
    String proxyPort
    String proxyPass
    String proxyUser
    String workspace
    HttpClient client
    
    protected def getWorkspacesUrl() {
        def subscriptionUrl = url + "subscription"
        HttpGet subscriptionMethod = new HttpGet(subscriptionUrl)
        try {
            // this worked for one proxy scenario where we were not responding to the proxy's auth challenge
            if (proxyUser && proxyPass) {
                def authString = proxyUser + ":" + proxyPass
                def authStringEnc = new String(org.apache.commons.codec.binary.Base64.encodeBase64(authString.getBytes()), 'UTF-8')
                subscriptionMethod.addHeader(new org.apache.http.message.BasicHeader('Proxy-Authorization', 'Basic ' + authStringEnc))
            }
            def subscriptionResult = client.execute(subscriptionMethod)
            def subscriptionContent = IO.readText(subscriptionResult.entity.content)
            def jsonSubscription = new JSONObject(subscriptionContent)
            def workspacesUrl = jsonSubscription.getJSONObject('Subscription').getJSONObject('Workspaces').getString('_ref')
            return workspacesUrl
        }
        catch (Exception e) {
            println "Unable to get the workspace URL from subscription ($subscriptionUrl): " + e
            return null
        }
        finally {
           subscriptionMethod.releaseConnection()
        }
    }
    
    protected def configureWorkspace() {
        boolean error = false
        def workspacesUrl = getWorkspacesUrl()
        if (!workspacesUrl) {
            System.exit(1)
        }
        HttpGet workspaceMethod = new HttpGet(workspacesUrl)
        try {
            def workResult = client.execute(workspaceMethod)
            def workResponse = IO.readText(workResult.entity.content)
            def jsonSubscription = new JSONObject(workResponse)
            def jsonResults = jsonSubscription.getJSONObject('QueryResult').getJSONArray('Results')
            for (int i=0; i<jsonResults.length(); i++) {
                def jsonResult = jsonResults.getJSONObject(i)
                if (workspace == jsonResult.getString('_refObjectName')) {
                    return jsonResult.getString('_ref')
                }
            }
            println "Either the workspace '${workspace}' does not exist or you do not have access to it. Please check " +
                    "the workspace name and confirm that your Rally user account has access to that workspace and then try again."
            error = true
        }
        catch (Exception e) {
            println "Error looking up the Rally workspace: " + e
            error = true
        }
        finally {
           workspaceMethod.releaseConnection()
           if (error) {
               System.exit(1)
           }
        }
    }
    
    protected void setupHttpClient() {
        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        if (!proxyUser && !proxyPass) {
            builder.setPreemptiveAuthentication(true)
        }
        builder.setUsername(user)
        builder.setPassword(password)
        
        // setup proxy if neccessary
        if (proxyHost) {
            println "Setting up proxy $proxyHost:$proxyPort"
            builder.setProxyHost(proxyHost)
            builder.setProxyPort(Integer.valueOf(proxyPort))
            if (proxyUser && proxyPass) {
                println "Using proxy user $proxyUser"
                builder.setProxyUsername(proxyUser)
                builder.setProxyPassword(proxyPass)
            }
        }
        client = builder.buildClient()
    }
    
    /**
     * Get the details for a Defect, Task or User Story
     * @param type One of: defect, task or hierarchicalrequirement
     * @param name Rally name identifier like DE1, TA1, or US1
     * @return XML content returned from Rally as a String
     */
    protected String findItemByName(workspaceRef, type, name) {
        HttpGet method = new HttpGet(url + type + '?workspace=' + URLEncoder.encode(workspaceRef, 'UTF-8') +
                '&query=' + URLEncoder.encode('(FormattedID = ' + name + ')', 'UTF-8') +
                '&fetch=true')
        try {
            def result = client.execute(method)
            return IO.readText(result.entity.content)
        }
        finally {
            method.releaseConnection();
        }
    }

    /**
     * Get the details for a Defect, Task or User Story
     * @param type One of: defect, task or hierarchicalrequirement
     * @param id Rally identifier for the item
     * @return XML content returned from Rally as a String
     */
    protected String getItemDetails(type, id) {
        // https://community.rallydev.com/slm/webservice/v2.0/{type}/{id}
        HttpGet method = new HttpGet(url + type + "/" + id)
        try {
            def result = client.execute(method)
            return IO.readText(result.entity.content)
        }
        finally {
            method.releaseConnection();
        }
    }
    
    protected String getKey() {
        HttpGet method = new HttpGet(url + 'security/authorize')

        try {
            def response = client.execute(method)
            def responseCode = response.statusLine.statusCode
            def content = IO.readText(response.entity.content)
            def operationResult = new JSONObject(content).get('OperationResult')
            def errors = operationResult.get('Errors')
            def warnings = operationResult.get('Warnings')

            if (errors.length() == 0 && isGoodResponseCode(responseCode)) {
               if (warnings.length() > 0) {
                   println "Warnings: $warnings"
               }
               return operationResult['SecurityToken']
            }
            else {
                println "ERROR!!! Failed to create comment"
                if (errors.length() > 0) {
                    println "Errors: $errors"
                }
                if (warnings.length() > 0) {
                    println "Warnings: $warnings"
                }
                throw new RuntimeException("Rally server did not create security key. StatusCode: ${responseCode}")
            }
        }
        finally {
            method.releaseConnection();
        }
    }
    
    protected boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }
}