Mô đun:Bracket builder

local p = {}
local entries = {}
local pathCell = {}
local crossCell = {}
local skipPath = {}
local shift = {}
local hascross = {}
local teams_per_match = {}
local rlegs = {}
local maxlegs = {}
local autolegs
local byes = {}
local hide = {}
local matchgroup = {}
local nowrap
local autocol
local seeds
local forceseeds
local boldwinner
local aggregate
local paramstyle
local masterindex

local function isempty(s)
return snil or s
end

local function notempty(s)
return s~=nil and s~=
end

local function bargs(s)
return pargs[s] or fargs[s]
end

local function toChar(num)
return string.char(string.byte("a")+num-1)
end

local function unboldParenthetical(text)
-- Replace wikilinks with unique placeholders
local counter = 0
local placeholders = {}
text = text:gsub('%[%[(.-)%]%]', function(link)
counter = counter + 1
local placeholder = '__WIKILINK__' .. counter .. '__'
placeholders[placeholder] = link
return placeholder
end)

-- Apply to parenthetical and bracketed text
text = text:gsub('(%b())', '%1')
:gsub('(%b[])', '%1')

-- Restore the original wikilinks
for placeholder, link in pairs(placeholders) do
text = text:gsub(placeholder, .. link .. )
end

return text
end

local function split(str,delim,tonum)
result = {};
local a = "[^"..table.concat(delim).."]+"
for w in str:gmatch(a) do
if tonum==true then
table.insert(result, tonumber(w));
else
table.insert(result, w);
end
end
return result;
end

local function getWidth(ctype, default)
local result = bargs(ctype..'-width')
if isempty(result) then return default end
if tonumber(result)~=nil then return result..'px' end
return result
end

local function matchGroups()
for j=minc,c do
matchgroup[j]={}
for i=1,r do
if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
matchgroup[j][i]=math.ceil(entries[j][i]['index']/teams_per_match[j])
entries[j][i]['group'] = math.ceil(entries[j][i]['index']/teams_per_match[j])
end
end
end
end

local function teamLegs(j,i)
local legs = rlegs[j]
if notempty(entries[j][i]['legs']) then
legs = tonumber(entries[j][i]['legs'])
end
if autolegs then
local l=1
repeat l=l+1
until isempty(entries[j][i]['score'][l])
legs = l-1
end
return legs
end

local function boldWinner()
local function boldScore(j,i,l)
if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
local myscore = entries[j][i]['score'][l]:gsub('%W',)
if myscore == "" or myscore:find("%D") then return 'normal'
else myscore=tonumber(myscore) end
local compscore = {}
for k,v in pairs(matchgroup[j]) do
if matchgroup[j][i]==v and k~=i then
local theirscore = entries[j][k]['score'][l] or
theirscore = theirscore:gsub('%W',)
if theirscore== "" or theirscore:find("%D") then return 'normal'
else table.insert(compscore,tonumber(theirscore)) end
end
end
for k,v in pairs(compscore) do
if myscorelegs/2 then
return 'bold'
end
if autolegs then
for l=1,legs do
if notempty(entries[j][i]['score'][l]) and string.find(entries[j][i]['score'][l],"nbsp") then
return 'normal'
end
end
else
for l=1,legs do
if isempty(entries[j][i]['score'][l]) or string.find(entries[j][i]['score'][l],"nbsp") then
return 'normal'
end
end
end
else
wins = 'aggwins'
end

local compteam = {}
for k,v in pairs(matchgroup[j]) do
if matchgroup[j][i]==v and k~=i then
table.insert(compteam,tonumber(entries[j][k][wins]))
end
end
for k,v in pairs(compteam) do
if entries[j][i][wins]1 then
entries[j][i]['score']['weight']['agg'] = boldScore(j,i,'agg')
end
end
end
for i=1,r do
if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then
local agg
local legs = teamLegs(j,i)
if aggregate and legs>1 then agg=true end
entries[j][i]['weight'] = boldTeam(j,i,agg)
end
end
end
end

local function isBlankEntry(col,row,ctype)
if isempty(entries[col][row]) then return true end
if isempty(entries[col][row]['team']) and isempty(entries[col][row]['text']) then return true end
return false
end

local function showSeeds(j,i)
local showseed=false
if forceseeds or notempty(entries[j][i]['seed']) then
showseed=true
else
for k=1,teams_per_match[j]-1 do
if notempty(entries[j][i+2k]) and entries[j][i]['group']==entries[j][i+2k]['group'] and notempty(entries[j][i+2k]['seed']) then
showseed=true
end
if notempty(entries[j][i-2k]) and entries[j][i]['group']==entries[j][i-2k]['group'] and notempty(entries[j][i-2k]['seed']) then
showseed=true
end
end
end
return showseed
end

local function cellBorder(b)
return b[1]..'px '..b[2]..'px '..b[3]..'px '..b[4]..'px'
end

local function Cell(tbl,j,i,rowspan,colspan,text,align,border,border_width,bg,padding,weight,nwrap)
local cell = tbl:tag('td')
if colspan~=1 then
cell:attr('colspan',colspan)
end
if rowspan~=1 then
cell:attr('rowspan',rowspan)
end
if notempty(border) then
cell:css('border',border)
end
if notempty(border_width) then
cell:css('border-width',cellBorder(border_width))
end
if notempty(bg) then
cell:css('background-color',bg)
end
if notempty(align) then
cell:css('text-align',align)
end
cell:css('padding','0em 0.3em')
if weight=='bold' then
cell:css('font-weight',weight)
end
if notempty(text) then
cell:wikitext(text)
end
return cell
end

local function teamCell(tbl,k,j,i,l,colspan)
local bg = 'F2F2F2'
local align
local padding
local weight
local text
local nwrap
local b={0,0,1,1}
if k'seed' or k'score' then
align='center'
end
if k~='seed' then
bg='F9F9F9'
end
if k=='team' then
padding='0.3em'
if teamLegs(j,i)==0 then
b[2]=1
end
end
if entries[j][i]['position']=='top' then
b[1]=1
end
if lteamLegs(j,i) or l'agg' or k=='seed' then
b[2]=1
end
if (lnil and entries[j][i]['weight']'bold') or entries[j][i]['score']['weight'][l]=='bold' then
weight='bold'
end
if l==nil then
text=unboldParenthetical(entries[j][i][k])
else
text=tostring(entries[j][i][k][l])
end
return Cell(tbl,j,i,2,colspan,text,align,'solid aaa',b,bg,padding,weight,nwrap)
end

local function insertEntry(tbl,j,i)
local entry_colspan=maxlegs[j]+2
if not seeds then entry_colspan=entry_colspan-1 end
if (aggregate and maxlegs[j]>1) or maxlegs[j]==0 then
entry_colspan=entry_colspan+1
end

if entries[j][i]~=nil and entries[j][i]['ctype']'blank' then
return
end

if entries[j][i]nil then
if entries[j][i-1]~=nil or i==1 then
local rowspan = 0
local row = i
repeat
rowspan=rowspan+1
row=row+1
until entries[j][row]~=nil or row>r
return Cell(tbl,j,i,rowspan,entry_colspan)
else
return
end
end

if entries[j][i]['ctype']=='header' then
if byes[j][entries[j][i]['headerindex']] then
local emptyround = true
local row = i+1
repeat
if not isBlankEntry(j,row) then
emptyround = false
end
row = row+1
until (entries[j][row]~=nil and entries[j][row]['ctype']'header') or row>r
if emptyround true then
return Cell(tbl,j,i,2,entry_colspan)
end
end

if hide[j][entries[j][i]['headerindex']] then
return Cell(tbl,j,i,2,entry_colspan)
end

if isempty(entries[j][i]['header']) then
if entries[j][i]['headerindex']1 then
if jc then entries[j][i]['header'] = 'Final'
elseif j==c-1 then entries[j][i]['header'] = 'Semifinals'
elseif j==c-2 then entries[j][i]['header'] = 'Quarterfinals'
else entries[j][i]['header'] = 'Round '..j
end
else
entries[j][i]['header'] = 'Lower round '..j
end
end

return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['header'],'center','1px solid aaa',nil,entries[j][i]['shade'])
end

if entries[j][i]['ctype']=='team' then
if (byes[j][entries[j][i]['headerindex']] and isBlankEntry(j,i)) or hide[j][entries[j][i]['headerindex']] then
return Cell(tbl,j,i,2,entry_colspan)
end

local legs = teamLegs(j,i)
local team_colspan = maxlegs[j]-legs+1
if aggregate and legs==1 and maxlegs[j]>1 then
team_colspan=team_colspan+1
end
if maxlegs[j]==0 then
team_colspan=team_colspan+1
end

if seeds then
if showSeeds(j,i)==true then
teamCell(tbl,'seed',j,i)
else
team_colspan=team_colspan+1
end
end
teamCell(tbl,'team',j,i,nil,team_colspan)
for l=1,legs do
teamCell(tbl,'score',j,i,l)
end
if aggregate and legs>1 then
teamCell(tbl,'score',j,i,'agg')
end
end

if entries[j][i]['ctype']'text' then
Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,nil,nil,nil,'0.3em')
end

if entries[j][i]['ctype']'group' then
local colspan=0
for m=j,entries[j][i]['colspan']+j-1 do
colspan=colspan+maxlegs[m]+2
if not seeds then colspan=colspan-1 end
if (aggregate and maxlegs[m]>1) or maxlegs[m]==0 then
colspan=colspan+1
end
end
colspan = colspan+2(entries[j][i]['colspan']-1)
return Cell(tbl,j,i,2,colspan,entries[j][i]['group'],'center')
end

if entries[j][i]['ctype']=='line' then
local b={0,0,0,0}
b[3]=2pathCell[j-1][i+1][3][1][3]
return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid black',b)
end

if entries[j][i]['ctype']=='line2' then
local b={0,0,0,0}
b[1]=2pathCell[j-1][i][3][1][1]
return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid black',b)
end
end

local function isRoundHidden(j,i,headerindex)
if notempty(entries[j][i]['pheader']) then
hide[j][entries[j][i]['headerindex']] = false
end
local row = i+1
repeat
if not isBlankEntry(j,row) then
hide[j][entries[j][i]['headerindex']] = false
end
row = row+1
until (entries[j][row]~=nil and entries[j][row]['ctype']=='header') or row>r
end

local function paramNames(cname,j,i,l)
local rname = {
{'RD'..j, bargs('RD'..j..'-altname') or 'RD'..j},
{'RD'..j..toChar(entries[j][i]['headerindex']),bargs('RD'..j..toChar(entries[j][i]['headerindex'])..'-altname') or 'RD'..j..toChar(entries[j][i]['headerindex'])}
}
local name = {cname, bargs(cname..'-altname') or cname}
local index = {entries[j][i]['index'], entries[j][i]['altindex']}
local result = {}
if cname'header' then
if entries[j][i]['headerindex']1 then
for k=1,2 do
table.insert(result,bargs(rname[1][3-k]) or )
table.insert(result,bargs(rname[2][3-k]) or )
end
else
for k=1,2 do
table.insert(result,bargs(rname[2][3-k]) or )
end
end
elseif cname'pheader' then
if entries[j][i]['headerindex']1 then
for k=1,2 do
table.insert(result,pargs[rname[1][3-k]] or )
table.insert(result,pargs[rname[2][3-k]] or )
end
else
for k=1,2 do
table.insert(result,pargs[rname[2][3-k]] or )
end
end
elseif cname=='score' then
for m=1,2 do for k=1,2 do
if l1 then
table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]) or )
end
table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]..'-'..l) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]..'-'..l) or )
end end
elseif cname'shade' then
for k=1,2 do
if entries[j][i]['headerindex']1 then
table.insert(result,bargs(rname[1][3-k]..'-'..name[1]) or )
else
table.insert(result,bargs(rname[2][3-k]..'-'..name[1]) or )
end
end
table.insert(result,bargs('RD-shade'))
table.insert(result,'F2F2F2')
elseif cname'text' then
for n=1,2 do for m=1,2 do for k=1,2 do
table.insert(result,bargs(rname[3-m][3-k]..'-'..name[3-n]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[3-n]..'0'..index[3-m]) or )
end end end
else
for m=1,2 do for k=1,2 do
table.insert(result,bargs(rname[3-m][3-k]..'-'..name[1]..index[3-m]) or bargs(rname[3-m][3-k]..'-'..name[1]..'0'..index[3-m]) or )
end end
end
for k=1,result do
if notempty(result[k]) then
return result[k]
end
end
return
end

local function indexedParams(j)
for i=1,r do
if entries[j][i]~=nil then
if entries[j][i]['ctype']=='team' then
local legs = rlegs[j]
if forceseeds then
entries[j][i]['seed'] = bargs(masterindex) or
masterindex = masterindex+1
end
entries[j][i]['team'] = bargs(tostring(masterindex)) or
masterindex = masterindex+1
entries[j][i]['legs'] = paramNames('legs',j,i)
entries[j][i]['score'] = {}
entries[j][i]['weight'] = 'normal'
entries[j][i]['score']['weight'] = {}
if notempty(entries[j][i]['legs']) then
legs = tonumber(entries[j][i]['legs'])
end
for l=1,legs do
entries[j][i]['score'][l] = bargs(tostring(masterindex)) or
masterindex = masterindex+1
entries[j][i]['score']['weight'][l] = 'normal'
end
if aggregate and legs>1 then
entries[j][i]['score']['agg'] = bargs(masterindex) or
masterindex = masterindex+1
entries[j][i]['score']['weight']['agg'] = 'normal'
end
end
if entries[j][i]['ctype']=='header' then
entries[j][i]['header'] = paramNames('header',j,i)
entries[j][i]['pheader'] = paramNames('pheader',j,i)
entries[j][i]['shade'] = paramNames('shade',j,i)
end
if entries[j][i]['ctype']=='text' then
entries[j][i]['text'] = bargs(tostring(masterindex)) or
masterindex = masterindex+1
end
if entries[j][i]['ctype']=='group' then
entries[j][i]['group'] = bargs(tostring(masterindex)) or
masterindex = masterindex+1
end
if entries[j][i]['ctype'] 'line' and entries[j][i]['hastext']true then
entries[j][i]['text'] = bargs(masterindex) or
masterindex = masterindex+1
end
end
end
end

local function assignParams()
masterindex = 1
local maxcol = 1
local byerows = 1
local hiderows = 1
for j=minc,c do
rlegs[j] = tonumber(bargs('RD'..j..'-legs')) or tonumber(bargs('legs')) or 1
if notempty(bargs('RD'..j..'-legs')) or bargs('legs') then autolegs = false end
if paramstyle == 'numbered' then
indexedParams(j)
else
for i=1,r do
if entries[j][i]~=nil then
if entries[j][i]['ctype']=='team' then
local legs = rlegs[j]
entries[j][i]['seed'] = paramNames('seed',j,i)
entries[j][i]['team'] = paramNames('team',j,i)
entries[j][i]['legs'] = paramNames('legs',j,i)
entries[j][i]['score'] = {}
entries[j][i]['weight'] = 'normal'
entries[j][i]['score']['weight'] = {}
if notempty(entries[j][i]['legs']) then
legs = tonumber(entries[j][i]['legs'])
end
if autolegs then
local l=1
repeat
entries[j][i]['score'][l] = paramNames('score',j,i,l)
entries[j][i]['score']['weight'][l] = 'normal'
l=l+1
until isempty(paramNames('score',j,i,l))
legs = l-1
else
for l=1,legs do
entries[j][i]['score'][l] = paramNames('score',j,i,l)
entries[j][i]['score']['weight'][l] = 'normal'
end
end
if aggregate and legs>1 then
entries[j][i]['score']['agg'] = paramNames('score',j,i,'agg')
entries[j][i]['score']['weight']['agg'] = 'normal'
end
end
if entries[j][i]['ctype']=='header' then
entries[j][i]['header'] = paramNames('header',j,i)
entries[j][i]['pheader'] = paramNames('pheader',j,i)
entries[j][i]['shade'] = paramNames('shade',j,i)
end
if entries[j][i]['ctype']=='text' then
entries[j][i]['text'] = paramNames('text',j,i)
end
if entries[j][i]['ctype']=='group' then
entries[j][i]['group'] = paramNames('group',j,i)
end
if entries[j][i]['ctype'] 'line' and entries[j][i]['hastext']true then
entries[j][i]['text'] = paramNames('text',j,i)
end
end
if autocol and not isBlankEntry(j,i) then
maxcol = math.max(maxcol,j)
end
end
end
for i=1,r do
if entries[j][i]~=nil and entries[j][i]['ctype']=='header' then
isRoundHidden(j,i)
end
if entries[j][i]~=nil and not hide[j][entries[j][i]['headerindex']] then
if not byes[j][entries[j][i]['headerindex']] or (byes[j][entries[j][i]['headerindex']] and not isBlankEntry(j,i)) then
byerows = math.max(byerows,i)
end
end
end
end
for j=minc,c do
for k=1,headerindex[j] do
if byes[j][k] or hide[j][k] then
r=byerows+1
end
end
end
if autocol then
c = maxcol
end
end

local function getHide(j,headerindex)
hide[j] = {}
for k=1,headerindex[j] do
if bargs('RD'..j..toChar(k)..'-hide')'yes' or bargs('RD'..j..toChar(k)..'-hide')'y' then
hide[j][k]=true
end
end
end

local function getByes(j,headerindex)
byes[j] = {}
for k=1,headerindex[j] do
if bargs('byes')'yes' or bargs('byes')'y' then
byes[j][k]=true
elseif tonumber(bargs('byes')) then
if jr-1 or skipPath[j][a] then
return false
end
for k=1,3 do
for n=1,4 do
if pathCell[j][i][k][1][n]~=pathCell[j][a][k][1][n] then
return false
end
end
end
return true
end
if repeatedPath(i) then
local row=i
repeat
if row~=i and repeatedPath(row) then
skipPath[j][row]=true
end
rowspan=rowspan+1
row=row+1
until row>r or not repeatedPath(row)
rowspan=rowspan-1
end
end

if i>1 and (crossCell[j][i-1]['left'][1]1 or crossCell[j][i-1]['right'][1]1) then
return
end
if hascross[j] then
colspan = 3
if crossCell[j][i]['left'][1]1 or crossCell[j][i]['right'][1]1 then
rowspan = 2
if crossCell[j][i]['left'][1]==1 then
cross[1] = 'linear-gradient(to top right, transparent calc(50% - 1px),'..crossCell[j][i]['left'][2]..' calc(50% - 1px),'..crossCell[j][i]['left'][2]..' calc(50% + 1px), transparent calc(50% + 1px))'
end
if crossCell[j][i]['right'][1]==1 then
cross[2] = 'linear-gradient(to bottom right, transparent calc(50% - 1px),'..crossCell[j][i]['right'][2]..' calc(50% - 1px),'..crossCell[j][i]['right'][2]..' calc(50% + 1px), transparent calc(50% + 1px))'
end
end
if notempty(cross[1]) and notempty(cross[2]) then
cross[1] = cross[1]..','
end
bg = cross[1]..cross[2]
end
for k=1,3 do
generatePathCell(tbl,j,i,k,bg,rowspan)
end
end

local function parsePaths(j)
local result={}
local str = fargs['col'..j..'-col'..(j+1)..'-paths'] or
for val in str:gsub("%s+","")
:gsub(",",", ")
:gsub("%S+","\0%0\0")
:gsub("%b()", function(s) return s:gsub("%z","") end)
:gmatch("%z(.-)%z") do
local array = split(val:gsub("%s+",""):gsub("%)",""):gsub("%(",""),{"-"})
for k,_ in pairs(array) do
array[k] = split(array[k],{","})
end
if notempty(array[2]) then
for m=1,array[2] do
array[3] = {}
array[2][m] = split(array[2][m],{":"})
array[3][m] = array[2][m][2]
array[2][m] = array[2][m][1]
end
for n=1,array[1] do
for m=1,array[2] do
table.insert(result,{tonumber(array[1][n]),tonumber(array[2][m]),['color']=array[3][m]})
end
end
end
end
return result
end

local function isPathHidden(j,i,start,stop)
local result=false
if notempty(entries[j][start-1]) and (byes[j][entries[j][start-1]['headerindex']] and isBlankEntry(j,start-1) and isBlankEntry(j,start+1) or hide[j][entries[j][start-1]['headerindex']]) then
if bargs('show-bye-paths')~='y' and bargs('show-bye-paths')~='yes' then
result=true
end
end
if notempty(entries[j+1][stop-1]) and (byes[j+1][entries[j+1][stop-1]['headerindex']] and isBlankEntry(j+1,stop-1) and isBlankEntry(j+1,stop+1) or hide[j+1][entries[j+1][stop-1]['headerindex']])then
if bargs('show-bye-paths')~='y' and bargs('show-bye-paths')~='yes' then
result=true
end
end
if bargs('RD'..j..'-RD'..(j+1)..'-path')'n' or bargs('RD'..j..'-RD'..(j+1)..'-path')'no' or bargs('RD'..j..'-RD'..(j+1)..'-path')'0' then
if notempty(entries[j][start-1]) and entries[j][start-1]['headerindex']1 then
result=true
end
end
return result
end

local function getPaths()
local paths = {}
for j=minc,c-1 do
hascross[j] = false
if notempty(fargs['col'..j..'-col'..(j+1)..'-cross']) then
hascross[j] = true
end
end
for j=minc,c-1 do
local straightpaths = {}
local outpaths = {}
local inpaths = {}
paths[j]=parsePaths(j)
pathCell[j] = {}
crossCell[j] = {}
skipPath[j] = {}
for i=1,r do
pathCell[j][i] = {}
crossCell[j][i] = {['left']={0,'black'},['right']={0,'black'}}
for k=1,3 do
pathCell[j][i][k] = {{0,0,0,0},['color']='black'}
end
skipPath[j][i] = false
end
local crossloc = split((fargs['col'..j..'-col'..(j+1)..'-cross'] or ):gsub("%s+", ""),{","},true)
if shift[j]~=0 and notempty(crossloc[1]) then
for n=1,crossloc do
crossloc[n] = crossloc[n]+shift[j]
end
end
for k,v in ipairs(paths[j]) do
local start = 2(paths[j][k][1]+shift[j])+(teams_per_match[j]-2)
local stop = 2(paths[j][k][2]+shift[j+1])+(teams_per_match[j+1]-2)
local mid = {}
local cross = 0

if notempty(crossloc[1]) then
for n=1,crossloc do
mid[n] = 2crossloc[n]+(teams_per_match[j]-2)
end
else
mid[1]=0
end
for n=1,mid do
if (startstart) or (start>stop and mid[n]>stop and mid[n]r then break end
pathCell[j][start+1][1][1][1] = 1
pathCell[j][start+1][1]['color'] = paths[j][k]['color']
if cross==0 then
if hascross[j] then
pathCell[j][start+1][2][1][1] = 1
pathCell[j][start+1][2]['color'] = paths[j][k]['color']
for i=start+1,stop do
pathCell[j][i][2][1][2] = 1
pathCell[j][i][2]['color'] = paths[j][k]['color']
end
else
for i=start+1,stop do
pathCell[j][i][1][1][2] = 1
pathCell[j][i][1]['color'] = paths[j][k]['color']
end
end
else
crossCell[j][cross]['left'] = {1,paths[j][k]['color']}
for i=start+1,cross-1 do
pathCell[j][i][1][1][2] = 1
pathCell[j][i][1]['color'] = paths[j][k]['color']
end
for i=cross+2,stop do
pathCell[j][i][2][1][2] = 1
pathCell[j][i][2]['color'] = paths[j][k]['color']
end
end
pathCell[j][stop][3][1][3] = 1
pathCell[j][stop][3]['color'] = paths[j][k]['color']
elseif start>stop then
if start>r then break end
pathCell[j][stop+1][3][1][1] = 1
pathCell[j][stop+1][3]['color'] = paths[j][k]['color']
if cross==0 then
if hascross[j] then
for i=stop+1,start do
pathCell[j][i][2][1][2] = 1
pathCell[j][i][2]['color'] = paths[j][k]['color']
end
pathCell[j][start][2][1][3] = 1
pathCell[j][start][2]['color'] = paths[j][k]['color']
else
for i=stop+1,start do
pathCell[j][i][1][1][2] = 1
pathCell[j][i][1]['color'] = paths[j][k]['color']
end
end
else
crossCell[j][cross]['right'] = {1,paths[j][k]['color']}
for i=stop+1,cross-1 do
pathCell[j][i][2][1][2] = 1
pathCell[j][i][2]['color'] = paths[j][k]['color']
end
for i=cross+2,start do
pathCell[j][i][1][1][2] = 1
pathCell[j][i][1]['color'] = paths[j][k]['color']
end
end
pathCell[j][start][1][1][3] = 1
pathCell[j][start][1]['color'] = paths[j][k]['color']
end
end
end
-- Thicken start==stop paths
for n=1,straightpaths do
local i = straightpaths[n][1]
local color = straightpaths[n][2]
if i>r then break end
if pathCell[j][i][1][1][3]==0 then
pathCell[j][i][1][1][3] = 1
pathCell[j][i][2][1][3] = 1
pathCell[j][i][3][1][3] = 1
pathCell[j][i][1]['color'] = color
pathCell[j][i][2]['color'] = color
pathCell[j][i][3]['color'] = color
if pathCell[j][i+1][1][1][1]==0 then
pathCell[j][i+1][1][1][1] = 0.5
pathCell[j][i+1][2][1][1] = 0.5
pathCell[j][i+1][3][1][1] = 0.5
pathCell[j][i+1][1]['color'] = color
pathCell[j][i+1][2]['color'] = color
pathCell[j][i+1][3]['color'] = color
end
elseif pathCell[j][i+1][1][1][1]==0 then
pathCell[j][i+1][1][1][1] = 1
pathCell[j][i+1][1]['color'] = color
if hascross[j] then
pathCell[j][i+1][2][1][1] = 1
pathCell[j][i+1][2]['color'] = color
end
pathCell[j][i+1][3][1][1] = 1
pathCell[j][i+1][3]['color'] = color
end
end
-- Thicken/Thin out paths
for n=1,outpaths do
local i = outpaths[n][1]
local color = outpaths[n][2]
if i0 and noPaths(j-k,i) then
skipPath[j-k][i] = true
skipPath[j-k][i+1] = true
end
k=k+1
until k>j-1 or not check(j-k,i) or not noPaths(j-k,i)
k=k-1
entries[j-k][i]={['ctype']='group',['index']=n,['colspan']=k+1}
entries[j-k][i+1]={['ctype']='blank'}
entries[j-k][i]['group'] = bargs('RD'..j..'-group'..n)
end
end
end
end
end
end

local function getCells()
local maxrow = 1
local colentry = {}
local bool = true
for j=minc,c do
if notempty(fargs['col'..j..'-headers']) then bool=false end
teams_per_match[j] = tonumber(fargs['RD'..j..'-teams-per-match']) or tonumber(fargs['col'..j..'-teams-per-match']) or tonumber(fargs['teams-per-match']) or 2
maxtpm = math.max(maxtpm,teams_per_match[j])
end
for j=minc,c do
entries[j] = {}
shift[j] = tonumber(bargs('RD'..j..'-shift')) or tonumber(bargs('shift')) or 0
colentry[j] = {
split((fargs['col'..j..'-headers'] or ):gsub("%s+", ""),{","},true),
split((fargs['col'..j..'-matches'] or ):gsub("%s+", ""),{","},true),
split((fargs['col'..j..'-lines'] or ):gsub("%s+", ""),{","},true),
split((fargs['col'..j..'-text'] or ):gsub("%s+", ""),{","},true),
}
if bool==true and fargs['noheaders']~='y' and fargs['noheaders']~='yes' then
table.insert(colentry[j][1],1)
end
end

for j=minc,c do
local textindex=0
for k,v in ipairs(colentry[j]) do
table.sort(colentry[j][k])
local ctype
if k==1 then ctype='header'
elseif k==2 then ctype='team'
elseif k==3 then ctype='line'
elseif k==4 then ctype='text'
elseif k==5 then ctype='group'
end
for n=1,colentry[j][k] do
if shift[j]~=0 and colentry[j][k][n]>1 then
colentry[j][k][n] = colentry[j][k][n]+shift[j]
end
local i=2colentry[j][k][n]-1
maxrow = math.max(i+2teams_per_match[j]-1,maxrow)
if ctype'team' then
if entries[j][i-1]nil and entries[j][i-2]==nil then
entries[j][i-2]={['ctype']='text',['index']=n}
entries[j][i-1]={['ctype']='blank'}
textindex=n
end
entries[j][i]={['ctype']=ctype,['index']=teams_per_match[j]n-(teams_per_match[j]-1),['position']='top'}
entries[j][i+1]={['ctype']='blank'}
for m=2,teams_per_match[j] do
entries[j][i+2(m-1)]={['ctype']=ctype,['index']=teams_per_match[j]n-(teams_per_match[j]-m)}
entries[j][i+2(m-1)+1]={['ctype']='blank'}
end
elseif ctype=='text' then
entries[j][i]={['ctype']=ctype,['index']=textindex+n}
entries[j][i+1]={['ctype']='blank'}
elseif ctype=='line' then
entries[j][i]={['ctype']=ctype}
entries[j][i+1]={['ctype']='blank'}
entries[j][i+2]={['ctype']='line2'}
entries[j][i+3]={['ctype']='blank'}
elseif ctype=='group' then
entries[j][i]={['ctype']=ctype,['index']=n}
entries[j][i+1]={['ctype']='blank'}
else
entries[j][i]={['ctype']=ctype,['index']=n,['position']='top'}
entries[j][i+1]={['ctype']='blank'}
end
end
end
end
if isempty(r) then
r = maxrow
end
end

function p.main(frame)
fargs = frame.args
pargs = frame:getParent().args;


r = tonumber(fargs.rows) or
c = tonumber(fargs.rounds) or 1
maxc = tonumber(pargs.maxrounds) or tonumber(pargs.maxround) or
minc = tonumber(pargs.minround) or 1
headerindex = {}
if notempty(maxc) then c=maxc end
if fargs.autocol'yes' or fargs.autocol'y' then autocol=true end
local colspacing = tonumber(fargs['col-spacing']) or 5
local height = bargs('height') or 0

maxtpm = 1
seeds = true
nowrap = true
forceseeds = false
boldwinner = bargs('boldwinner') or
if bargs('seeds')'y' or bargs('seeds')'yes' then forceseeds=true end
if bargs('seeds')'n' or bargs('seeds')'no' then seeds=false end
if bargs('aggregate')'y' or bargs('aggregate')'yes' then aggregate=true end
if bargs('autolegs')'y' or bargs('autolegs')'yes' then autolegs=true end
if bargs('paramstyle')=='numbered' then
paramstyle = 'numbered'
else
paramstyle = 'indexed'
end
if pargs.nowrap'n' or pargs.nowrap'no' then nowrap=false end

getCells()
getAltIndices()
assignParams()
matchGroups()
if (boldwinner'yes' or boldwinner'y' or boldwinner'high') then boldWinner() end
getPaths()
if minc1 then
getGroups()
end

for j=minc,c do
maxlegs[j] = rlegs[j]
for i=1,r do
if notempty(entries[j][i]) then
if notempty(entries[j][i]['legs']) then
maxlegs[j] = math.max(rlegs[j],entries[j][i]['legs'])
end
if autolegs then
local l=1
repeat l=l+1
until isempty(entries[j][i]['score']) or isempty(entries[j][i]['score'][l])
maxlegs[j] = math.max(maxlegs[j],l-1)
end
end
end
end

local div = mw.html.create('div')
:css('overflow','auto')

if height~=0 then
div:css('height',height)
end

local tbl = mw.html.create('table')
:attr('cellpadding','0')
:attr('cellspacing','0')
:css('font-size','90%')
:css('border-collapse','separate')
:css('margin','1em 2em 0em 1em')

if nowrap then
tbl:css('white-space','nowrap')
end

tbl:tag('tr'):css('visibility','collapse')
tbl:tag('td'):css('width','1px')
for j=minc,c do
if seeds then
tbl:tag('td'):css('width',getWidth('seed','25px'))
end
tbl:tag('td'):css('width',getWidth('team','150px'))
if maxlegs[j]==0 then
tbl:tag('td'):css('width',getWidth('score','25px'))
else
for l=1,maxlegs[j] do
tbl:tag('td'):css('width',getWidth('score','25px'))
end
end
if aggregate and maxlegs[j]>1 then
tbl:tag('td'):css('width',getWidth('agg',getWidth('score','25px')))
end
if j~=c then
if hascross[j] then
tbl:tag('td'):css('width',colspacing+1-4 ..'px')
:css('padding-left','4px')
tbl:tag('td'):css('padding-left','5px')
:css('width','5px')
tbl:tag('td'):css('width',colspacing-1-2 ..'px')
:css('padding-right','2px')
else
tbl:tag('td'):css('width',colspacing+1-4 ..'px')
:css('padding-left','4px')
tbl:tag('td'):css('width',colspacing-1-2 ..'px')
:css('padding-right','2px')
end
end
end

for i=1,r do
local row = tbl:tag('tr')
row:tag('td'):css('height','11px')
for j=minc,c do
insertEntry(row,j,i)
if j~=c then
insertPath(row,j,i)
end
end
end

div:wikitext(tostring(tbl))

return tostring(div)
end

return p