Mô đun:Team bracket

--
-- Mô đun này thực hiện nhiều bản mẫu nhánh đấu
--

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
RD1seedmap[r] = 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 s[r] ~= nil and s[r] ~= and tonumber(s[r]) then
legs[r] = tonumber(s[r])
elseif lastlegs then
legs[r] = lastlegs
else
legs[r] = 1
end
lastlegs = legs[r]
if legs[r] > 1 and aggregate ~= then
legs[r] = legs[r] + 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 - seeds[i 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 = rows[i]
rowspan = rowspan or 1
local jmax = i + rowspan - 1
for j = i, jmax do
if rows[j] == nil then
rowspan = rowspan - 1
elseif row == nil then
row = rows[j]
end
end
local cell = row and row:tag('td') or mw.html.create('td')
if rowspan and rowspan > 1 then
cell:attr('rowspan', rowspan)
end
if colspan and colspan > 1 then
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 = RD1seedmap[team]
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 = args[argname]
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 = args[argname]
return value
end

local function getTeamArg(round, type, team)
local argname = getTeamArgName(round, type, team)
local value = args[argname]
if isblank(value) then
return
end
if mw.ustring.find(value, '[%s][%s ]&[Nn][Bb][Ss][Pp];[%s]') then
tcats = tcats ..
end
return mw.ustring.gsub(value, '[%s][%s ]&[Nn][Bb][Ss][Pp];[%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 "Chung kết"
elseif roundFromLast 2 then
return "Bán kết"
elseif roundFromLast == 3 then
return "Tứ kết"
else
return "Vòng " .. 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, legs[round] do
local fw = nil
local agg = legs[round] > 1 and s == legs[round] and true or false
local score1 = (agg and getScoreArg(round, team, 'agg') or nil) or
getScoreArg(round, team, s) or ((legs[round] == 1) and getScoreArg(round, team)) or nil
local score2 = (agg and getScoreArg(round, otherteam, 'agg') or nil) or
getScoreArg(round, otherteam, s) or ((legs[round] == 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 legs[round] 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 legs[r+1] > legs[r] then
pad = legs[r+1] - legs[r]
end
if compact and betweenTeams then
addBlank(offset, nil, height, 1)
if topPair then
blank = addBlank(offset, nil, 2height, tonumber(hideSeeds and '1' or '2') + legs[r] + 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') + legs[r] + 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') + legs[r])
elseif rows[j] then
if compactFinal and (r maxround) then
renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r-1] - legs[r])
elseif compactFinal and (r maxround - 1) then
renderTeam(rows[j], r, team, topTeam, otherhideteam, legs[r+1] - legs[r])
else
renderTeam(rows[j], 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
mask[i] = 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
rows[i] = 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') + legs[1])
if compact and (rounds > 2) then
blank = addBlank(i, nil, 1, tonumber(hideSeeds and '3' or '4') + legs[1])
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 '5px' or '1px')
if compactFinal and r == (maxround-1) then
addHeading(titleRow, r, getRoundName(r), legs[r+1] - legs[r])
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 = legs[r]
if compactFinal and r == (maxround-1) then
legsr = legs[r+1] > legs[r] and legs[r+1] or legs[r]
end
for s = 1, legsr do
scoreCells[s] = 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 args[argname] then
args[argname] = seeds[i]
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)
return tostring(tbl) .. tcats
end

function p.teamBracket(frame)
return p.main(frame)
end

return p