/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* (c) Copyright IBM Corporation 2012, 2014. 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.findbugs

import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.DefaultHttpClient

import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import com.urbancode.commons.util.IO

public class FindBugsXmlHelper {
    
    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
            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 FindBugs 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 FindBugsSummary(findingName, findingDesc, findingSeverity)
                    summaryMap.put(findingName, summary)
                }
                summary.count++
            }
            
            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))
        }
        def builder = new groovy.xml.MarkupBuilder(reportXml)
        builder."analytics"("name": reportName, "buildLifeId": buildLifeId, "type": "FindBugs") {
            summaryMap.each { summaryEntry ->
                FindBugsSummary 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"
        HttpClientBuilder clientBuilder = new HttpClientBuilder();
        clientBuilder.setTrustAllCerts(true);
        DefaultHttpClient client = clientBuilder.buildClient();
        
        HttpPost postMethod = new HttpPost(url);
        def authToken = System.getenv("AUTH_TOKEN")
        if (authToken) {
            postMethod.setHeader("Authorization-Token", authToken)
            postMethod.setHeader("Content-Type", "application/xml")
        }
       
        postMethod.setEntity(new StringEntity(xml));
    
        def httpResponse = client.execute(postMethod)
        def responseCode = httpResponse.getStatusLine().getStatusCode()
        if (isGoodResponseCode(responseCode)) {
            IO.copy(postMethod.getEntity().getContent(), System.out)
            println ""
        }
        else {
            IO.copy(postMethod.getEntity().getContent(), System.err)
            throw new RuntimeException("Failed to upload FindBugs report. StatusCode: ${responseCode}")
        }
    }
    
    private boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }

}