local _module = {}
_module.create = function(frame, title, teams, isLimitedOvers, tableStyle, useWebSlice)
---------- Functions ----------
local strMatch = string.match
local strFind = string.find
local strFormat = string.format
local strSub = string.sub
local strRepeat = string.rep
local strUpper = string.upper
local yesno = require("Module:Yesno")
---------- Background colours for table cells ----------
local noMatchColour = "#C0C0C0" -- No match defined
local homeWinColour = "#CCCCFF" -- Home team wins
local awayWinColour = "#FFCCCC" -- Away team wins
local noResultColour = "#FFDEAD" -- Match abandoned
local drawColour = "#F0E68C" -- Match drawn
local tieColour = "#DDFFDD" -- Match tied
local notPlayedColour = "inherit" -- Not played yet
local errorColour = "#FF7777" -- Error
-- The table containing all the matches, looked up by home and away teams.
local matches = {}
-- Matches which have been defined have a 'true' value for their match number key in this table.
local matchIDs = {}
-- This is used to lookup team objects by name
local teamLookup = {}
-- The total number of teams
local teamCount = #teams
-- The output buffer. It contains all the strings to be output. The 'print' function adds a string to the output buffer
local output = {}
local outputIndex = 1
local print = function(s)
output[outputIndex] = s
outputIndex = outputIndex + 1
end
-- The error buffer. It contains all the errors accumulated when the table was generated. addError() adds an error to the buffer
local errors
local errorIndex = 1
local addError = function(msg, matchID)
errors = errors or {}
if matchID then
errors[errorIndex] = strFormat('* <span class="error" style="font-weight: normal">Error (match %s): %s</span>\n', matchID, msg)
else
errors[errorIndex] = strFormat('* <span class="error" style="font-weight: normal">Error: %s</span>\n', msg)
end
errorIndex = errorIndex + 1
end
-- Sort the teams and create the lookup table
local teamSorter = function(t1, t2)
return t1.fullName < t2.fullName
end
table.sort(teams, teamSorter)
for i = 1, teamCount do
local teamObj = teams[i]
teamLookup[teamObj.code] = teamObj
teamLookup[teamObj.shortName] = teamObj
teamLookup[teamObj.fullName] = teamObj
end
-- Parse the rows
for i, row in ipairs(frame.args) do
local match = {}
-- Key/value pairs for each row are separated by semicolons, and a colon separates the key from the value.
local semicolon = 0
repeat
local start = semicolon + 1
semicolon = strFind(row, ';', start, true) or 0
local colon = strFind(row, ':', start, true)
if colon and (colon < semicolon or semicolon == 0) then
match[strMatch(strSub(row, start, colon - 1), '^%s*(.-)%s*$')] = strMatch(strSub(row, colon + 1, semicolon - 1), '^%s*(.-)%s*$')
end
until semicolon == 0
local hasError = false
local id = match.match
if not id then
addError(strFormat("Parameter #%d does not have a match number.", i))
hasError = true
end
-- Get the home and away teams for the match.
local home, away, t
t = match.home
if t then
home = teamLookup[t]
if not home then addError("The team '" .. t .. "' does not exist.", id); hasError = true end
else addError("Missing parameter: 'home'."); hasError = true end
t = match.away
if t then
away = teamLookup[t]
if not away then addError("The team '" .. t .. "' does not exist.", id); hasError = true end
else addError("Missing parameter: 'away'."); hasError = true end
if home == away then -- Home and away teams cannot be the same.
addError("Invalid match (home and away teams are equal).", id); hasError = true
elseif matchIDs[id] then -- A match with the given match number is already defined
addError("A match with this match number has already been defined.", id); hasError = true
end
if not hasError then -- If there is no error, store the match in the matches table.
matchIDs[id] = true
if not matches[home] then matches[home] = {} end
matches[home][away] = match
end
end
-- Construct the header
print(strFormat([[
%s
<div style="float: left">
{| class="wikitable" style="%s"
! scope="row" | Visitor team →
]],
useWebSlice and frame:expandTemplate({ title = "WebSlice-begin", args = { id = "427", title = name } }) or "",
tableStyle or "text-align: center; white-space: nowrap; width: 100%"))
for i = 1, teamCount do
local team = teams[i]
print(strFormat('! rowspan="2" scope="col" style="padding: inherit 10px" | [[%s|%s]]\n', team.pageName, team.code))
end
print('|-\n! scope="col" | Home team ↓\n')
-- The wikitext fot the table cell where a match is not defined.
local noMatchCell = '| style="background-color: ' .. noMatchColour .. '" |\n'
-- The text appended to the margin string if the match's 'dl' parameter is true
local dlString = isDL and ' <span style="font-size: 85%">(D/L)</span>' or ""
--[[
Returns a margin string from the given parameters, or nil if an error occurs.
id: The match number (used in error messages).
margin: A number suffixed with 'R' (runs) or 'W' (wickets), or 'F' for a forfeited match.
isDL: If the result is decided by the D/L method, this should be true.
isSuperOver: If the result is decided by a super over, this should be true.
]]
local getMarginString = function(id, margin, isDL, isSuperOver)
if not margin then
addError("The result 'H' or 'A' requires a margin.", id)
elseif margin == 'F' then return "Forfeited"
elseif isSuperOver then return "Super Over"
else
local n, t = tonumber(strSub(margin, 1, -2)), strUpper(strSub(margin, -1, -1))
if not n then
addError("Margin must be a valid number suffixed with R or W.", id)
elseif t == 'R' then
return strFormat("%d runs%s", n, dlString)
elseif t == 'W' then
return strFormat("%d wickets%s", n, dlString)
elseif t == 'I' then
if isLimitedOvers then
addError("A margin suffixed with 'I' cannot be used in limited-overs formats.", id)
else
return strFormat("inns & %d runs%s", n, dlString)
end
else
addError("Margin must be 'F', or a valid number suffixed with 'R', 'W' or 'I'.", id)
end
end
return nil -- Return nil in case of an error
end
-- Outputs an error cell for a given match number.
local printErrorCell = function(id)
print(strFormat('| style="background-color: %s; padding: 3px 5px; line-height: 300%%" |[[#match%s|Match %s]]\n', errorColour, id, id))
end
-- Output the main body of the table
for i = 1, teamCount do
-- Each row starts with a home team header
local home = teams[i]
local noHomeMatches = not matches[home]
print(strFormat('|-\n! scope="row" style="text-align: left; padding: 3px 5px; white-space: normal%s" | [[%s|%s]]\n', noHomeMatches and "; line-height: 275%" or "", home.pageName, home.fullName))
if noHomeMatches then -- No home matches played by the team
print(strRepeat(noMatchCell, teamCount))
else
for j = 1, teamCount do
local away = teams[j]
local match = matches[home][away]
if match then
local id, result, dl, superover = match.match, match.result, yesno(match.dl, false), yesno(match.superover, false)
if not result then -- Result not provided
addError("Missing parameter: 'result'.")
printErrorCell(id)
elseif result == 'H' then -- Home team wins
local m = getMarginString(id, match.margin, dl, superover)
if m then
print(strFormat('| style="background-color: %s; padding: 3px 5px" | %s<br />[[#match%s|%s]]\n', homeWinColour, home.shortName, id, m))
else printErrorCell(id) end
elseif result == 'A' then -- Away team wins
local m = getMarginString(id, match.margin, dl, superover)
if m then
print(strFormat('| style="background-color: %s; padding: 3px 5px" | %s<br />[[#match%s|%s]]\n', awayWinColour, home.shortName, id, m))
else printErrorCell(id) end
elseif result == 'X' then -- Match has not been played yet
print(strFormat('| style="background-color: %s; padding: 3px 5px; line-height: 300%%" | [[#match%s|Match %s]]\n', notPlayedColour, id, id))
elseif result == 'D' then -- Drawn match
if isLimitedOvers then -- No draws in limited-overs matches
addError("The result 'D' cannot be used in limited-overs formats.", id)
printErrorCell(id)
else
print(strFormat('| style="background-color: %s; padding: 3px 5px; line-height: 300%%" | [[#match%s|Match drawn]]\n', drawColour, id))
end
elseif result == 'N' then -- Abandoned match
print(strFormat('| style="background-color: %s; padding: 3px 5px" | [[#match%s|Match<br />abandoned]]\n', noResultColour, id))
elseif result == 'T' then -- Tied match
print(strFormat('| style="background-color: %s; padding: 3px 5px;" | [[#match%s|Match tied]]\n', tieColour, id))
else -- Invalid result
addError("Invalid result: '" .. result .. "'. Expected: H, A, X, N, D or T.", id)
printErrorCell(id)
end
else
-- The match is not defined.
print(noMatchCell)
end
print('\n')
end
end
end
-- Legend and notes
if isLimitedOvers then
print(strFormat([[
|}
{| class="wikitable" style="float:right; text-align: center; font-size: 90%%; width: 30%%"
| style="background-color: %s; width: 50%%" | Home team won
| style="background-color: %s; width: 50%%" | Visitor team won
|-
| style="background-color: %s; width: 50%%" | Match abandoned
| style="background-color: %s; width: 50%%" | Match tied
|}
<ul style="font-size: 90%%">
<li>'''Note''': Results listed are according to the home (horizontal) and visitor (vertical) teams.</li>
<li>'''Note''': Click on a result to see a summary of the match.</li>
</ul>
</div>
<div style="clear: both" />
%s
]],
homeWinColour, awayWinColour, noResultColour, tieColour,
useWebSlice and frame:expandTemplate({ title = 'WebSlice-end', args = {} }) or ""))
else
print(strFormat([[
|}
{| class="wikitable" style="float:right; text-align: center; font-size: 90%%;"
| style="background-color: %s; width: 33.333333%%" | Home team won
| style="background-color: %s; width: 33.333333%%" | Visitor team won
| style="background-color: %s; width: 33.333333%%" rowspan="2" | Match drawn
|-
| style="background-color: %s; width: 33.333333%%" | Match abandoned
| style="background-color: %s; width: 33.333333%%" | Match tied
|}
<ul style="font-size: 90%%">
<li>'''Note''': Results listed are according to the home (horizontal) and visitor (vertical) teams.</li>
<li>'''Note''': Click on a result to see a summary of the match.</li>
</ul>
</div>
<div style="clear: both" />
%s]],
homeWinColour, awayWinColour, noResultColour, tieColour, drawColour,
useWebSlice and frame:expandTemplate({ title = 'WebSlice-end', args = {} }) or ""))
end
if errorIndex ~= 1 then -- If there are errors, output them and insert a tracking category
return strFormat('<div class="plainlist">\n%s</div>[[Category:Pages with errors reported by Module:CricketLeagueGroupStageSummary]]\n%s', table.concat(errors), table.concat(output))
end
return table.concat(output)
end
return _module