Jump to content

Module:Build bracket

Permanently protected module
From Wikipedia, the free encyclopedia

This is the current revision of this page, as edited by Pbrks (talk | contribs) at 01:43, 10 February 2024 (allow for aggregate width change). The present address (URL) is a permanent link to this version.

(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

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 <span style="font-weight:normal"></span> to parenthetical and bracketed text
    text = text:gsub('(%b())', '<span style="font-weight:normal">%1</span>')
               :gsub('(%b[])', '<span style="font-weight:normal">%1</span>')

    -- 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,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 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 #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     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 #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]=2*pathCell[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]=2*pathCell[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 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,'#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 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<r then
		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,'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] = 2*crossloc[n]+(teams_per_match[j]-2)
				end
			else
				mid[1]=0
			end
			for n=1,#mid do
				if (start<stop and mid[n]<stop and mid[n]>start) or (start>stop and mid[n]>stop and mid[n]<start) then
					cross = mid[n]
				end
			end
			paths[j][k]['color'] = paths[j][k]['color'] or 'black'
			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<stop then
					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<r and pathCell[j][i][1][1][3]==1 and pathCell[j][i+1][1][1][1]==0 then
				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<r and pathCell[j][i][1][1][3]==0 and pathCell[j][i+1][1][1][1]==1 then
				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<r and pathCell[j][i][3][1][3]==1 and pathCell[j][i+1][3][1][1]==1 and pathCell[j][i][3]['color']==pathCell[j][i+1][3]['color'] then
				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
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy