Module:Sandbox/Labratscientist

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 s==nil 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 myscore<=v then return 'normal' end

end

if l~='agg' then

entries[j][i]['wins'] = entries[j][i]['wins']+1

else

entries[j][i]['aggwins'] = 1

end

return 'bold'

end

end

local function boldTeam(j,i,agg)

local wins

local legs = teamLegs(j,i)

if agg~=true then

wins = 'wins'

if entries[j][i][wins]>legs/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]<=v then

return 'normal'

end

end

return 'bold'

end

for j=minc,c do

for i=1,r do

if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then

entries[j][i]['wins'] = 0

entries[j][i]['aggwins'] = 0

end

end

for i=1,r do

if entries[j][i]~= nil and entries[j][i]['ctype']=='team' then

local legs = teamLegs(j,i)

for l=1,legs do

entries[j][i]['score']['weight'][l] = boldScore(j,i,l)

end

if aggregate and legs>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+2*k]) and entries[j][i]['group']==entries[j][i+2*k]['group'] and notempty(entries[j][i+2*k]['seed']) then

showseed=true

end

if notempty(entries[j][i-2*k]) and entries[j][i]['group']==entries[j][i-2*k]['group'] and notempty(entries[j][i-2*k]['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,color,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(color) then

cell:css('color',color)

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 = 'var(--background-color-neutral,#eaecf0)'

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 l==teamLegs(j,i) or l=='agg' or k=='seed' then

b[2]=1

end

if (l==nil 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 var(--border-color-base,#a2a9b1)',b,bg,'var(--color-base,#202122)',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 j==c 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 var(--border-color-base,#a2a9b1)',nil,'var(--background-color-neutral,#eaecf0)','var(--color-base,#202122)')

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,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]=2*pathCell[j-1][i+1][3][1][3]

return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid var(--border-color-base,#a2a9b1)',b)

end

if entries[j][i]['ctype']=='line2' then

local b={0,0,0,0}

b[1]=2*pathCell[j-1][i][3][1][1]

return Cell(tbl,j,i,2,entry_colspan,entries[j][i]['text'],nil,'solid var(--border-color-base,#a2a9b1)',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 l==1 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,'var(--background-color-neutral,#eaecf0)')

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 j<=tonumber(bargs('byes')) then

byes[j][k]=true

end

else

byes[j][k]=false

end

if bargs('RD'..j..'-byes')=='yes' or bargs('RD'..j..'-byes')=='y' then

byes[j][k]=true

elseif bargs('RD'..j..'-byes')=='no' or bargs('RD'..j..'-byes')=='n' then

byes[j][k]=false

end

if bargs('RD'..j..toChar(k)..'-byes')=='yes' or bargs('RD'..j..toChar(k)..'-byes')=='y' then

byes[j][k]=true

elseif bargs('RD'..j..'-byes')=='no' or bargs('RD'..j..'-byes')=='n' then

byes[j][k]=false

end

end

end

local function getAltIndices()

local teamindex=1

local textindex=1

local groupindex=1

for j=minc,c do

headerindex[j]=0

for i=1,r do

if entries[j][i]==nil and i==1 then

headerindex[j]=headerindex[j]+1

end

if entries[j][i]~=nil then

if entries[j][i]['ctype'] == 'header' then

entries[j][i]['altindex'] = headerindex[j]

teamindex=1

textindex=1

headerindex[j]=headerindex[j]+1

elseif entries[j][i]['ctype'] == 'team' then

entries[j][i]['altindex'] = teamindex

teamindex=teamindex+1

elseif entries[j][i]['ctype'] == 'text' then

entries[j][i]['altindex'] = textindex

textindex=textindex+1

elseif entries[j][i]['ctype'] == 'group' then

entries[j][i]['altindex'] = groupindex

groupindex=groupindex+1

elseif entries[j][i]['ctype'] == 'line' and entries[j][i]['hastext']==true then

entries[j][i]['altindex'] = textindex

textindex=textindex+1

end

entries[j][i]['headerindex'] = headerindex[j]

end

end

getByes(j,headerindex)

getHide(j,headerindex)

end

end

local function noPaths(j,i)

local result = true

local cols = 2

if hascross[j]==true then

cols = 3

end

for k=1,cols do

for n=1,4 do

if pathCell[j][i][k][1][n]~=0 then

result = false

return result

end

end

end

if hascross[j]==true and (crossCell[j][i]['left'][1]==1 or crossCell[j][i]['right'][1]==1) then

result = false

return result

end

return result

end

local function generatePathCell(tbl,j,i,k,bg,rowspan)

local color = pathCell[j][i][k]['color']

if not hascross[j] and k==2 then

return

end

local cell=tbl:tag('td')

local a=pathCell[j][i]

if rowspan~=1 then

cell:attr('rowspan',rowspan)

end

if notempty(bg) and k==2 then

cell:css('background',bg)

:css('transform','translate(-1px)')

end

if a[k][1][1]~=0 or a[k][1][2]~=0 or a[k][1][3]~=0 or a[k][1][4]~=0 then

cell:css('border','solid '..color)

:css('border-width',2*a[k][1][1]..'px '..2*a[k][1][2]..'px '..2*a[k][1][3]..'px '..2*a[k][1][4]..'px')

end

return cell

end

local function insertPath(tbl,j,i)

if skipPath[j][i] then

return

end

local colspan = 2

local rowspan = 1

local angle = 58.2

local pathcolor

local bg = ''

local cross = {,}

if i

local function repeatedPath(a)

if a>r-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,'var(--border-color-base,#a2a9b1)'},['right']={0,'var(--border-color-base,#a2a9b1)'}}

for k=1,3 do

pathCell[j][i][k] = {{0,0,0,0},['color']='var(--border-color-base,#a2a9b1)'}

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] = 2*crossloc[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]

cross = mid[n]

end

end

paths[j][k]['color'] = paths[j][k]['color'] or 'var(--border-color-base,#a2a9b1)'

table.insert(outpaths,{start,paths[j][k]['color']})

table.insert(inpaths,{stop,paths[j][k]['color']})

if not isPathHidden(j,i,start,stop) then

if start==stop then

table.insert(straightpaths,{start,paths[j][k]['color']})

elseif start

if stop>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 i

pathCell[j][i+1][1][1][1] = 0.5*pathCell[j][i][1][1][3]

pathCell[j][i+1][2][1][1] = 0.5*pathCell[j][i][2][1][3]

pathCell[j][i+1][1]['color'] = pathCell[j][i][1]['color']

pathCell[j][i+1][2]['color'] = pathCell[j][i][2]['color']

elseif i

pathCell[j][i][1][1][3] = pathCell[j][i+1][1][1][1]

pathCell[j][i][2][1][3] = pathCell[j][i+1][2][1][1]

pathCell[j][i+1][1][1][1] = 0.5*pathCell[j][i][1][1][3]

pathCell[j][i+1][2][1][1] = 0.5*pathCell[j][i][2][1][3]

pathCell[j][i][1]['color'] = pathCell[j][i+1][1]['color']

pathCell[j][i][2]['color'] = pathCell[j][i+1][2]['color']

end

end

-- Thin double-in paths

for n=1,#inpaths do

local i = inpaths[n][1]

local color = inpaths[n][2]

if i

pathCell[j][i+1][3][1][1] = 0.5*pathCell[j][i][3][1][3]

end

end

end

for j=minc,c-1 do

for i=1,r-1 do

local straightpath=false

if (entries[j+1][i-1]==nil or (byes[j+1][entries[j+1][i-1]['headerindex']]) and isBlankEntry(j+1,i-1)) then

if (pathCell[j][i][3][1][3]~=0 and pathCell[j+1][i][1][1][3]~=0) or (pathCell[j][i+1][3][1][1]~=0 and pathCell[j+1][i+1][1][1][1]~=0) then

if pathCell[j+1][i][1][1][3]==pathCell[j+1][i][3][1][3] and pathCell[j+1][i+1][1][1][1]==pathCell[j+1][i+1][3][1][1] then

straightpath=true

end

pathCell[j+1][i][1][1][3]=pathCell[j][i][3][1][3]

pathCell[j+1][i+1][1][1][1]=pathCell[j][i+1][3][1][1]

pathCell[j+1][i][2][1][3]=pathCell[j][i][3][1][3]

pathCell[j+1][i+1][2][1][1]=pathCell[j][i+1][3][1][1]

entries[j+1][i-1]={['ctype']='line'}

entries[j+1][i]={['ctype']='blank'}

if notempty(entries[j+1][i+1]) then

entries[j+1][i+1]['ctype'] = 'line2'

else

entries[j+1][i+1]={['ctype']='line2'}

end

entries[j+1][i+2]={['ctype']='blank'}

if straightpath then

pathCell[j+1][i][3][1][3]=pathCell[j+1][i][1][1][3]

pathCell[j+1][i+1][3][1][1]=pathCell[j+1][i+1][1][1][1]

end

end

end

end

end

end

local function getGroups()

local function check(j,i)

local result=false

if entries[j][i] == nil then

if entries[j][i+1] == nil then

result=true

elseif entries[j][i+1]['ctype']=='text' and isBlankEntry(j,i+1) then

result=true

end

elseif entries[j][i]['ctype']=='text' and isBlankEntry(j,i) then

result=true

end

return result

end

for j=minc,c-1 do

if teams_per_match[j]==2 then

local n=0

for i=1,r-1 do

if pathCell[j][i][3][1][3]==1 or pathCell[j][i+1][3][1][1]==1 then

n=n+1

if check(j,i) then

local k=minc-1

repeat

if entries[j-k][i+1]~=nil and entries[j-k][i+1]['ctype']=='text' and isBlankEntry(j-k,i+1) then

entries[j-k][i+2]=nil

end

entries[j-k][i]={['ctype']='blank'}

entries[j-k][i+1]={['ctype']='blank'}

if k>0 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=2*colentry[j][k][n]-1

maxrow = math.max(i+2*teams_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 minc==1 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