-- AgXML.escapeNodeTextString is more correct, but not enough to justify
-- the dependency on the XML toolkit and namespace.
-- Just cover the basic cases to avoid breaking HTML tags.
local function escapeForMarkup( s )
	local result = string.gsub( s, "&", "&amp;" )
	result = string.gsub( result, "<", "&lt;" )
	result = string.gsub( result, ">", "&gt;" )
	
	return result
end

--------------------------------------------------------------------------------

-- returns a pair of functions, one to which elements can be "written"
-- (a la print or AgDebugPrint) and one which causes all such lines to
-- written as a single multi-line dump.
local function outputAccumulator( outfunc )
	local lines = { "" }
	local emit = function( ... )
		local values = { ... }
		for i = 1, #values do
			values[ i ] = tostring( values[ i ] )
		end
		table.insert( lines, table.concat( values, "\t" ) )
	end
	
	local flush = function( ... )
		local result = table.concat( lines, "\n" )
		lines = { }
		if outfunc then
			outfunc( result )
		else
			return result
		end
	end
	
	return emit, flush
end

--------------------------------------------------------------------------------

local function plainTextEmitter( emit )
	return function( lineNumber, isActive, hitCount, lineText )
		local status = " "
		if isActive and hitCount then
			status = "*"
		elseif isActive then
			status = "-"
		elseif hitCount then
			status = "?"
		end
		emit( string.format( "% 5d %s %s\t", lineNumber, status, lineText ) )
	end
end

--------------------------------------------------------------------------------

-- DOCTYPE declaration to tell IE "render right -- I mean it, you stupid browser!"
local startHyperText = [[<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" --"http://www.w3.org/TR/REC-html40/strict.dtd"-->
<html>
<head><title>Coverage Example</title>
<style type="text/css">
table {
	padding: 0;
	margin: 0;
	spacing: 0;
	border-spacing: 0;
	border-collapse: collapse;
	font-size: 8pt
}
tr.h { background-color: #88ee88 }
tr.a { background-color: #ee8888 }
tr.x { background-color: #eeee88 }
tr.n { background-color: #eeeeee }
td.c { font-family: monospace; white-space: pre }
td.l {
	font-family: monospace;
	text-align: right;
	border-style:solid;
	border-color:black;
	border-width: 0 1px 0 0;
	border-color: #ffffff;
	padding: 0 20px 0 10px
}
</style>
</head>
<body>
<table>]]

local endHyperText = '</table></body></html>'

local function hyperTextEmitter( emit )
	return function( lineNumber, isActive, hitCount, lineText )
		local class = "n"
		if isActive and hitCount then
			class = "h"
		elseif isActive then
			class = "a"
		elseif hitCount then
			class = "x"
		end
		
		lineText = escapeForMarkup( lineText )
		
		emit( string.format(
			'<tr class="%s"><td class="l">%s</td><td class="l">%d</td><td class="c">%s</td></tr>',
			class, hitCount and tostring(hitCount) or "", lineNumber, lineText ) )
	end
end

--------------------------------------------------------------------------------

-- print the lines of a file with line numbers and coverage status
local function emitLuaMarkingActiveLines( emitter, filename, hits, active )
	local fh = io.open( filename, "r" )
	local i = 1
	for line in fh:lines() do
		emitter( i, active[ i ], hits[ i ], line )
		i = i + 1
	end
end

--------------------------------------------------------------------------------

local function formatHtmlReport( filepath, hitLines, activeLines )
	local source
	local emit, flush = outputAccumulator( function( text )
		source = startHyperText .. text .. endHyperText
	end )

	emitLuaMarkingActiveLines( hyperTextEmitter( emit ),
		filepath, hitLines, activeLines )
	flush()

	return source
end

--------------------------------------------------------------------------------

local function formatPlainTextReport( fn, filepath, hitLines, activeLines )
	emitLuaMarkingActiveLines( plainTextEmitter( fn ),
		filepath, hitLines, activeLines )
end

--------------------------------------------------------------------------------

return {
	formatHtmlReport = formatHtmlReport,
	formatPlainTextReport = formatPlainTextReport
}
