package com.urbancode.air.plugin.accuwork

import com.urbancode.air.ExitCodeException

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

    //**************************************************************************
    // INSTANCE
    //**************************************************************************
    List<String> bugIdList
    String comment
    boolean usingChangeSets = false;
    
    public void execute() {
        boolean error = false;
        
        login()
        
        try {
            usingChangeSets = bugIdList ? bugIdList.isEmpty() : true
            if (usingChangeSets) {
                String changesXml = getChangeSetXml()
                parseChangeSets(changesXml)
                
                if (!changes.isEmpty()) {
                    for (FileChange change : changes) {
                        def root = queryDB(null, change)
                        String xml = genXml(root)
                        sendXml(change.issueId, xml)
                    }
                }
                else {
                    println "No issues found"
                }
            }
            else {
                for (String bugId : bugIdList) {
                    def root = queryDB(bugId, null)
                    String xml = genXml(root)
                    
                    // We have to parse and send xml for each bug because we don't know 
                    // what other fields may be present. Any fields that are not added to
                    // the upload will also remove them from the actual issue
                    sendXml(bugId, xml)
                }
            }
        }
        catch (ExitCodeException e) {
            println e.getMessage()
            error = true
        }
        finally {
            logout()
            
            if (error) {
                System.exit(1)
            }
        }
        
    }
    
    private def queryDB(String bugId, FileChange change) {
        // query existing bug information.
        if (usingChangeSets) {
            bugId = change.issueId
            issueDB = change.depotName
        }
        
        print("\nQuerying Information for BUG[${bugId}] from depot ${issueDB}.")
        
        ByteArrayOutputStream bouts = new ByteArrayOutputStream();
        // generate query.xml file.
        File queryFile = File.createTempFile("accurev_bugreport", "xml");
        OutputStream outs = new FileOutputStream(queryFile);
        
        String xmlString = "<queryIssue issueDB=\"" + issueDB + "\" 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();
                }
                
                println bouts.toString();
            }
            
            return parseXml(bouts.toString())
        }
        finally {
            queryFile.delete();
        }
    }
    
    private def parseXml(def xml) {
        def rootNode = new XmlParser().parseText(xml)

        Node newRoot = new Node(null, "modifyIssue")
        
        NodeList nodeList = rootNode.issue
        Node parent = nodeList[0]
        
        newRoot.append(parent)
        
        List<Node> children = new ArrayList(parent.children())
        boolean foundDescription = false;
        
        for (int i = 0; i < children.size(); i++) {
            Node child = children[i]
        
            if (child.name() == "transNum") {
                println "Removing transNum node"
                parent.remove(child)
            }
            
            if (child.name() == "description") {
                foundDescription = true;
                String newComment = child.text() + " " + comment
                println "Setting description to " + newComment
                child.setValue(newComment)
            }
        }
        
        if (!foundDescription) {
            String descriptionId = findFieldId("description")
            
            if (descriptionId) {
                Map<String, String> attributes = new HashMap<String, String>();
                attributes.put("fid", descriptionId)
                
                Node child = new Node(parent, "description", attributes, comment);
            }
            else {
                println "No description field found in the schema for AccuRev issues. Unable to add comment to issue."
            }
        }
        
        return newRoot
    }
    
    private String findFieldId(String fieldName) {
        String result;
        
        String xml
        def command = [scmCommand, "getconfig", "-p", issueDB, "-r", "schema.xml"]
        ch.runCommand("Finding field id for ${fieldName}", command) {Process proc ->
            proc.out.close()
            proc.consumeProcessErrorStream(System.out)
            xml = proc.text
        }
        
        new XmlSlurper().parseText(xml).field.each { item ->
            if (item.@name.text() == fieldName) {
                result = item.@fid.text()
            }
        }
        
        return result
    }
    
    private String genXml(def root) {
        def xmlBuilder = new groovy.xml.StreamingMarkupBuilder(useDoubleQuotes: true);
        xmlBuilder.encoding = "UTF-8"
        def xmlOut = xmlBuilder.bind{
            mkp.xmlDeclaration()
            'modifyIssue'('issueDB':"$issueDB", 'useAlt':"false"){
                'issue'{
                    root.issue[0].children().each { child ->
                        String name = child.name()
                        String id = child.@fid
                        String text = child.text()
                        
                        "$name"('fid':"$id", text)
                    }
                }
            }
        }
        println xmlOut.toString()
        return xmlOut.toString()
    }
    
    private void sendXml(String bugId, String xml) {
        // generate query.xml file.
        File queryFile = File.createTempFile("accurev_bugreport", "xml");
        
        try {
            OutputStream outs = new FileOutputStream(queryFile);
            outs.write(xml.getBytes());
            outs.close()
            
            def command = [scmCommand, "xml", "-l", queryFile.getAbsolutePath()]
            ch.runCommand("Sending changes for bug " + bugId + " to issueDB " + issueDB, command)
        }
        finally {
            queryFile.delete()
        }
    }
}