package com.urbancode.air.plugin.automation;

import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.protocol.*

import com.urbancode.commons.util.IO
import com.urbancode.commons.util.https.OpenSSLProtocolSocketFactory

import java.util.regex.Pattern

public class XMLHelper {
    
    String issuePattern
    def issueIdSet = [] as Set
    def issueIdToChangeSetListMap = [:]
    
    public XMLHelper(String issuePattern) {
        this.issuePattern = issuePattern
    }
    
    public 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 "\nGetting source changes from server"
        ProtocolSocketFactory socketFactory = new OpenSSLProtocolSocketFactory()
        Protocol https = new Protocol("https", socketFactory, 443)
        Protocol.registerProtocol("https", https)
        
        GetMethod getMethod = new GetMethod(changesRequestUrl)
        if (authToken) {
            getMethod.setRequestHeader("Authorization-Token", authToken)
        }
        
        String changesXml
        
        try {
            HttpClient client = new HttpClient()
            def responseCode = client.executeMethod(getMethod)
            InputStream responseStream = getMethod.getResponseBodyAsStream()
            
            changesXml = IO.readText(responseStream)
            if (!isGoodResponseCode(responseCode)) {
                throw new Exception("Failed to get build life source changes from the server: $changesXml")
            }
        }
        finally {
            getMethod.releaseConnection()
        }
        
        parseChangesets(changesXml)
        
        return changesXml
    }
    
    private void parseChangesets(String changesXml) {
        if (!changesXml.contains("change-set")) {
            println "No changes detected."
        }
        else {
            println "Parsing Changelog"
            
            new XmlSlurper().parseText(changesXml)."change-set".each { changeSetElem ->
                def issueIdPattern = java.util.regex.Pattern.compile(issuePattern)
                def issueMatcher = issueIdPattern.matcher(changeSetElem.'comment'.text());
                
                while (issueMatcher?.find()) {
                    def issueId
                    if (issueMatcher.groupCount() > 0 ) {
                        // they specified a '(...)' group within the pattern, use that as the issue id
                        issueId = issueMatcher.group(1)
                    }
                    else {
                        // use the whole matching substring as the issue id
                        issueId = issueMatcher.group()
                    }
                    
                    println "Found issue identifier in change comment: $issueId"
                    issueIdSet.add(issueId)
                    def changeSetList = issueIdToChangeSetListMap[issueId]
                    if (!changeSetList) {
                        changeSetList = []
                        issueIdToChangeSetListMap[issueId] = changeSetList
                    }
                    
                    def changeId = changeSetElem."change-id"?.text() ? changeSetElem."change-id".text() : changeSetElem."id".text()
                    changeSetList.add(changeId)
                }
            }
        }
    }
    
    private void sendPost(String issuesXml) {
        int buildLifeId = Integer.parseInt(System.getenv("BUILD_LIFE_ID"))
        def authToken = System.getenv("AUTH_TOKEN")
        String webUrl = System.getenv("WEB_URL")
        webUrl += webUrl.endsWith("/") ? "" : "/"
        
        String postUrl = webUrl + "rest/buildlife/${buildLifeId}/issues"
        
        println "Uploading Issues xml"
        //println issuesXml
        
        ProtocolSocketFactory socketFactory = new OpenSSLProtocolSocketFactory()
        Protocol https = new Protocol("https", socketFactory, 443)
        Protocol.registerProtocol("https", https)
 
        PostMethod postMethod = new PostMethod(postUrl)
        try {
            if (authToken) {
                postMethod.setRequestHeader("Authorization-Token", authToken)
                postMethod.setRequestHeader("Content-Type", "application/xml")
            }
            
            postMethod.setRequestEntity(new StringRequestEntity(issuesXml));
            
            HttpClient client = new HttpClient()
            
            def responseCode = client.executeMethod(postMethod)
            InputStream responseStream = postMethod.getResponseBodyAsStream()
            if (isGoodResponseCode(responseCode)) {
                IO.copy(responseStream, System.out)
                println ""
            }
            else {
                IO.copy(responseStream, System.err)
                throw new RuntimeException("JIRA results upload to server failed. StatusCode: ${responseCode}")
            }
        }
        finally {
            postMethod.releaseConnection()
        }
    }
    
    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }
}