package com.urbancode.air.plugin.analytics

import org.apache.commons.httpclient.HttpClient
import org.apache.commons.httpclient.UsernamePasswordCredentials
import org.apache.commons.httpclient.auth.AuthScope
import org.apache.commons.httpclient.methods.StringRequestEntity
import org.apache.commons.httpclient.methods.GetMethod
import org.apache.commons.httpclient.methods.PostMethod
import org.apache.commons.httpclient.params.HttpClientParams
import org.apache.commons.httpclient.protocol.Protocol
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory

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

public class XmlHelper {
    
    public void uploadResult(def reportFiles, String reportName, boolean includeDescription) {
        def buildLifeId = System.getenv("BUILD_LIFE_ID")
        // define a closure for parsing the Sonargraph output file and writing out air XML format
        def reportXml = new java.io.StringWriter()
        new groovy.xml.MarkupBuilder(reportXml).
        "analytics"("name":reportName, "buildLifeId":buildLifeId, "type":"Sonargraph") {
            reportFiles.each { reportFile ->
                def addFinding = { findingId, findingFile, findingLine, findingName, findingSeverity, findingDesc, findingStatus ->
                    "finding"() {
                        "id"(findingId)
                        "file"(findingFile)
                        "line"(findingLine)
                        "name"(findingName)
                        "severity"(findingSeverity)
                        if (includeDescription) {
                            "description"(findingDesc)
                        }
                        "status"(findingStatus)
                    }
                }
                
                def handler = new SonargraphHandler(addFinding)
                def reader = javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().XMLReader
                reader.setContentHandler(handler)
                def inputStream = new FileInputStream(reportFile)
                reader.parse(new org.xml.sax.InputSource(inputStream))
            }
        }
        
        if (reportXml) {
            // uncomment to debug content sent to the server
            // println reportXml
            String baseUrl = System.getenv("WEB_URL")
            baseUrl += baseUrl.endsWith("/") ? "" : "/"
            def encodedReportName = URLEncoder.encode(reportName)
            String url = baseUrl + "rest/buildlife/${buildLifeId}/sourceanalytics?reportName=${encodedReportName}"
            sendPostRequest(url, reportXml.toString())
        }
        else {
            println 'No report was able to be generated'
        }
    }
    
    public void uploadSummariesOnly(def reportFiles, String reportName, boolean includeDescription) {
        def buildLifeId = System.getenv("BUILD_LIFE_ID")
        // define a closure for parsing the Sonargraph output file and writing out air XML format
        def reportXml = new java.io.StringWriter()
        def summaryMap = [:]
        reportFiles.each { reportFile ->
            def addFinding = { findingId, findingFile, findingLine, findingName, findingSeverity, findingDesc, findingStatus ->
                def summary = summaryMap.get(findingName)
                if (!summary) {
                    summary = new SonargraphSummary(findingName, findingDesc, findingSeverity)
                    summaryMap.put(findingName, summary)
                }
                summary.count++
            }
            
            def handler = new SonargraphHandler(addFinding)
            def reader = javax.xml.parsers.SAXParserFactory.newInstance().newSAXParser().XMLReader
            reader.setContentHandler(handler)
            def inputStream = new FileInputStream(reportFile)
            reader.parse(new org.xml.sax.InputSource(inputStream))
        }
        def builder = new groovy.xml.MarkupBuilder(reportXml)
        builder."analytics"("name": reportName, "buildLifeId": buildLifeId, "type": "Sonargraph") {
            summaryMap.each { summaryEntry ->
                SonargraphSummary summary = summaryEntry.value
                "finding"() {
                    "name"(summary.name)
                    "severity"(summary.severity)
                    "count"(summary.count)
                    if (includeDescription) {
                        "description"(summary.description)
                    }
                }
            }
        }
        
        if (reportXml) {
            // uncomment to debug content sent to the server
            // println reportXml
            String baseUrl = System.getenv("WEB_URL")
            baseUrl += baseUrl.endsWith("/") ? "" : "/"
            def encodedReportName = URLEncoder.encode(reportName)
            String url = baseUrl + "rest/buildlife/${buildLifeId}/sourceanalyticsummaries?reportName=${encodedReportName}"
            sendPostRequest(url, reportXml.toString())
        }
        else {
            println 'No report was able to be generated'
        }
    }
    
    //------------------------------------------------------------------------------
    // Construct XML message and upload
    //------------------------------------------------------------------------------
    private void sendPostRequest(String url, String xml) {
        println "Sending request to $url"
        ProtocolSocketFactory socketFactory = new OpenSSLProtocolSocketFactory()
        Protocol https = new Protocol("https", socketFactory, 443)
        Protocol.registerProtocol("https", https)
    
        PostMethod postMethod = new PostMethod(url)
        def authToken = System.getenv("AUTH_TOKEN")
        if (authToken) {
            postMethod.setRequestHeader("Authorization-Token", authToken)
            postMethod.setRequestHeader("Content-Type", "application/xml")
        }
    
        postMethod.setRequestEntity(new StringRequestEntity(xml));
    
        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("Failed to upload Sonargraph report. StatusCode: ${responseCode}")
        }
    }
    
    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }

}