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.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity

import com.urbancode.air.*
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import com.urbancode.commons.util.IO
import com.urbancode.ubuild.plugin.rtcworkitems.RTCWorkItemHelper


public class AddComment extends AutomationBase {
    
    //*****************************************************************************************************************
    // CLASS
    //*****************************************************************************************************************
    
    //*****************************************************************************************************************
    // INSTANCE
    //*****************************************************************************************************************
    
    String workItemProperty = "workItems"
    boolean chnglgComments
    String comment
    
    public void execute(props, apTool) {
        addComment(props, apTool);
    }
    
    public void addComment(props, apTool) {
        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        HttpClient client= builder.buildClient()
        
        XTrustProvider.install();
        def rtcHelper = new RTCWorkItemHelper(props, apTool);
        def catalogurl = rtcHelper.getCatalogUrl(client);
        rtcHelper.authenticateRTCUser(catalogurl, client);
        def servicesUrl = rtcHelper.getServicesUrl(catalogurl, client);
        def workItemUrl = rtcHelper.getWorkItemUrl(servicesUrl, client);
        
        try {
            def changesXml = getChangeSets()
            System.out.println "Examining source changes for work items..."
            def defectIdSet = [] as Set
            def defectIdToChangeSetListMap = [:] as Map
            new XmlSlurper().parseText(changesXml)."change-set".each { element ->
                if (element.'properties'.size() > 0) {
                    element.'properties'.'property'.each {
                        if (workItemProperty.equalsIgnoreCase(it.'name'.text())) {
                            it.'value'.text().split(',').each {
                                defectIdSet << it
                            }
                        }
                    } 
                
                    defectIdSet.each { item ->
                        def currentCommentSet = defectIdToChangeSetListMap[item]?:[] as Set
                        currentCommentSet << element.'comment'.text()
                        defectIdToChangeSetListMap.put(item, currentCommentSet)
                    }
                }
            }
            if (defectIdSet.size() == 0) {
                println "No RTC work items were found in the source changes.";
            }
            else {
                println "${defectIdSet.size()} RTC work items were found in the source changes.";
                for (def defectId in defectIdSet) {
                    def defectData = null
                    HttpPost method = null
                    def createResult;
                    defectData = getWorkItemByIdentifier(defectId, workItemUrl, client);
                    if (!defectData) {
                        continue;
                    }
                    def defectXml = new XmlParser().parseText(defectData);
                    if (defectXml.attributes()[RTCWorkItemHelper.n_oslc_cm.'totalCount'].equals("1")) {
                        //lets add the comment 
                        def xmlBuilder = new groovy.xml.StreamingMarkupBuilder()
                        def changeLogText = defectIdToChangeSetListMap.get(defectId)
                        def workItemComment = (chnglgComments ? changeLogText.join(' ') + ' ' : "") + (comment ?: '')
                        println "Adding comment for work item ${defectId}: ${workItemComment}";
                        xmlBuilder.encoding = "UTF-8"
                        def newComment = {
                          mkp.xmlDeclaration()
                          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/')
                          rtc_cm.Comment{
                            dc.description(workItemComment);
                          }
                        }
                        //get the post url
                        def commentUrl = 
                            defectXml[RTCWorkItemHelper.n_oslc_cm.ChangeRequest][RTCWorkItemHelper.n_rtc_cm.comments][0]
                                     .attributes()[RTCWorkItemHelper.n_oslc_cm.'collref'];
                        //post the new comment
                        try {
                            method = new HttpPost(commentUrl);
                            String newCommentString = xmlBuilder.bind(newComment);
                            method.setEntity(new StringEntity(newCommentString));
                            method.addHeader("Accept", "application/x-oslc-cm-change-request+xml");
                            method.addHeader("Content-type", "application/x-oslc-cm-change-request+xml");
                            HttpResponse response = client.execute(method);
                            createResult = response.statusLine.statusCode
                            if (isGoodResponseCode(createResult)) {
                                println "Successfully added comment to work item $defectId";
                            }
                            else {
                                println "Failed to add comment to work item $defectId";
                                println method.getResponseBodyAsString();
                                System.exit(1);
                            }
                        }
                        finally {
                            if (method != null) {
                                method.releaseConnection();
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace()
            System.exit(1)
        }
    }
    
    private String getWorkItemByIdentifier(String identifier, String queryUrl, HttpClient client) {
        HttpGet queryMethod = null;
        String resp ="";
        try {
            queryMethod = new HttpGet(queryUrl + '.xml?oslc_cm.query=' + URLEncoder.encode('dc:identifier="' + identifier + '"', "UTF-8"));
            queryMethod.addHeader("Accept", "application/x-oslc-cm-change-request+xml");
            def result = client.execute(queryMethod);
            resp = IO.readText(result.entity.content)
        }
        finally {
            if (queryMethod != null) {
                queryMethod.releaseConnection();
            }
        }
        return resp;
    }
    
    private String getChangeSets() {
        def authToken = System.getenv("AUTH_TOKEN")
        int buildLifeId = Integer.parseInt(System.getenv("BUILD_LIFE_ID"))
        String webUrl = System.getenv("WEB_URL")
        webUrl += webUrl.endsWith("/") ? "" : "/"
        
        String changesRequestUrl = webUrl + "rest/buildlife/${buildLifeId}/sourcechanges"
        
        println "Getting source changes from server"
        
        HttpGet getMethod = new HttpGet(changesRequestUrl)
        if (authToken) {
            getMethod.addHeader("Authorization-Token", authToken)
        }
        
        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        HttpClient client = builder.buildClient()
        HttpResponse response = client.execute(getMethod)
        def responseCode = response.statusLine.statusCode
        InputStream responseStream = response.entity.content
        
        String changesXml = IO.readText(responseStream)
        
        if (!isGoodResponseCode(responseCode)) {
            throw new Exception("Failed to get build life source changes from the server: $changesXml")
        }
        
        getMethod.releaseConnection()
        
        return changesXml
    }
    
    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }
    
}

