package com.urbancode.air.plugin.bugs;

import groovy.util.slurpersupport.GPathResult
import java.util.zip.ZipEntry
import java.util.zip.ZipFile
import com.urbancode.commons.xml.XPathUtils
import org.w3c.dom.Document
import org.w3c.dom.Element
import com.urbancode.commons.xml.DOMUtils

public class FindBugsHandler extends org.xml.sax.helpers.DefaultHandler {

    def tagNameStack = new Stack()
    def findingId
    def findingFile
    def findingLine
    def findingName
    def findingSeverity
    def findingDesc
    def addFinding

    Document messagesXmlDoc    
    
    Map<String, String> namesToDescriptions = new HashMap<String, String>()

    FindBugsHandler(def addFinding) {
        this.addFinding = addFinding
    }

    void startElement(String ns, String localName, String qName, org.xml.sax.Attributes attribs) {
        switch (qName) {
            case 'BugInstance':
                findingId = attribs.getValue('instanceHash')
                findingName = attribs.getValue('type')
                findingSeverity = attribs.getValue('category')
                findingLine = null
                break

            case 'ShortMessage':
                findingDesc = new StringBuilder()
                break

            case 'SourceLine':
                if (tagNameStack.peek() == 'Class') {
                    findingFile = attribs.getValue('sourcepath')
                }
                else if (tagNameStack.peek() == 'BugInstance' && findingLine == null) {
                    findingLine = attribs.getValue('start')
                }
                break
        }
        tagNameStack.push(qName)
    }

    void characters(char[] ch, int start, int length) {
        if (tagNameStack.peek() == 'ShortMessage') {
            String desc = getDescriptionForName(findingName)
            if (desc) {
                findingDesc.append(desc);
            }
            else {
                findingDesc.append(ch, start, length)
            }
        }
    }

    void endElement(String ns, String localName, String qName) {
        tagNameStack.pop()
        switch (qName) {
            case 'BugInstance':
                addFinding(findingId, findingFile, findingLine, findingName, findingSeverity, findingDesc, '')
                break
        }
    }
    
    private String getDescriptionForName(String name) {
        String result 
        if (!messagesXmlDoc) {
            messagesXmlDoc = DOMUtils.loadDocument(getClass().getResourceAsStream('/messages.xml'))
        }
        result = namesToDescriptions.get(name)
        if (!result && messagesXmlDoc) {
            XPathUtils xpath = new XPathUtils()
            String detailsLocator = "//BugPattern[@type=${xpath.quotedXPathString(name)}]/Details"
            result = xpath.getXPathText(messagesXmlDoc.documentElement, detailsLocator)
            if (result) {
                result = result.replaceAll("</?p>", "").replaceAll(" +",  " ").replaceAll("[\n\r\t]", " ").trim();
                namesToDescriptions.put(name, result)
            }
        }
        return result;
    }
}
