モジュール:TeamBracket

--
-- This module implements many bracket templates
--
local p = {}
local args = {}
local rows = {}
local mask = {}
local rounds
local maxround
local legs = {}
local compact
local byes
local hideSeeds
local showSeeds
local hideHeadings
local showThird
local offsetThird
local compactFinal
local sepwidth
local aggsep
local aggregate
local boldwinner
local hideomittedscores
local RD1seedmap = {}
local tcats = 
local function isnotblank(s)
	return s and s ~= 
end
local function isblank(s)
	return (not s) or (s == )
end
local function sumScores(s1, s2)
	s1 = mw.ustring.gsub(s1 or , '^\'%s*(%d%.*).-$', '%1')
	s2 = mw.ustring.gsub(s2 or , '^\'%s*(%d%.*).-$', '%1')
	if s1 ~=  and s2 ~=  then
		return tonumber(s1) + tonumber(s2)
	end
	return s1
end
local function scoreCompare(s1,s2,highwin)
	local ps1 = mw.ustring.gsub(s1 or , '^\'%s*(%d%.*)\'%s*%(\'%s*(%d%.*)\'%s*%).-$', '%2')
	local ps2 = mw.ustring.gsub(s2 or , '^\'%s*(%d%.*)\'%s*%(\'%s*(%d%.*)\'%s*%).-$', '%2')
	s1 = mw.ustring.gsub(s1 or , '^\'%s*(%d%.*).-$', '%1')
	s2 = mw.ustring.gsub(s2 or , '^\'%s*(%d%.*).-$', '%1')
	
	if s1 ~=  and s2 ~=  then
		s1 = tonumber(s1)
		s2 = tonumber(s2)
		if s1 and s2 then
			if (s1 == s2) then
				ps1 = tonumber(ps1)
				ps2 = tonumber(ps2)
				if ps1 and ps2 then
					s1 = ps1
					s2 = ps2
				end
			end
			if highwin then
				return ((s1 > s2) and 1) or ((s1  s1) and 1) or ((s2  0 then
			RD1seedmapr = c
			c = c + 1
		end
	end
end
local function parseLegs(s)
	s = mw.text.split((s or '1') .. '/', '%s*/%s*')
	if aggregate == 'n' or aggregate == 'no' or aggregate == '0' then
		aggregate = 
	end
	local n = showThird and (rounds + 1) or (rounds)
	local lastlegs = nil
	for r=1,n do
		if sr ~= nil and sr ~=  and tonumber(sr) then
			legsr = tonumber(sr)
		elseif lastlegs then
			legsr = lastlegs
		else
			legsr = 1
		end
		lastlegs = legsr
		if legsr > 1 and aggregate ~=  then
			legsr = legsr + 1
		end
	end
end
local function getSeeds()
	local seeds = {1, 2}
	local count = 2
	local before = false
	for r = 2, rounds do
		local max = math.pow(2, r)
		for i = 1, count do
			local pos = i * 2
			if before then pos = pos - 1 end
			table.insert(seeds, pos, max - seedsi * 2 - 1 + 1)
			before = not before
		end
		count = count * 2
	end
	return seeds
end
local function addTableRow(tbl)
	return tbl:tag('tr')
end
local function addBlank(i, css, rowspan, colspan)
	local row = rowsi
	local jmax = i + rowspan - 1
	for j = i, jmax do
		if rowsj == nil then
		elseif row == nil then
			row = rowsj
		end
	end
	local cell = row and row:tag('td') or mw.html.create('td')
		cell:attr('rowspan', rowspan)
	end
		cell:attr('colspan', colspan)
	end
	if css then
		cell:css(css)
	end
	return cell
end
local function addBorders(cell, topcell, seedorteam, extrasep)
	if sepwidth > 1 then topcell = true end
	if seedorteam then
		cell:css('border', '1px solid #aaa')
			:css('border-top-width', topcell and '1px' or '0')
	else
		cell:css('border-color', '#aaa')
			:css('border-style', 'solid')
			:css('border-top-width', topcell and '1px' or '0')
			:css('border-left-width', (extrasep and '1px') or ((sepwidth > 1) and '1px') or '0')
			:css('border-right-width', '1px')
			:css('border-bottom-width', '1px')
	end
end
local function addHeading(row, r, text, pad)
	pad = (pad == nil or pad  rounds then
		return string.format('3rd-%s%d', type, team)
	else
		if (round == 1) then
			team = RD1seedmapteam
			if team == 0 then
				return 'NIL'
			end
		end
		return string.format('RD%d-%s%d', round, type, team)
	end
end
local function getShadeArg(round, team, s)
	local argname = getTeamArgName(round, 'shade', team) .. (s and ('-' .. s) or )
	local value = argsargname
	if isblank(value) then
		return '#f9f9f9'
	end
	return value
end
local function getScoreArg(round, team, s)
	local argname = getTeamArgName(round, 'score', team) .. (s and ('-' .. s) or )
	local value = argsargname
	return value
end
local function getTeamArg(round, type, team)
	local argname = getTeamArgName(round, type, team)
	local value = argsargname
	if isblank(value) then
		return 
	end
	if mw.ustring.find(value, '%s*%s *&NnBbSsPp;%s*') then
		tcats = tcats .. 
	end
	return mw.ustring.gsub(value, '%s*%s *&NnBbSsPp;%s*', )
end
local function isHidden(r, team)
	return isblank( getTeamArg(r, 'team', team) )
end
local function getRoundName(round)
	local name = args'RD' .. round
	if isnotblank(name) then
		return name
	end
	local roundFromLast = rounds - round + 1
	if roundFromLast == 1 then
		return "決勝"
	elseif roundFromLast == 2 then
		return "準決勝"
	elseif roundFromLast == 3 then
		return "準々決勝"
	else
		return "ラウンド" .. math.pow(2, roundFromLast)
	end
end
local function addPath(index, round, top, left, w)
	local prop = top and 'border-bottom-width' or 'border-top-width'
	if left and round == 1 then
		if compact then
			addBlank(index)
		else
			addBlank(index, {'height' = '7px'})
			addBlank(index+1, {'height' = '7px'})
		end
		return nil
	else
		local cell = addBlank(index, 
			{'border-width' = '0',
			'border-style' = 'solid',
			'border-color' = 'black'}, (not compact) and 2 or 1)
		if left or round  1) and tcs or nil)
		:wikitext(teamArg)
		:newline()
	addBorders(teamCell, top or otherbye, true, false)
	local scoreCells = {}
	local wins, otherwins = 0, 0
	local sumscore, othersumscore = 0, 0
	local teamcolspan = tcs
	local hassum = false
	for s = 1, legsround do
		local fw = nil
		local agg = legsround > 1 and s == legsround and true or false
		local score1 = (agg and getScoreArg(round, team, 'agg') or nil) or 
			getScoreArg(round, team, s) or ((legsround == 1) and getScoreArg(round, team)) or nil
		local score2 = (agg and getScoreArg(round, otherteam, 'agg') or nil) or 
			getScoreArg(round, otherteam, s) or ((legsround == 1) and getScoreArg(round, otherteam)) or nil
		local showscore = true
		if agg and aggregate ~=  and score1 == nil and hassum then
			score1 = (aggregate == 'score')	and sumscore 
				or ((aggregate == 'legs' or aggregate == 'sets') and wins)
				or nil
		end
		if agg and aggregate ~=  and score2 == nil and hassum then
			score2 = (aggregate == 'score')	and othersumscore
				or ((aggregate == 'legs' or aggregate == 'sets') and otherwins)
				or nil
		end
		if score1 == nil and score2 == nil then
			if hideomittedscores > 0 and s >= hideomittedscores then
				teamcolspan = teamcolspan + 1
				showscore = false
			end
		else
			hassum = true
		end
		if showscore then
			local winner = scoreCompare(score1, score2, boldwinner ~= 'low')
			sumscore = sumScores(sumscore, score1)
			othersumscore = sumScores(othersumscore, score2)
			if winner == 1 then
				if boldwinner ~=  or (agg and (aggregate == 'score' or aggregate == 'legs' or aggregate == 'sets')) then 
					if agg and (aggregate == 'legs' or aggregate == 'sets') and (wins  1 and s == legsround and aggsep or nil)
		end
	end
	if teamcolspan > 1 then
		teamCell:attr('colspan', teamcolspan)
	end
	if boldwinner ~=  and wins > otherwins then
		if (aggregate == 'legs' or aggregate == 'sets') and (wins  1) and (r  0 then
			local pad = 0
			local betweenTeams = (topTeam == false and topPair == true) or (topTeam == true and topPair == false)
			if compactFinal and (r == maxround - 1) then
				betweenTeams = false
			end
			if compactFinal and (r == maxround - 1) and legsr+1 > legsr then
				pad = legsr+1 - legsr
			end
			if compact and betweenTeams then
				addBlank(offset, nil, height, 1)
				if topPair then
					blank = addBlank(offset, nil, 2*height, tonumber(hideSeeds and '1' or '2') + legsr + pad)
					if args'RD' .. r .. '-group' .. group then
						blank:wikitext(args'RD' .. r .. '-group' .. group)
						blank:css('text-align', 'center')
					end
					group = group + 1
				end
				blank = addBlank(offset, 
				{'border-width' = '0',
				'border-style' = 'solid',
				'border-color' = 'black'},
				height, 1)
			else
				blank = addBlank(offset, 
				{'border-width' = '0',
				'border-style' = 'solid',
				'border-color' = 'black'},
				height, tonumber(hideSeeds and '3' or '4') + legsr + pad)
			end
		end
		-- add bracket
		local j = topTeam and i + step - (compact and 1 or 2) or i
		-- add left path
		addPath(j, r, topTeam, true, hideleftpath and '0' or '2px')
		if hideteam then
			addBlank(j, nil, (not compact) and 2 or nil, tonumber(hideSeeds and '1' or '2') + legsr)
		elseif rowsj then
			if compactFinal and (r == maxround) then
				renderTeam(rowsj, r, team, topTeam, otherhideteam, legsr-1 - legsr)
			elseif compactFinal and (r == maxround - 1) then
				renderTeam(rowsj, r, team, topTeam, otherhideteam, legsr+1 - legsr)
			else
				renderTeam(rowsj, r, team, topTeam, otherhideteam)
			end
		end
		local rightPath = addPath(j, r, topTeam, false, (hiderightpath or hideteam) and '0' or '2px')
		if not topTeam then topPair = not topPair end
		if not topPair and r  rmax) and i or rmax
			maski = true
		end
	end
	for r = 1, maxround do
		local teams = math.pow(2, rounds - r + 1)
		local step = count / teams
		local topTeam = true -- is top row in match-up
		local team = 1
		for i = 1, count, step do
			local offset, height, blank
			local hideteam = false
			if r  mmax) and i or mmax
		end
	end
	for i = mmin, mmax do
		rowsi = addTableRow(tbl)
	end
end
local function renderTree(tbl)
	-- create 3 or 1 rows for every team
	local count = math.pow(2, rounds) * (compact and 1 or 3)
	local offsetcount = 2 * (compact and 1 or 3) + (compact and 2 or 3)
	offsetThird = getThirdOffset()
	maskRows(tbl, count, offsetcount)
	if showThird then
		for i = (count+1), (offsetcount + offsetThird) do
			if (rounds > 1) then
				local blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs1)
				if compact and (rounds > 2) then
					blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs1)
				end
			end
		end
	end
	if not compact then
		-- fill rows with groups
		for r = 1, rounds - 1 do
			renderGroups(count, r)
		end
	end
	-- fill rows with bracket
	for r = 1, maxround do
		renderRound(count, r)
	end
	if showThird then
		renderThird(count, compact)
	end
end
local function renderHeadings(tbl)
	local titleRow = addTableRow((not hideHeadings) and tbl or mw.html.create('table'))
	local widthRow = addTableRow(tbl)
	for r = 1, (compactFinal and (maxround-1) or maxround) do
		titleRow:tag('td')
		widthRow:tag('td'):css('width', r > 1 and '9px' or '1px')
		if compactFinal and r == (maxround-1) then
			addHeading(titleRow, r, getRoundName(r), legsr+1 - legsr)
		else
			addHeading(titleRow, r, getRoundName(r) )
		end
		local seedCell
		if (not hideSeeds) then
			seedCell = widthRow:tag('td'):css('width', getWidth('seed', '25px'))
		end
		local teamCell = widthRow:tag('td'):css('width', getWidth('team', '150px'))
		local scoreCells = {}
		local legsr = legsr
		if compactFinal and r == (maxround-1) then
			legsr = legsr+1 > legsr and legsr+1 or legsr
		end
		for s = 1, legsr do
			scoreCellss = widthRow:tag('td'):css('width', getWidth('score', '25px'))
		end
		titleRow:tag('td')
		widthRow:tag('td'):css('width', r  4) and compact and args'compact-final' and (args'compact-final' == 'yes' or args'compact-final' == 'y'))
	sepwidth = tonumber(args'sepwidth' or ((args.sets or args.legs) and 1) or (compact and 1) or 2) or 1
	aggregate = (args'aggregate' or ):lower()
	aggsep = args'aggsep' or args'aggregate' or nil
	boldwinner = args'boldwinner' or args'bold_winner' or 
	local autoSeeds = (args'autoseeds' and (args'autoseeds' == 'yes' or args'autoseeds' == 'y'))
	hideSeeds = (args'seeds' and (args'seeds' == 'no' or args'seeds' == 'n'))
	showSeeds = (args'seeds' and (args'seeds' == 'yes' or args'seeds' == 'y'))
	byes = (args'byes' and (args'byes' == 'yes' or args'byes' == 'y') and 1) or (tonumber(args'byes' or '0') or 0)
	hideomittedscores = (args'hideomittedscores' and (args'hideomittedscores' == 'yes' or args'hideomittedscores' == 'y') and 1) or (tonumber(args'hideomittedscores' or '0') or 0)
	hideHeadings = (args'headings' and (args'headings' == 'no' or args'headings' == 'n'))
	showThird = isnotblank(args'3rd') or isnotblank(args'3rd-team1') or isnotblank(args'3rd-team2')
	local align = (args'float' or args'align' or ):lower()
	local clear = args'clear' or 'none'
	parseSeedmap(args'RD1-omit')
	parseLegs(args.sets or args.legs)
	
	if autoSeeds then
		-- set default seeds for round 1
		local seeds = getSeeds()
		for i = 1, table.getn(seeds) do
			local argname = getTeamArgName(1, 'seed', i)
			if not argsargname then
				argsargname = seedsi
			end
		end
	end
	-- create the table
	local tbl = mw.html.create('table')
		:css('border-style', 'none')
		:css('font-size', '90%')
		:css('border-collapse', 'separate')
		:css('border-spacing', '0')
		:attr('cellpadding', '0')
	if (args'nowrap' and (args'nowrap' == 'yes' or args'nowrap' == 'y')) then
		tbl:css('white-space', 'nowrap')
	end
	
	if align == 'right' then
		tbl:css('float', 'right')
		if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then
			tbl:css('clear', 'right')
		end
		tbl:css('margin', '1em 0 1em 2em')
	elseif align == 'left' then
		tbl:css('float', 'left')
		if clear ~= 'none' and clear ~= 'no' and clear ~= 'n' then
			tbl:css('clear', 'left')
		end
		tbl:css('margin', '1em 2em 1em 0')
	elseif align == 'center' or align == 'centre' then
		tbl:css('margin', '1em auto')
	else
		tbl:css('margin', '1em 2em 1em 1em')
	end
	renderHeadings(tbl)
	renderTree(tbl)
	if (args'wide' and (args'wide' == 'y' or args'wide' == 'yes')) then
		return  .. tostring(tbl) ..  .. tcats
	end
	return tostring(tbl) .. tcats
end
function p.teamBracket(frame)
	return p.main(frame)
end
return p