/*
* 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.
*/
package com.urbancode.air.plugin.integration

import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil

import com.urbancode.air.plugin.rtcworkitems.RTCWorkItemHelper
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpRequestBase
import org.apache.http.entity.StringEntity

public class CreateWorkItem {

    def apTool
    String url
    String password
    String username
    String projectName
    String comment
    String workItemType
    String workItemSummary
    String workItemDescription
    def workItemTags
    String filedAgainst
    String additionalAttributes
    String procId
    String compProcId
    String appProcId
    String requestId
    String serverUrl
    boolean addCommentUrl
    def props
    boolean debug

    public void execute() {
        createWorkItem()
    }

    public void createWorkItem() {

        HttpClientBuilder hcBuilder = new HttpClientBuilder()
        hcBuilder.setTrustAllCerts(true)
        HttpClient client = hcBuilder.buildClient()

        def rtcHelper = new RTCWorkItemHelper(props)
        def catalogurl = rtcHelper.getCatalogUrl(client)
        rtcHelper.authenticateRTCUser(catalogurl, client)
        def servicesUrl = rtcHelper.getServicesUrl(catalogurl, client)
        def contextId = servicesUrl?.split("/")[-3]
        System.out.println("Context ID: " + contextId)
        def workItemTypeId = rtcHelper.getWorkItemTypeId(workItemType, contextId, client)
        def filedAgainstID
        if (filedAgainst && filedAgainst.trim().length() > 0) {
            filedAgainstID = rtcHelper.getFiledAgainstId(filedAgainst, contextId, client)
        }
        def workItemCreateUrl = rtcHelper.getWorkItemCreationUrl(workItemTypeId, servicesUrl, client)


        def attributes
        List<String> badNamespaces = ["dc", "rdf", "oslc_disc", "jd", "calm", "jp", "atom", "opensearch"]
        if (additionalAttributes && additionalAttributes.trim().length() > 0 && additionalAttributes.indexOf("=") > 0) {
            attributes = additionalAttributes.trim().split("\r|\n|\r\n")?.findAll{ it -> it && it.trim().length() > 0 && it.indexOf("=") > 0}
            // Crash if invalid namespace is given. Add "rtc_cm" if not found (for backwards compatibility)
            attributes = attributes.collect{ it ->
                if (it.matches("(" + badNamespaces.join("|") + ").*")) {
                    throw new Exception("[Error] Additional Argument '${it}' uses an invalid namespace. " +
                        "Only the 'rtc_cm' and 'oslc_cm' namespaces are allowed.")
                }
                else if (it.startsWith("oslc_cm:") || it.startsWith("rtc_cm:")) {
                    it = it
                }
                else {
                    it = "rtc_cm:" + it
                }
            }
        }

        HttpRequestBase method = null
        def response = null
        def createResult
        def gBuilder = new groovy.xml.StreamingMarkupBuilder()

        def newWorkItem = {
            mkp.declareNamespace('oslc_cm':'http://open-services.net/xmlns/cm/1.0/')
            mkp.declareNamespace('rtc_cm':'http://jazz.net/xmlns/prod/jazz/rtc/cm/1.0/')
            mkp.declareNamespace('dc': 'http://purl.org/dc/terms/')
            mkp.declareNamespace('rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#')
            mkp.declareNamespace('calm': 'http://jazz.net/xmlns/prod/jazz/calm/1.0/')
            mkp.declareNamespace('oslc_pl': 'http://open-services.net/ns/pl#')
            'oslc_cm:ChangeRequest'{
                if (filedAgainstID) {
                    'rtc_cm:filedAgainst'('rdf:resource':"$filedAgainstID")
                }

                'dc:title'(workItemSummary)
                if (workItemDescription) {
                    'dc:description'(workItemDescription.replaceAll("\n","&#13;&#10;"))
                }
                if (workItemTags.size() > 0) {
                    'dc:subject'(workItemTags.join(", "))
                }

                if (attributes && attributes.size() > 0) {
                    attributes.each {
                        def key = it.split("=",2)[0]?.trim()
                        def value = it.split("=",2)[1]?.trim()
                        if (key.contains("linktype")) {
                            "$key"('rdf:resource':value)
                        } else {
                            "$key"(value)
                        }
                    }
                }
            }
        }
        println "Creating work item ..."
        if (debug) {
            def smBuilder = new StreamingMarkupBuilder()
            println "========================"
            println "[Debug] Work Item: " + XmlUtil.serialize(smBuilder.bind(newWorkItem))
            println "========================"
        }
        gBuilder.encoding = "UTF-8"
        def workItemId
        //post the new work item
        try {
            method = new HttpPost(workItemCreateUrl)
            String newCommentString = gBuilder.bind(newWorkItem)
            method.setEntity(new StringEntity(newCommentString))
            method.setHeader("Accept", "application/x-oslc-cm-change-request+xml")
            method.setHeader("Content-type", "application/x-oslc-cm-change-request+xml")
            createResult = client.execute(method)
            int statusCode = createResult.getStatusLine().getStatusCode()
            if (statusCode < 300 && statusCode >= 200) {
                def resp = createResult.getEntity().getContent()

                try {
                    def respXml = new XmlParser().parse(resp)
                    workItemId = respXml['dc:identifier']?.text()
                }
                catch (Exception e) {
                    System.out.println(resp)
                    throw e
                }
                println "Successfully created work item $workItemId"
                apTool.setOutputProperty("workItemId", workItemId)
            }
            else {
                println "Failed to create work item"
                throw new Exception ("[Error] Failed to create work item: \n ${createResult.getEntity().getContent().text}")
            }
        }
        finally {
            if (method != null) {
                method.releaseConnection()
            }
            apTool.storeOutputProperties()
        }

        if(comment && comment.trim().length() > 0) {
            AddComment ac = new AddComment()
            ac.url = url
            ac.username = username
            ac.password = password

            ac.projectName = projectName
            ac.workItemId = workItemId
            ac.comment = comment
            ac.props = props
            ac.requestId = requestId
            ac.appProcId = appProcId
            ac.compProcId = compProcId
            ac.procId = procId
            ac.addCommentUrl = addCommentUrl
            ac.serverUrl = serverUrl

            ac.execute()
        }
    }
}
