Mô đun:Election results

require('strict')
local p = {}
local political_party = require('Mô đun:Political party')
function p.main(frame)
	local args = require('Mô đun:Arguments').getArgs(frame)
	local index, headings, showtotal = {}, {}, {}
	local cols, rounds = 0, 1
	local winner, winner_votes = {0, 0}, {0, 0}
	local valid = {0, 0}
	local invalid = {tonumber(args.invalid) or 0, tonumber(args.invalid2) or 0}
	local majority = {tonumber(args.majority)}
	local majority2 = {tonumber(args.majority2)}
	local majoritypct = {tonumber(args.majoritypct)}
	local majoritypct2 = {tonumber(args.majoritypct2)}
	local totalvotes = {tonumber(args.totalvotes), tonumber(args.totalvotes2)}
	local electorate = {tonumber(args.electorate), tonumber(args.electorate2)}
	local turnout = {tonumber(args.turnout), tonumber(args.turnout2)}
	local seats = 0
	local seats_2 = 0
	local st1t = 0
	local st2t = 0
	local st3t = 0
	local st4t = 0
	local st5t = 0
	local totseats = 0
	local row, secondrow
	local tracking = 
	local max_rows = 0
	-- helper functions
	local lang = mw.getContentLanguage()
	local function fmt(n)
		return n and tonumber(n) and lang:formatNum(tonumber(n)) or nil
	end
	local function pct(n, d)
		n, d = tonumber(n), tonumber(d)
		if n and d and d > 0 then
			return string.format('%.2f', n / d * 100)
		end
		return '–'
	end
	local function tonumdash(s)
		if s then
			s = mw.ustring.gsub(s, '&MmNnDdAaSsHh;', '-')
			s = mw.ustring.gsub(s, '&MmIiNnUuSs;', '-')
			s = mw.ustring.gsub(s, '—–−', '-')
			return tonumber(s) or 0
		end
	end
	local function unlink(s)
		if s then
			s = s:match("^^%-%%(^%-)|^%-%%.*$") or s
			s = s:match("^^%-%%(^%-)%%.*$") or s
		end
		return s
	end
	local function get_color(color, party)
		if color == nil then
			local party = unlink(party) or 
			if party ~=  then
				color = political_party._fetch({party, 'color'})
			end
		end
		if color ~= nil then
			color = mw.ustring.gsub(color, '&(#)35;', '%1')
		end
		return color
	end
	-- preprocess the input
	local stop_flag = false
	local i = 0
	local has_votes = args'invalid' or args'totalvotes' or args'electorate' or args'turnout'
	local has_seats = args'seats' .. i .. '_2'
	local has_sw = args'sw' .. i .. '_2'
	local seats_only = has_seats and not has_votes
	local has_rspan = args'vspan' .. i
	local has_sspan = args'sspan' .. i
	while stop_flag == false do
		stop_flag = true
		for kk = 1, 20 do
			i = i + 1
			for k, key in ipairs({'alliance', 'atotal', 'cand', 'vp', 'party', 'ivotes', 'ipct', 'iseats', 'sc', 'st1t', 'st2t', 'st3t', 'st4t', 'st5t', 'sw', 'seats', 'totalvotes', 'totseats', 'acolor'}) do
				if argskey .. i then
					headingskey = true
					stop_flag = false
					max_rows = i > max_rows and i or max_rows
				end
			end
			if args'row' .. i then
				stop_flag = false
				max_rows = i > max_rows and i or max_rows
			end
			if args'row' .. i or args'cand' .. i or args'party' .. i or args'alliance' .. i or args'atotal' .. i or args'atotalnv' .. i or args'header' .. i then
				table.insert(index, i)
				if args'votes' .. i then
					has_votes = true
					if tonumber(args'votes' .. i) then showtotal.votes = 1 end
					local votesi = tonumber(args'votes' .. i) or 0
					args'votes' .. i = votesi
					if votesi > winner_votes1 then
						winner1 = i
						winner_votes1 = votesi
					end
					valid1 = valid1 + votesi
				end
				if args'ivotes' .. i then
					has_votes = true
				end
				if args'ipct' .. i then
					has_votes = true
				end
				if args'sw' .. i .. '_2' then
					has_sw = true
					rounds = 2
				end
				if args'valid2' or args'invalid2' or args'totalvotes2' or args'electorate2' or args'turnout2' then
					rounds = 2
				end
				if args'vspan' .. i then
					has_rspan = true
				end
				if args'sspan' .. i then
					has_sspan = true
				end
				if args'ipct' .. i .. '_2' then
					rounds = 2
				end
				if args'votes' .. i .. '_2' then
					has_votes = true
					rounds = 2
					if tonumber(args'votes' .. i .. '_2') then showtotal.votes_2 = 1 end
					local votesi = tonumber(args'votes' .. i .. '_2') or 0
					args'votes' .. i .. '_2' = votesi
					if votesi > winner_votes2 then
						winner2 = i
						winner_votes2 = votesi
					end
					valid2 = valid2 + votesi
				end
				if args'seats' .. i then
					if tonumber(args'seats' .. i) then showtotal.seats = 1 end
					seats = seats + (tonumber(args'seats' .. i) or 0)
				end
				if args'seats' .. i .. '_2' then
					has_seats = true
					rounds = 2
					if tonumber(args'seats' .. i ..'_2') then showtotal.seats_2 = 1 end
					seats_2 = seats_2 + (tonumber(args'seats' .. i .. '_2') or 0)
				end
				if args'st1t' .. i then
					if tonumber(args'st1t' .. i) then showtotal.st1t = 1 end
					st1t = st1t + (tonumber(args'st1t' .. i) or 0)
				end
				if args'st2t' .. i then
					if tonumber(args'st2t' .. i) then showtotal.st2t = 1 end
					st2t = st2t + (tonumber(args'st2t' .. i) or 0)
				end
				if args'st3t' .. i then
					if tonumber(args'st3t' .. i) then showtotal.st3t = 1 end
					st3t = st3t + (tonumber(args'st3t' .. i) or 0)
				end
				if args'st4t' .. i then
					if tonumber(args'st4t' .. i) then showtotal.st4t = 1 end
					st4t = st4t + (tonumber(args'st4t' .. i) or 0)
				end
				if args'st5t' .. i then
					if tonumber(args'st5t' .. i) then showtotal.st5t = 1 end
					st5t = st5t + (tonumber(args'st5t' .. i) or 0)
				end
				if args'totseats' .. i then
					if tonumber(args'totseats' .. i) then showtotal.totseats = 1 end
					totseats = totseats + (tonumber(args'totseats' .. i) or 0)
				end
				if has_seats and not has_votes then
					seats_only = true
				end
			end
		end
	end
	local ovalid = {valid1, valid2}
	seats = ((args'total_seats' or ) == 'TOTAL' and seats) or args'total_seats' or seats
	totseats = ((args'total_totseats' or ) == 'TOTAL' and totseats) or args'total_totseats' or totseats
	st1t = ((args'total_st1t' or ) == 'TOTAL' and st1t) or args'total_st1t' or st1t
	st2t = ((args'total_st2t' or ) == 'TOTAL' and st2t) or args'total_st2t' or st2t
	st3t = ((args'total_st3t' or ) == 'TOTAL' and st3t) or args'total_st3t' or st3t
	st4t = ((args'total_st4t' or ) == 'TOTAL' and st4t) or args'total_st4t' or st4t
	st5t = ((args'total_st5t' or ) == 'TOTAL' and st5t) or args'total_st5t' or st5t
	if seats or totseats or st1t or st2t or st3t or st4t or st5t or args'total_sc' or args'total_st1t' or args'total_st2t' or args'total_st3t' or args'total_st4t' or args'total_st5t' or args'valid' or ((rounds > 1) and args'valid2') then
		max_rows = max_rows + 1
		local i = max_rows
		table.insert(index, i)
		args'votes' .. i = showtotal.votes and valid1 or nil
		args'votes' .. i .. '_2' = showtotal.votes_2 and valid2 or nil
		args'colour' .. i = 'inherit'
		args'color' .. i = 'inherit'
		args'row' .. i = 'Tổng cộng'
		args'sw' .. i = '–'
		args'sw' .. i .. '_2' = '–'
		args'seats' .. i = showtotal.seats and seats or nil
		args'seats' .. i .. '_2' = showtotal.seats_2 and seats_2 or nil
		args'st1t' .. i = showtotal.st1t and st1t or args.total_st1t
		args'st2t' .. i = showtotal.st2t and st2t or args.total_st2t
		args'st3t' .. i = showtotal.st3t and st3t or args.total_st3t
		args'st4t' .. i = showtotal.st4t and st4t or args.total_st4t
		args'st5t' .. i = showtotal.st5t and st5t or args.total_st5t
		args'sc' .. i = args'total_sc'
		args'totseats' .. i = showtotal.totseats and totseats or nil
		args'font-weight' .. i = 'bold'
		args'class' .. i = 'sortbottom'
		ovalid1 = tonumber(args'valid') or valid1
		ovalid2 = tonumber(args'valid2') or valid2
	end
	-- build the table
	local root = mw.html.create(args'embed' and  or 'table')
	if args'embed' == nil then
		root
			:addClass('wikitable sortable')
			:tag('caption')
				:wikitext(args.caption)
				:done()
	end
	local topcell = nil
	if args'image' then
		topcell = root
			:tag('tr')
				:tag('td')
					:wikitext(args'image')
					:css('text-align', 'center')
	end
	local rowspan = (rounds > 1) and 2 or headings'st1t' and 2 or nil
	row = args'embed' and mw.html.create() or root:tag('tr')
	if args'dsv' then
		row
			:tag('th')
				:wikitext('Đảng')
				:attr('scope', 'col')
				:attr('colspan', 2)
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 2
		row
			:tag('th')
			:wikitext(args.candtitle or 'Ứng cử viên')
			:attr('scope', 'col')
			:attr('rowspan', rowspan)
			:done()
		cols = cols + 1
	elseif headings'cand' then
	if headings'cand' and headings'party' then
		row
			:tag('th')
				:wikitext('Ứng cử viên')
				:attr('scope', 'col')
				:attr('colspan', 2)
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 2
	end
	if headings'cand' and not headings'party' then
		row
			:tag('th')
				:wikitext('Ứng cử viên')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 1
	end
		if headings'vp' then
			row
				:tag('th')
						:wikitext('Bạn đồng hành')
						:attr('scope', 'col')
						:attr('rowspan', rowspan)
						:done()
			cols = cols + 1
		end
		if headings'party' then
			row
				:tag('th')
				:wikitext('Đảng')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:done()
			cols = cols + 1
		end
	elseif headings'party' and headings'alliance' then
			row
				:tag('th')
				:wikitext(args.partytitle or 'Đảng hoặc liên minh')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:attr('colspan', 4)
				:done()
			cols = cols + 4
	else 
			row
			:tag('th')
				:wikitext(args.partytitle or 'Đảng')
				:attr('scope', 'col')
				:attr('colspan', 2)
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 2
	end
	if rounds > 1 then
		if has_seats and headings'sw' then
			row
				:tag('th')
					:wikitext(args.firstround or 'Vòng đầu')
					:attr('scope', 'col')
					:attr('colspan', 4)
					:done()
				:tag('th')
					:wikitext(args.secondround or 'Vòng hai')
					:attr('scope', 'col')
					:attr('colspan', 4)
					:done()
		elseif has_seats then
			row
				:tag('th')
					:wikitext(args.firstround or 'Vòng đầu')
					:attr('scope', 'col')
					:attr('colspan', 3)
					:done()
				:tag('th')
					:wikitext(args.secondround or 'Vòng hai')
					:attr('scope', 'col')
					:attr('colspan', 3)
					:done()
		elseif has_votes then
			row
				:tag('th')
					:wikitext(args.firstround or 'Vòng đầu')
					:attr('scope', 'col')
					:attr('colspan', 2)
					:done()
				:tag('th')
					:wikitext(args.secondround or 'Vòng hai')
					:attr('scope', 'col')
					:attr('colspan', 2)
					:done()
		end
		secondrow = args'embed' and mw.html.create() or root:tag('tr')
	else
		secondrow = row
	end
	if headings'seats' and not has_seats then
		row
			:tag('th')
				:wikitext(args.seatstitle or 'Ghế')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 1
	end
	if headings'st1t' then
		row
			:tag('th')
				:wikitext('Ghế')
				:attr('colspan', 5)
				:attr('scope', 'col')
				:done()
	if rounds ghế' or 'Totseats&pm;')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 1
	end
	if headings'sc' then
		row
			:tag('th')
				:wikitext('+/–')
				:attr('scope', 'col')
				:attr('rowspan', rowspan)
				:done()
		cols = cols + 1
	end
	if topcell then
		topcell:attr('colspan', cols)
	end
	local cs = cols - 2*rounds
			- (headings'sw' and 1 or 0)
			- (headings'totseats' and 1 or 0)
			- (headings'seats' and 1 or 0)
			- (headings'sc' and 1 or 0)
			- (headings'st1t' and 1 or 0)
			- (headings'st2t' and 1 or 0)
			- (headings'st3t' and 1 or 0)
			- (headings'st4t' and 1 or 0)
			- (headings'st5t' and 1 or 0)
			- (has_seats and 1 or 0)
			- (has_sw and 1 or 0)
			+ (has_votes and 0 or 2)
			- (seats_only and 2 or 0)
	local rsuff = (rounds > 1) and {, '_2'} or {}
	for i, v in ipairs(index) do
		row = root:tag('tr')
			:addClass(args'class' .. v)
			:css('font-weight', args'font-weight' .. v)
		-- determine the colors
		local color = get_color(args'colour' .. v or args'color' .. v or nil, args'party' .. v)
		local acolor = get_color(args'acolour' .. v or args'acolor' .. v or nil, args'alliance' .. v)
		-- headers
		if args'header' .. v then
			row
			:tag('th')
				:wikitext(args'header' .. v)
				:attr('colspan', cols)
		else
		if args'row' .. v or headings'cand' and not headings'party' and not args'vp' .. v then
			row
				:css('background-color', args'acolor' .. v)
				:tag('td')
					:wikitext(args'row' .. v or args'cand' .. v)
					:attr('colspan', cs)
		elseif headings'cand' and not headings'party' and headings'vp' then
			row
				:tag('td')
					:wikitext(args'cand' .. v)
			row
				:tag('td')
					:wikitext(args'vp' .. v)
		elseif args'alliance' .. v and args'party' .. v then
			row
				:tag('td')
					:attr('rowspan', args'aspan' .. v)
					:css('background-color', acolor)
			row
				:tag('td')
					:attr('rowspan', args'aspan' .. v)
					:wikitext(args'alliance' .. v)
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:wikitext(args'party' .. v)
		elseif args'alliance' .. v then
			row
				:tag('td')
					:css('background-color', acolor)
			row
				:tag('td')
					:attr('colspan', '3')
					:wikitext(args'alliance' .. v)
		elseif args'atotal' .. v or args'atotalnv' .. v then
				row
					:css('font-style', 'italic')
					:tag('td')
						:attr('colspan', '2')
						:wikitext('Tổng cộng')
		else
			-- create the empty color cell
			row
				:css('background-color', args'acolor' .. v)
				:tag('td')
					:css('background-color', color)
			-- add the rest of the row
			if args'dsv' then
				row
					:tag('td')
						:wikitext(args'party' .. v)
				row
					:tag('td')
						:wikitext(args'cand' .. v)
			end
			if headings'cand' and not args'dsv' then
				row
					:tag('td')
						:wikitext(args'cand' .. v)
				if headings'vp' then
					row
						:tag('td')
							:wikitext(args'vp' .. v)
				end
			end
			if headings'party' and not args'dsv' then
				row
					:tag('td')
						:wikitext(args'party' .. v)
			end
		end
		if args'votes' .. v then
				row:tag('td')
					:attr('rowspan', args'vspan' .. v)
					:css('text-align', 'right')
					:wikitext(fmt(args'votes' .. v))
				row:tag('td')
					:attr('rowspan', args'vspan' .. v)
					:css('text-align', 'right')
					:wikitext(pct(args'votes' .. v, valid1))
		elseif args'ivotes' .. v or args 'ipct' .. v or args'atotal' .. v then
				row:tag('td')
					:attr('rowspan', args'vspan' .. v)
					:css('text-align', 'right')
					:css('font-style', 'italic')
					:wikitext(fmt(args'ivotes' .. v) or fmt(args'atotal' .. v))
			if args'ipct' .. v or args'apct' .. v or args'atotal' .. v then
				row:tag('td')
					:attr('rowspan', args'vspan' .. v)
					:css('text-align', 'right')
					:css('font-style', 'italic')
					:wikitext(args'ipct' .. v or args'apct' .. v or pct(args'atotal' .. v, valid1))
			else
				row:tag('td')
					:attr('rowspan', args'vspan' .. v)
					:wikitext()
			end
		elseif has_votes and not headings'sw' and not has_seats and not has_rspan or args'invalid' and not headings'sw' and not has_seats and not has_rspan or args'totalvotes' and not headings'sw' and not has_seats and not has_rspan or args'electorate' and not headings'sw' and not has_seats and not has_rspan or args'turnout' and not headings'sw' and not has_seats and not has_rspan or has_seats and args'seats' .. v and not args'votes' .. v and not args'ivotes' .. v and not has_rspan or has_votes and not args'votes' .. v and not args'ivotes' .. v and not args'ipct' .. v and not args'apct' .. v and not args'atotal' .. v  and args'row' .. v and args'seats' .. v and headings 'alliance' and not headings'sw' or args'atotalnv' .. v and args'aseats' .. v and not has_rspan then
				row:tag('td')
					:attr('colspan', 2)
		elseif has_seats and not args'seats' .. v and not headings'sw' and not has_rspan or has_votes and headings'sw' and not has_seats and not has_rspan then
				row:tag('td')
					:attr('colspan', 3)
		elseif has_seats and headings'sw' and not has_rspan then
				row:tag('td')
					:attr('colspan', 4)
		end
		if headings'sw' and args'votes' .. v or headings'sw' and args'ivotes' .. v or headings'sw' and args'atotal' .. v then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'sw' .. v)
		end
		if headings'seats' and not args'dsv' and not has_seats and rounds  1 and args'seats' .. v .. '_2' and not has_rspan or has_votes and rounds > 1 and not has_seats and not has_rspan or has_seats and not args'votes' .. v .. '_2' and args'seats' .. v .. '_2' and not has_rspan or args'atotalnv' .. v and args'aseats' .. v .. '_2' and not has_rspan then
				row:tag('td')
					:attr('colspan', 2)
		elseif has_seats and not args'seats' .. v .. '_2' and not headings'sw' and not has_rspan then
				row:tag('td')
					:attr('colspan', 3)
		elseif has_seats and headings'sw' and not has_rspan then
				row:tag('td')
					:attr('colspan', 4)
		end
		if headings'seats' and args'dsv' and not has_sspan or headings'seats' and rounds > 1 and not has_seats and not has_sspan or args'seats' .. v and has_sspan and rounds > 1 then
			row
				:tag('td')
					:attr('rowspan', args'sspan' .. v)
					:css('text-align', 'right')
					:wikitext(fmt(args'seats' .. v) or '–')
		end
		if has_sw and args'votes' .. v .. '_2' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'sw' .. v .. '_2')
		end
		if args'seats' .. v .. '_2' or has_seats and args'votes' .. v .. '_2' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(fmt(args'seats' .. v .. '_2') or '–')
		end
		if args'iseats' .. v .. '_2' or has_seats and args'ivotes' .. v .. '_2' and not args'seats' .. v .. '_2' or args'aseats' .. v .. '_2' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(fmt(args'iseats' .. v .. '_2') or fmt(args'aseats' .. v .. '_2'))
		end
		if headings'st1t' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'st1t' .. v or '–')
		end
		if headings'st2t' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'st2t' .. v or '–')
		end
		if headings'st3t' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'st3t' .. v or '–')
		end
		if headings'st4t' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'st4t' .. v or '–')
		end
		if headings'st5t' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'st5t' .. v or '–')
		end
		if headings'totseats' and not args'itotseats' .. v and not args'atotseats' .. v then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(fmt(args'totseats' .. v) or '–')
		elseif headings'totseats' then
			row
				:tag('td')
					:css('text-align', 'right')
					:css('font-style', 'italic')
					:wikitext(args'itotseats' .. v or args'atotseats' .. v)
		end
		if headings'sc' then
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'sc' .. v or '–')
		end
		end
	end
	-- separating line
	if args'valid' or args'valid2' or args'invalid' or args'invalid2' or args'totalvotes' or args'totalvotes2' or args'electorate' or args'electorate2' or args'turnout' or args'turnout2' or args'source' then
	row = root
		:tag('tr')
			:addClass('sortbottom')
	row
		:tag('td')
			:css('background', '#eaecf0')
			:attr('colspan', cols)
	end
	-- valid votes
	if args'invalid' or args'invalid2' then
	row = root
		:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Phiếu bầu hợp lệ')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	if args'invalid' then
	row
		:tag('td')
			:wikitext(fmt(ovalid1))
		:tag('td')
				:wikitext(pct(ovalid1, ovalid1 + invalid1))
	elseif not args'invalid' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
				:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'validsw' then
	row
		:tag('td')
			:wikitext(args'validsw')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'validsw' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if rounds > 1 and args'invalid2' then
	row
		:tag('td')
			:wikitext(fmt(ovalid2))
		:tag('td')
				:wikitext(pct(ovalid2, ovalid2 + invalid2))
	elseif rounds > 1 and not args'invalid2' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
			:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'validsw2' then
	row
		:tag('td')
			:wikitext(args'validsw2')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'validsw2' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if args'invalidsw' and not has_sw then
		row:tag('td')
			:wikitext(args'validsw')
		local cspan = (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
	if headings'seats' or headings'sc' then
		local cspan = (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	elseif headings'sw' or headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'sw' and 1 or 0) + (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	-- invalid votes
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
		if args'blank' then
	row
		:tag('th')
			:wikitext('Phiếu bầu không hợp lệ')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	else
	row
		:tag('th')
			:wikitext('Phiếu bầu không hợp lệ/trống')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	end
	if args'invalid' then
	row
		:tag('td')
			:wikitext(fmt(invalid1))
		:tag('td')
				:wikitext(pct(invalid1, ovalid1 + invalid1))
	elseif not args'invalid' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
				:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'invalidsw' then
	row
		:tag('td')
			:wikitext(args'invalidsw')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'invalidsw' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if rounds > 1 and args'invalid2' then
	row
		:tag('td')
			:wikitext(fmt(invalid2))
		:tag('td')
				:wikitext(pct(invalid2, ovalid2 + invalid2))
	elseif rounds > 1 and not args'invalid2' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
				:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'invalidsw2' then
	row
		:tag('td')
			:wikitext(args'invalidsw2')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'invalidsw2' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if args'invalidsw' and not has_sw then
		row:tag('td')
			:wikitext(args'invalidsw')
	if headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	elseif headings'sw' or headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'sw' and 1 or 0) + (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	end
	-- total
	if args'invalid' or args'totalvotes' or args'invalid2' or args'totalvotes2' then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('font-weight', 'bold')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Tổng cộng phiếu bầu')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('background', 'inherit')
	if not args'totalvotes' and args'invalid' then
	row
		:tag('td')
			:wikitext(fmt(ovalid1 + invalid1))
		:tag('td')
			:wikitext(pct(1, 1))
	elseif args'totalvotes' then
	row
		:tag('td')
			:wikitext(fmt(args.totalvotes))
		:tag('td')
			:wikitext('–')
	elseif not args'invalid' and not args'totalvotes' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
			:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'invalidsw' then
	row
		:tag('td')
			:wikitext('–')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'invalidsw' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if rounds > 1 and args'invalid2' and not args'totalvotes2' then
	row
		:tag('td')
			:wikitext(fmt(ovalid2 + invalid2))
		:tag('td')
			:wikitext(pct(1, 1))
	elseif rounds > 1 and args'totalvotes2' then
	row
		:tag('td')
			:wikitext(fmt(args.totalvotes2))
		:tag('td')
			:wikitext('–')
	elseif rounds > 1 and not args'invalid2' or rounds > 1 and not args'totalvotes2' then
	row
		:tag('td')
			:wikitext()
		:tag('td')
				:wikitext()
	end
	if has_seats and not headings'sw' then
	row
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and args'invalidsw2' then
	row
		:tag('td')
			:wikitext('–')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'invalidsw2' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if args'invalidsw' and not has_sw then
		row:tag('td')
			:wikitext('–')
	if headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	elseif headings'sw' or headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'sw' and 1 or 0) + (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	end
	-- registered
	if args'electorate' or args'electorate2' or args'turnout' or args'turnout2' then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Cử tri phiếu bầu đã đăng ký')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	row
			:tag('td')
				:wikitext(fmt(electorate1))
	if args'invalid' and args'electorate' then
		row
			:tag('td')
				:wikitext(pct(ovalid1 + invalid1, electorate1))
	elseif args'totalvotes' and args'electorate' then
		row
			:tag('td')
				:wikitext(pct(totalvotes1, electorate1))
	elseif args'electorate' then
		row
			:tag('td')
				:wikitext(args.turnout or '–')
	else
		row
			:tag('td')
				:wikitext(args.turnout)
	end
	if has_seats and not headings'sw' then
		row
			:tag('td')
				:wikitext()
	end
	if has_seats and headings'sw' and args'turnoutsw' then
	row
		:tag('td')
			:wikitext(args'turnoutsw')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'turnoutsw' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	if rounds > 1 then
		row
			:tag('td')
				:wikitext(fmt(electorate2))
	if args'invalid2' and args'electorate2' then
		row
			:tag('td')
				:wikitext(pct(ovalid2 + invalid2, electorate2))
	elseif args'totalvotes2' and args'electorate2' then
		row
			:tag('td')
				:wikitext(pct(totalvotes2, electorate2))
	elseif args'electorate2' then
		row
			:tag('td')
				:wikitext(args.turnout2 or '–')
	else
		row
			:tag('td')
				:wikitext(args.turnout2)
	end
	if has_seats and not headings'sw' then
		row
			:tag('td')
				:wikitext()
	end
	if has_seats and headings'sw' and args'turnoutsw2' then
	row
		:tag('td')
			:wikitext(args'turnoutsw2')
		:tag('td')
			:wikitext()
	end
	if has_seats and headings'sw' and not args'turnoutsw2' then
	row
		:tag('td')
			:attr('colspan', 2)
			:wikitext()
	end
	end
	if args'turnoutsw' and not has_sw then
		row:tag('td')
			:wikitext(args'turnoutsw')
	if headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	elseif headings'sw' or headings'seats' or headings'sc' or headings'st1t' or headings'st2t' or headings'st3t' or headings'st4t' or headings'st5t' then
		local cspan = (headings'sw' and 1 or 0) + (headings'seats' and 1 or 0) + (headings'sc' and 1 or 0) + (headings'st1t' and 1 or 0) + (headings'st2t' and 1 or 0) + (headings'st3t' and 1 or 0) + (headings'st4t' and 1 or 0) + (headings'st5t' and 1 or 0)
		row
			:tag('td')
				:attr('colspan', cspan > 1 and cspan or nil)
	end
	end
	if args'majority' then
	if args'invalid' or args'electorate' then
	row = root
		:tag('tr')
			:addClass('sortbottom')
	row
		:tag('td')
			:css('background', '#eaecf0')
			:attr('colspan', cols)
	end
	row = root
		:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Đa số')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	for k=1, rounds do
	row
		:tag('td')
			:wikitext(fmt(majorityk))
		:tag('td')
			:wikitext(fmt(majoritypctk))
	end
	if args'majoritysw' then
	row
		:tag('td')
			:wikitext(args'majoritysw')
	end
	end
	if args'result' then
		row = root:tag('tr')
			:addClass('sortbottom')
		-- determine the color
		local color = get_color(args'resultcolour' or nil, args'result')
		if args'resultsw' then
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', 2)
					:wikitext(args'result')
			row
				:tag('td')
					:attr('colspan', 2)
					:css('text-align', 'right')
					:wikitext('Swing')
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'resultsw')
		else
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', cols - 1)
					:wikitext(args'result')
		end
	end
	if args'majority2' then
	row = root
		:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row
		:tag('th')
			:wikitext('Đa số')
			:attr('scope', 'row')
			:attr('colspan', cs)
			:css('text-align', 'left')
			:css('font-weight', 'normal')
			:css('background', 'inherit')
	for k=1, rounds do
	row
		:tag('td')
			:wikitext(fmt(majority2k))
		:tag('td')
			:wikitext(fmt(majoritypct2k))
	end
	if args'majoritysw2' then
	row
		:tag('td')
			:wikitext(args'majoritysw2')
	end
	end
	if args'result2' then
		row = root:tag('tr')
			:addClass('sortbottom')
		-- determine the color
		local color = get_color(args'resultcolour' or nil, args'result2')
		if args'resultsw2' then
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', 2)
					:wikitext(args'result2')
			row
				:tag('td')
					:attr('colspan', 2)
					:css('text-align', 'right')
					:wikitext('Swing')
			row
				:tag('td')
					:css('text-align', 'right')
					:wikitext(args'resultsw2')
		else
			row
				:tag('td')
					:css('background-color', color)
			row
				:tag('td')
					:attr('colspan', cols - 1)
					:wikitext(args'result2')
		end
	end
	if args'source' then
	row = root:tag('tr')
			:addClass('sortbottom')
			:css('text-align', 'right')
	row:tag('td')
		:wikitext('Nguồn: ', args.source)
		:attr('colspan', cols)
		:css('text-align', 'left')
	end
	if args'embedded' then
		root:wikitext(args'embedded')
	end
	return tostring(root) .. tracking
end
return p