/*
* 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.
*/
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 org.codehaus.jettison.json.JSONArray
import org.codehaus.jettison.json.JSONObject

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

void getReportParams(Properties stepProps, JSONArray jsonParams, JSONObject query) {
    JSONArray jsonCriteriaArray = query.optJSONArray('criteria')
    if (jsonCriteriaArray) {
        for (int criteriaIndex=0; criteriaIndex<jsonCriteriaArray.length(); criteriaIndex++) {
            JSONObject jsonCriteria = jsonCriteriaArray.getJSONObject(criteriaIndex);
            if (jsonCriteria.has('paramName')) {
                def paramName = jsonCriteria.getString('paramName')
                def paramValue = stepProps.getProperty('params/' + paramName);
                JSONObject jsonParam = new JSONObject()
                jsonParam.put("name", paramName)
                if (jsonCriteria.getString('type') == 'in') {
                    JSONArray jsonValues = new JSONArray()
                    if (paramValue) {
                        for (String splitValue : paramValue.split('[\r\n]+')) {
                            jsonValues.put(splitValue)
                        }
                    }
                    jsonParam.put("value", jsonValues)
                }
                else {
                    jsonParam.put("value", paramValue)
                }
                jsonParams.put(jsonParam)
            }
        }
    }
    if (query.has('joins')) {
        JSONArray jsonJoins = query.getJSONArray('joins')
        for (int joinIndex=0; joinIndex<jsonJoins.length(); joinIndex++) {
            JSONObject jsonJoin = jsonJoins.getJSONObject(joinIndex)
            getReportParams(stepProps, jsonParams, jsonJoin.getJSONObject('query'))
        }
    }
}

final AirPluginTool airPluginTool = new AirPluginTool(this.args[0], this.args[1]);
final Properties stepProps = airPluginTool.getStepProperties()
final File workDir = new File('.').canonicalFile
final String osName = System.getProperty('os.name').toLowerCase(Locale.US)
final boolean windows = (osName =~ /windows/)

def urbancodeReportName = stepProps['urbancodeReportName']
def outputFile = new File(stepProps['outputFile'])
def outputFormat = stepProps['outputFormat']

def authToken = System.getenv('AUTH_TOKEN')
URI uri = URI.create(System.getenv("WEB_URL"))
def reportUrl = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath() +
        "/rest2/reporting/reports/${urbancodeReportName}", uri.getQuery(), uri.getFragment()).toString()
def reportOuputUrl = reportUrl + "/output"

assert !workDir.isFile() : "Working directory ${workDir} is a file!"
workDir.mkdirs()
outputFile.delete()

println "Running ${urbancodeReportName} and sending results to ${outputFile} as ${outputFormat}"

def jsonParams = new JSONArray()
println "Report Info URL: ${reportUrl}"
HttpGet getMethod = new HttpGet(reportUrl)
try {
    if (authToken) {
        getMethod.addHeader("Authorization-Token", authToken)
    }
    getMethod.addHeader("Content-Type", "application/json")
    getMethod.addHeader("Accept", "application/json")
    
    HttpClientBuilder builder = new HttpClientBuilder()
    builder.setTrustAllCerts(true)
    HttpClient client = builder.buildClient()
    
    HttpResponse response = client.execute(getMethod)
    def responseCode = response.statusLine.statusCode
    if (responseCode >= 200 && responseCode < 300) {
        InputStream body = response.entity.content
        String responseString = IO.readText(body)
        def jsonReport = new JSONObject(responseString)
        def jsonQuery = jsonReport.get('query')
        getReportParams(stepProps, jsonParams, jsonQuery)
    }
    else {
        throw new Exception("Getting report information failed with response code: " + responseCode)
    }
}
finally {
    getMethod.releaseConnection()
}

println "Report Output URL: ${reportOuputUrl}"
println "Parameters: ${jsonParams}"

HttpPost postMethod = new HttpPost(reportOuputUrl)
try {
    if (authToken) {
        postMethod.addHeader("Authorization-Token", authToken)
    }
    postMethod.addHeader("Content-Type", "application/json")
    if ('CSV'.equals(outputFormat)) {
        postMethod.addHeader("Accept", "text/csv")
    }
    else {
        postMethod.addHeader("Accept", "application/json")
    }
    postMethod.setEntity(new StringEntity(jsonParams.toString(), "application/json", "UTF-8"));
    
    HttpClientBuilder builder = new HttpClientBuilder()
    builder.setTrustAllCerts(true)
    HttpClient client = builder.buildClient()
    
    HttpResponse response = client.execute(postMethod)
    def responseCode = response.statusLine.statusCode
    if (responseCode >= 200 && responseCode < 300) {
        def writer = new BufferedWriter(new FileWriter(outputFile))
        try {
            if ('CSV'.equals(outputFormat)) {
                writer << response.entity.content
            }
            else { // HTML
                InputStream body = response.entity.content
                String responseString = IO.readText(body)
                def json = new JSONObject(responseString)
                writer << '<html><head></head><body><table><thead><tr>'
                // write column headers
                def jsonColumns = json.getJSONArray('columns')
                for (int columnIndex=0; columnIndex<jsonColumns.length(); columnIndex++) {
                    writer << '<th>' + jsonColumns.getString(columnIndex).replace("<", "&lt;") + '</th>'
                }
                writer << '</tr></thead><tbody>'
                // write content
                def jsonResults = json.getJSONArray('results')
                for (int resultIndex=0; resultIndex<jsonResults.length(); resultIndex++) {
                    writer << '<tr>'
                    def jsonResultValues = jsonResults.getJSONArray(resultIndex)
                    for (int valueIndex=0; valueIndex<jsonResultValues.length(); valueIndex++) {
                        writer << '<td>' + jsonResultValues.getString(valueIndex).replace("<", "&lt;") + '</td>'
                    }
                    writer << '</tr>'
                }
                writer << '</tbody></table></body></html>'
            }
            writer.flush()
        }
        finally {
            writer.close()
        }
        println "Report output completed"
    }
    else {
        throw new Exception("Running report failed with response code: " + responseCode)
    }
}
finally {
    postMethod.releaseConnection()
}