/*
* 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.
*/

import org.apache.http.message.BasicNameValuePair

import com.urbancode.air.AirPluginTool
import com.urbancode.air.plugin.automation.RallyHelper

// Get step variables
AirPluginTool apTool = new AirPluginTool(this.args[0], this.args[1])
Properties inProps = apTool.getStepProperties()

String rallyUrl    = inProps['rallyUrl']
String rallyVer    = inProps['rallyVer']
String workspace   = inProps['workspace']
String rallyUser   = inProps['rallyUser']
String rallyPass   = inProps['rallyPass']
String rallyApiKey = inProps['rallyApiKey']
String proxyHost   = inProps['proxyHost']
String proxyPort   = inProps['proxyPort']
String proxyPass   = inProps['proxyPass']
String proxyUser   = inProps['proxyUser']

String projectKey = inProps['projectKey']
String reqKey     = inProps['reqKey']
String defectName = inProps['defectName']
String defectDesc = inProps['defectDesc']
String severity   = inProps['severity']
String priority   = inProps['priority']
String env        = inProps['env']
String state      = inProps['state']
String submitter  = inProps['submitter']
String build      = inProps['build']

// Set up RallyHelper
RallyHelper.setupHttpClient(rallyApiKey, rallyUser, rallyPass, proxyHost, proxyPort, proxyUser, proxyPass)
String workspaceRef = RallyHelper.configureWorkspace(rallyUrl, rallyVer, workspace)

// Get Defect ObjectID
String getBody
List<BasicNameValuePair> queryParams = new LinkedList<BasicNameValuePair>()
queryParams.add(new BasicNameValuePair('workspace', workspaceRef))
queryParams.add(new BasicNameValuePair('fetch', 'true'))
if (projectKey) {
    queryParams.add(new BasicNameValuePair('query', "(Name = \"${projectKey}\")"))
    println ("\n[action]  Retrieving ObjectID for artifact ${projectKey}...")
    getBody = RallyHelper.executeHttpGet('project', queryParams)
}
else {
    queryParams.add(new BasicNameValuePair('query', "(FormattedID = \"${reqKey}\")"))
    println ("\n[action]  Retrieving ObjectID for artifact ${reqKey}...")
    getBody = RallyHelper.executeHttpGet('hierarchicalrequirement', queryParams)
}

def projId
def reqId
if (projectKey) {
    projId = RallyHelper.getElement(getBody, 'Results.Object.ObjectID', 'QueryResult.Results.ObjectID')
}
else {
    String projRef = RallyHelper.getElement(getBody, 'Results.Object.Project.@ref', 'QueryResult.Results.Project._ref')
    if (!projRef) {
        println ('[error]  Could not determine project reference.')
    }
    projId = projRef.substring(projRef.lastIndexOf('/') + 1)
    reqId = RallyHelper.getElement(getBody, 'Results.Object.ObjectID', 'QueryResult.Results.ObjectID')
}

if (projId) {
    println ("[ok]  ObjectID found: ${projId}")
}
else {
    println ('[error]  Could not determine ObjectID.')
    System.exit(1)
}

// Get user id
if (!rallyVer.substring(0, 2).equals('1.')) {
    println ("\n[action]  Retrieving id for user ${submitter}...")
    queryParams = new LinkedList<BasicNameValuePair>()
    queryParams.add(new BasicNameValuePair('workspace', workspaceRef))
    queryParams.add(new BasicNameValuePair('query', "(EmailAddress = ${submitter.trim()})"))
    queryParams.add(new BasicNameValuePair('fetch', 'true'))
    getBody = RallyHelper.executeHttpGet('user', queryParams)

    submitter = RallyHelper.getElement(getBody, 'Results.Object.ObjectID', 'QueryResult.Results.ObjectID')
    if (submitter) {
        println ("[ok]  user id found: ${submitter}")
    }
    else {
        println ("[error]  Could not determine user id for ${submitter}.")
        System.exit(1)
    }
}


// Generate POST content
HashMap<String, String> children = new HashMap<String, String>()
children.put('Project', projId)
if (reqId) {
    children.put('Requirement', reqId)
}
children.put('Description', defectDesc)
children.put('Name', defectName)
children.put('Priority', priority)
children.put('Severity', severity)
children.put('State', state)
children.put('SubmittedBy', submitter)
children.put('Environment', env)
children.put('FoundInBuild', build)
children.put('Workspace', workspaceRef)
String updateInfo = RallyHelper.buildPost('Defect', children)

// Create defect
println ('\n[action]  Creating defect...')
String postBody = RallyHelper.executeHttpPost('defect/create', updateInfo)

// Process returned info
println ('\n[action]  Checking response from Rally Server...')
RallyHelper.printWarngingsAndErrors(postBody, 'Create')

def defectId
def defectRef = RallyHelper.getElement(postBody, 'Object.@ref', 'CreateResult.Object._ref')
if (!defectRef) {
    println ('[error]  Could not create defect.')
    System.exit(1)
}
defectId = defectRef.substring(defectRef.lastIndexOf('/') + 1)
if (!defectId) {
    println ('[error]  Could not get newly created defect ID.')
    System.exit(1)
}

// Verify change
println ('\n[action]  Verifying comment added...')
getBody = RallyHelper.executeHttpGet('defect/' + defectId)
def cId = RallyHelper.getElement(getBody, 'ObjectID', 'Defect.ObjectID')
def cProjRef = RallyHelper.getElement(getBody, 'Project.@ref', 'Defect.Project._ref')
def cProj = cProj = cProjRef.substring(cProjRef.lastIndexOf('/') + 1)
def cReq
if (reqId) {
    def cReqRef = RallyHelper.getElement(getBody, 'Requirement.@ref', 'Defect.Requirement._ref')
    cReq = cReqRef.substring(cReqRef.lastIndexOf('/') + 1)
}
def cName = RallyHelper.getElement(getBody, 'Name', 'Defect.Name')
def cDesc = RallyHelper.getElement(getBody, 'Description', 'Defect.Description')
def cSeverity = RallyHelper.getElement(getBody, 'Severity', 'Defect.Severity')
def cPriority = RallyHelper.getElement(getBody, 'Priority', 'Defect.Priority')
def cEnv = RallyHelper.getElement(getBody, 'Environment', 'Defect.Environment')
def cState = RallyHelper.getElement(getBody, 'State', 'Defect.State')
def cSubmit = RallyHelper.getElement(getBody, 'SubmittedBy', 'Defect.SubmittedBy._ref')
if (cSubmit.startsWith('http')) {
    cSubmit = cSubmit.substring(cSubmit.lastIndexOf('/') + 1)
}
def cBuild = RallyHelper.getElement(getBody, 'FoundInBuild', 'Defect.FoundInBuild')

int equality = 0
equality += checkEquality('ObjectId', cId, defectId)
equality += checkEquality('Project ID', cProj, projId)
equality += checkEquality('Story ID', cReq, reqId)
equality += checkEquality('Name', cName, defectName)
equality += checkEquality('Description', cDesc, defectDesc)
equality += checkEquality('Severity', cSeverity, severity)
equality += checkEquality('Priority', cPriority, priority)
equality += checkEquality('Environment', cEnv, env)
equality += checkEquality('State', cState, state)
equality += checkEquality('Submitted By', cSubmit, submitter)
equality += checkEquality('Found in Build', cBuild, build)

if (equality == 0) {
    println ('\n[ok]  Defect successfully created.')
    System.exit(0)
}
else {
    println ('\n[error]  Defect created with incorrect fields.')
    System.exit(1)
}

/**
*  @param type The type of field to print out
*  @param actual The actual text of the field, to be compared to the desired
*  @param desired The desired text of the field
*  @return 0 if the desired matches the actual, 1 otherwise
*/
private int checkEquality(String type, def actual, def desired) {
    if (desired.toString().equals(actual.toString())) {
        println ("[ok] ${type}: expected ${desired}, found ${actual}")
        return 0
    }
    else {
        println ("[error] ${type}: expected ${desired}, found ${actual}")
        return 1
    }
}