package com.urbancode.air.plugin.bugs

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 FindBugs 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":"FindBugs") {
            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 FindBugsHandler(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
            sendPostRequest(reportName, reportXml.toString())
        }
        else {
            println 'No report was able to be generated'
        }
    }
    
    //------------------------------------------------------------------------------
    // Construct XML message and upload
    //------------------------------------------------------------------------------
    private void sendPostRequest(String reportName, String xml) {
        def authToken = System.getenv("AUTH_TOKEN")
        def buildLifeId = System.getenv("BUILD_LIFE_ID")
        
        // construct the URL with property replacements
        String baseUrl = System.getenv("WEB_URL")
        
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        def encodedReportName = URLEncoder.encode(reportName)
        String url = baseUrl + "rest/buildlife/${buildLifeId}/sourceanalytics?reportName=${encodedReportName}"
        
        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)
        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 FindBugs report. StatusCode: ${responseCode}")
        }
    }
    
    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }

}