package com.urbancode.air.plugin.accuwork

import java.util.List;
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

import com.urbancode.air.ExitCodeException

public class GetDetails extends AccuworkBase {
    
    //**************************************************************************
    // CLASS
    //**************************************************************************

    //**************************************************************************
    // INSTANCE
    //**************************************************************************
    
    private type
    private status
    private description
    
    public void execute() {
        boolean error = false
        
        login()
        
        try {
            String changesXml = getChangeSetXml()
            parseChangeSets(changesXml)
            
            for (FileChange change : changes) {
                queryDB(change)
            }
            
            if (!changes.isEmpty()) {
                String xml = genXml()
                sendPostRequest(xml)
            }
            else {
                println "No issues found"
            }
        }
        catch (ExitCodeException e) {
            println e.getMessage()
            error = true
        }
        finally {
            logout()
            
            if (error) {
                System.exit(1)
            }
        }
    }
    
    private void queryDB(FileChange change) {
        String bugId = change.issueId
        
        // query existing bug information.
        print("\nQuerying Information for BUG[${bugId}] from depot ${change.depotName}.")
        
        ByteArrayOutputStream bouts = new ByteArrayOutputStream();
        // generate query.xml file.
        File queryFile = File.createTempFile("accurev_bugreport", "xml");
        OutputStream outs = new FileOutputStream(queryFile);
        
        String xmlString = "<queryIssue issueDB=\"" + change.depotName + "\" useAlt=\"false\">1 == \"" + bugId + "\"</queryIssue>";
        
        outs.write(xmlString.getBytes());
        outs.close();
        
        try {
            def command = [scmCommand, "xml"]
            
            if (host) {
                command << "-H" << host
            }
            
            command << "-l" << queryFile.getAbsolutePath()
            
            ch.runCommand("Querying Database", command) { Process proc ->
                proc.out.close() // close stdin
                def out = new PrintStream(System.out, true);
                try {
                    proc.waitForProcessOutput(bouts, out) // forward stdout and stderr to autoflushing output stream
                }
                finally {
                    out.flush();
                }
            }
            
            parseXml(bouts.toString(), change)
        }
        finally {
            queryFile.delete();
        }
    }
    
    private void parseXml(def xml, FileChange change) {
        def rootNode = new XmlParser().parseText(xml)
        
        NodeList nodeList = rootNode.issue
        Node parent = nodeList[0]
        
        List<Node> children = new ArrayList(parent.children())
        
        for (int i = 0; i < children.size(); i++) {
            Node child = children[i]
            
            if (child.name() == "shortDescription") {
                change.name = child.text()
                change.description = child.text()
            }
            else if (child.name() == "description") {
                change.description = child.text()
            }
            else if (child.name() == "status") {
                change.status = child.text()
            }
            else if (child.name() == "type") {
                change.type = child.text()
            }
        }
    }
    
    private String genXml() {
        def xmlBuilder = new groovy.xml.StreamingMarkupBuilder();
        xmlBuilder.encoding = "UTF-8"
        def xmlOut = xmlBuilder.bind {
            mkp.xmlDeclaration()
            'issues'{
                changes.each { change ->
                    'issue'('issue-tracker':"AccuWork", 'id':change.issueId, 'change-id':change.changeId, 'repo-id':change.repoId) {
                        'name'(change.name)
                        'type'(change.type)
                        'status'(change.status)
                        'description'(change.description)
                        'url'(change.issueUrl)
                    }
                }
            }
        }
        return xmlOut.toString()
    }
    
    private void sendPostRequest(String xml) {
        def authToken = System.getenv("AUTH_TOKEN")
        String buildLifeId = System.getenv("BUILD_LIFE_ID")
        
        // construct the URL with property replacements
        String baseUrl = System.getenv("WEB_URL")
        
        baseUrl += baseUrl.endsWith("/") ? "" : "/"
        String url = baseUrl + "rest/buildlife/${buildLifeId}/issues"
        
        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 AccuWork issues. StatusCode: ${responseCode}")
        }
    }
}