/*
* 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.test.mstest
import org.xml.sax.Attributes;
import org.xml.sax.InputSource
import org.xml.sax.helpers.DefaultHandler
import java.text.SimpleDateFormat
import javax.xml.parsers.SAXParserFactory

class MSTestHandler extends DefaultHandler {
    final SimpleDateFormat vs2010Date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");

    def testTable = [:]
    def testListIdToName = [:]
    def suiteToTestResults = [:]

    def filename

    def inUnitTest
    def inUnitTestResult
    def inMessage

    def testName
    def testResult
    def testDuration
    def testId
    def testTestListId

    def testListId
    def testListName

    def unitTestId
    def unitTestClassName
    def unitTestName

    def messages = []
    def currentText = new StringBuilder()

    MSTestHandler(def filename) {
        this.filename = filename
    }

    void startElement(String ns, String localName, String qName, Attributes attrs) {
        switch (qName) {
            case 'TestList':
                testListName = attrs.getValue('name')
                testListId = attrs.getValue('id')
                break

            case 'UnitTest':
                inUnitTest = true
                unitTestId = attrs.getValue('id')
                break

            case 'UnitTestResult':
                inUnitTestResult = true
                testId = attrs.getValue('testId')
                testName = attrs.getValue('testName')
                testResult = attrs.getValue('outcome')
                testTestListId = attrs.getValue('testListId')
                String durationStr;
                durationStr = attrs.getValue('duration')
                if (!durationStr) {
                    def startValue = attrs.getValue('startTime');
                    if (startValue) {
                        String startTime = attrs.getValue('startTime').replace('T',' ').substring(0,23)
                        String endTime = attrs.getValue('endTime').replace('T', ' ').substring(0,23)
                        def startDate = vs2010Date.parse(startTime)
                        def endDate = vs2010Date.parse(endTime)
                        testDuration = endDate.getTime() - startDate.getTime()
                    }
                    else {
                        // aborted / not executed
                        testDuration = 0
                    }
                }
                else {
                    testDuration = durationStr
                }
                break

            case 'Message':
                if (inUnitTestResult) {
                    inMessage = true
                }
                break

            case 'TestMethod':
                if (inUnitTest) {
                    unitTestClassName = attrs.getValue('className')
                    unitTestName = attrs.getValue('name')
                }
                break
        }
    }

    void endElement(String ns, String localName, String qName) {
        switch (qName) {
            case 'TestList':
                testListIdToName[testListId] = testListName
                break

            case 'UnitTest':
                testTable[unitTestId] = new UnitTest(unitTestName, unitTestClassName)
                inUnitTest = false
                break

            case 'UnitTestResult':
                def className = testTable[testId].className
                def testTestListName = testListIdToName[testTestListId]
                def testResultsList = suiteToTestResults[testTestListName]
                if (!testResultsList) {
                    testResultsList = []
                    suiteToTestResults[testTestListName] = testResultsList
                }
                testResultsList << new UnitTestResult(testName, className, testResult, testDuration, messages)
                inUnitTestResult = false
                messages = []
                break

            case 'Message':
                if (inUnitTestResult) {
                    messages << currentText.toString()
                    currentText = new StringBuilder()
                    inMessage = false;
                }
                break
        }
    }

    void characters(char[] ch, int start, int length) {
        if (inMessage) {
            currentText.append(ch, start, length)
        }
    }

    def readTests() {
        def reader = SAXParserFactory.newInstance().newSAXParser().XMLReader
        def suiteFile = (filename instanceof File) ? filename : new File(filename)
        suiteFile.withInputStream { stream ->
            reader.setContentHandler(this)
            reader.parse(new InputSource(stream))
        }
        return suiteToTestResults
    }
}
