namespace rooibos
    ' @ignore
    namespace Coverage
        function reportCodeCoverage() as void

            if m.global._rbs_ccn = invalid then
                ? "There was no rooibos code coverage component - not generating coverage report"
                return
            end if
            t = createObject("roTimespan")
            ? ""
            ? "...Generating code coverage report"
            ? ""
            m.global._rbs_ccn.save = true
            cc = m.global._rbs_ccn
            expectedMap = cc.expectedMap
            filePathMap = cc.filePathMap
            resolvedMap = cc.resolvedMap

            hitFiles = []
            missFiles = []
            allLinesCount = 0
            allLinesHit = 0
            for each key in expectedMap
                filename = filePathMap[key]
                expectedCount = expectedMap[key].count()
                allLinesCount += expectedCount
                if expectedCount > 0 then
                    if resolvedMap[key] <> invalid then
                        resolvedCount = resolvedMap[key].count()
                        allLinesHit += resolvedCount
                        if resolvedCount = 0 then
                            resolvedPercent = 0
                        else
                            resolvedPercent = (resolvedCount / expectedCount) * 100
                        end if
                        hitFiles.push({ percent: resolvedPercent, text: filename + ": " + str(resolvedPercent).trim() + "% (" + strI(resolvedCount).trim() + "/" + strI(expectedCount).trim() + ")" })
                    else
                        missFiles.push(filename + ": MISS!")
                    end if
                else
                    missFiles.push(filename + ": MISS!")
                end if
            end for
            if allLinesHit = 0 then
                allLinesPercent = 0
            else
                allLinesPercent = (allLinesHit / allLinesCount) * 100
            end if
            ? ""
            ? ""
            ? "+++++++++++++++++++++++++++++++++++++++++++"
            ? "Code Coverage Report"
            ? "+++++++++++++++++++++++++++++++++++++++++++"
            ? ""
            ? "Total Coverage: " ; str(allLinesPercent).trim() ; "% (" ; strI(allLinesHit).trim() ; "/" + strI(allLinesCount).trim() ; ")"
            ? "Files: " ; resolvedMap.count(); "/" ; expectedMap.count()
            ? ""
            ? "HIT FILES"
            ? "---------"
            hitFiles.SortBy("percent")
            for i = 0 to hitFiles.count() - 1
                ? hitFiles[i].text
            end for
            ? ""
            ? "MISSED FILES"
            ? "------------"
            for i = 0 to missFiles.count() - 1
                ? missFiles[i]
            end for
            ? ""
            ? "+++++++++++++++++++++++++++++++++++++++++++"
            ? "Code Coverage Report Complete"; t.totalMilliseconds(); "ms"
            ? "+++++++++++++++++++++++++++++++++++++++++++"
        end function

        function createLCovOutput(logToConsole = true as boolean) as string
            ? "Generating lcov.info file..."

            cc = m.global._rbs_ccn
            expectedMap = cc.expectedMap
            filePathMap = cc.filePathMap
            resolvedMap = cc.resolvedMap

            results = []

            for each module in filePathMap.items()
                buffer = ""
                moduleNumber = module.key
                filePath = module.value
                packageName = "."

                relativePath = filePath.replace("pkg:", packageName)
                sanitizedPath = relativePath.replace("\\", "/")

                buffer += "TN:" + chr(10)
                buffer += "SF:" + sanitizedPath + chr(10)

                for each expected in expectedMap[moduleNumber]
                    lineNumber = val(expected)
                    SHIFT = 1

                    if resolvedMap[moduleNumber] <> invalid and resolvedMap[moduleNumber].doesExist(expected) then
                        buffer += "DA:" + str(lineNumber + SHIFT).trim() + "," + str(resolvedMap[moduleNumber][expected]).trim() + chr(10)
                    else
                        buffer += "DA:" + str(lineNumber + SHIFT).trim() + ",0" + chr(10)
                    end if
                end for

                buffer += "LF:" + str(expectedMap[moduleNumber].count()).trim() + chr(10)

                if resolvedMap[moduleNumber] <> invalid then
                    buffer += "LH:" + str(resolvedMap[moduleNumber].count()).trim() + chr(10)
                else
                    buffer += "LH:0" + chr(10)
                end if

                buffer += "end_of_record"
                if logToConsole then
                    ? buffer
                    ' When logging to the console it is very possible to flood the buffer and cause the application to exit.
                    ' Sleep for a short amount of time so as to give console scrapers time to empty the buffer
                    sleep(30)
                else
                    results.push(buffer)
                end if
            end for

            return results.join(chr(10))
        end function

        function printLCovInfo()

            ?
            ? "+++++++++++++++++++++++++++++++++++++++++++"
            ? "LCOV.INFO FILE"
            ? "+++++++++++++++++++++++++++++++++++++++++++"
            ?
            ? "+-=-coverage:start"
            rooibos.coverage.createLCovOutput()
            ? "+-=-coverage:end"
        end function

    end namespace
end namespace
