Module:MatchSchedule

local util_args = require('Module:ArgsUtil') local util_vars = require('Module:VarsUtil') local util_cargo = require('Module:CargoUtil') local util_map = require('Module:MapUtil') local util_table = require('Module:TableUtil') local util_time = require('Module:TimeUtil') local util_text = require('Module:TextUtil') local util_esports = require('Module:EsportsUtil') local m_team = require('Module:Team') local Patch = require('Module:PatchVariablesClass') local ScoreboardTab = require('Module:ScoreboardTabVariablesClass')

local Phase = require('Module:Phase')

local i18n = require('Module:I18nUtil') local lang = mw.getLanguage('en')

local MATCH_FIELDS = { 'Round', 'Group', 'Team1', 'Team2', 'Result', 'BestOf', 'DateTime_UTC', 'DateTime_PST', 'DateTime_CET', 'DateTime_KST', 'PBP', 'Color', 'MVP', 'VodInterview', 'With', 'Reddit', 'Vod', 'Vod2', 'Vod3', 'Vod4', 'Vod5', 'Vod6', 'Vod7' }

local GAME_ARGS = { 'Blue', 'Red', 'Winner', 'FF', 'Selection', 'MatchHistory', 'Recap', 'Vod', 'VodPB', 'VodGameStart', 'VodPostgame', 'VodHighlights', 'VodInterview', 'InterviewWith', 'MVP', 'MVPPoints', 'BlueFootnote', 'RedFootnote', 'Summary' }

local GAME_FIELDS = {}

local ALLOWED_TZ = { PST = true, KST = true, CET = true }

local h = {} local p = {} function p.start(frame) i18n.init('MatchSchedule') local args = util_args.merge local tbl = mw.html.create args.tab = args.tab and Phase(args.tab):name or 'Matches' tbl:tag('tr'):tag('th'):attr('colspan','50'):wikitext(args.tab) local tr = tbl:tag('tr') for _, v in ipairs(MATCH_FIELDS) do		tr:tag('th'):wikitext(i18n.print(v)) end for _, v in ipairs(GAME_FIELDS) do		tr:tag('th'):wikitext(i18n.print(v)) end h.setStartVars(args) return ' ' end

function h.setStartVars(args) util_vars.setGlobalIndex('N_TabInPage') util_vars.resetGlobalIndex('N_MatchInTab') util_vars.setVar('OverviewPage', util_esports.getOverviewPage) util_vars.setVar('TabName', args.tab) util_vars.setVarOnlyIf('Bestof', args.bestof) util_vars.setVarOnlyIf('MVPPoints', args.mvppoints) util_vars.setVarOnlyIf('shownname', args.shownname) if args.phase then local thisphase = Phase(args.phase):name local lastphase = util_vars.getVar('Phase') if lastphase ~= thisphase then util_vars.setVar('Phase', thisphase) util_vars.setGlobalIndex('Phase_N') end end end

function h.getTZData(args) if not args.date then return {} end local time = ('%s %s'):format(args.date, args.time or '23:59') if not args.timezone or not ALLOWED_TZ[args.timezone] then error('Missing or invalid timezone. Allowed values: PST, CET, KST.') end local tz = args.timezone or 'PST' local dst = util_args.norm(args.dst) return util_time.getTimezones(time, tz, dst) end

function h.makeCargoMatchFields(args) local tzdata = h.getTZData(args) local tbl = { _table = 'MatchSchedule', Team1 = args.team1, -- was previously cast Team2 = args.team2, -- was previously cast Team1Points = args.team1points, Team2Points = args.team2points, Team1PointsTB = args.team1pointstb, Team2PointsTB = args.team2pointstb, DateTime_UTC = tzdata.UTC, HasTime = util_args.isDefined(args.time), OverviewPage = util_vars.getVar('OverviewPage'), Winner = args.Winner, -- cast version with capital letter Team1Score = args.team1score, Team2Score = args.team2score, FF = args.ff, WinnerScoreUnknown = args.winnerscoreunknown, DST = args.dst, IsFlexibleStart = util_args.castAsBool(args.flex), ExcludeH2H = util_args.castAsBool(args.excludeh2h), BestOf = args.bestof or util_vars.getVar('Bestof'), ShownRound = args.round or util_vars.getVar('Round'), Phase = util_vars.getVar('Phase'), N_MatchInPage = util_vars.setGlobalIndex('MS_Overall'), Tab = util_vars.getVar('TabName'), N_MatchInTab = util_vars.setGlobalIndex('N_MatchInTab'), N_TabInPage = util_vars.getGlobalIndex('N_TabInPage'), N_Page = util_vars.getVar('N_Page'), Player1 = args.player1, Player2 = args.player2, IsTiebreaker = util_args.castAsBool(args.istb), OverrideAllowPredictions = util_args.castAsBool(args.predictionoverride), Stream = args.stream, StreamDisplay = args.streamdisplay, Venue = args.venue, CastersPBP = args.pbp, CastersColor = args.color, Casters = h.getAllCasters(args.pbp, args.color), MVP = args.mvp, MVPPoints = args.mvppoints or util_vars.getVar('MVPPoints'), VodInterview = args.vodinterview, Vod = args.vod, Vod2 = args.vod2, Vod3 = args.vod3, Vod4 = args.vod4, Vod5 = args.vod5, Vod6 = args.vod6, Vod7 = args.vod7, InterviewWith = args.with, Recap = args.recap, Reddit = args.reddit, Team1Footnote = args.team1footnote, Team2Footnote = args.team2footnote, Footnote = args.footnote, }	tbl.InitialN_MatchInTab = args.initialorder or tbl.N_MatchInTab tbl.InitialPageAndTab = args.initialtab local title = mw.title.getCurrentTitle.text tbl.UniqueMatch = title .. '_' .. tbl.Tab .. '_' .. tbl.N_MatchInTab tbl.ShownName = args.shownname or util_vars.getVar('shownname') or tbl.OverviewPage tbl.Team1Final = args.team1final and m_team.teamlinkname(args.team1final) or tbl.Team1 tbl.Team2Final = args.team2final and m_team.teamlinkname(args.team2final) or tbl.Team2 -- TODO: these should be made able to cope with nil Team1, Team2 tbl.PageAndTeam1 = tbl.OverviewPage .. '_' .. tbl.Team1 tbl.PageAndTeam2 = tbl.OverviewPage .. '_' .. tbl.Team2 h.getMatchDay(tbl, tzdata.UTC, args.matchday) return tbl end

function h.getAllCasters(pbp, color) local tbl = {} tbl[#tbl+1] = pbp tbl[#tbl+1] = color return util_table.concat(tbl, ',') end

function h.getMatchDay(tbl, tzdata, gameday) local thistime = tonumber(util_time.unix(tzdata)) local lasttime = tonumber(util_vars.getVar('MatchTime') or '') local lastday = tonumber(util_vars.getVar('MatchDay') or '') util_vars.setVar('MatchTime', thistime) if gameday then tbl.MatchDay = gameday util_vars.setVar('MatchDay', gameday) elseif not lasttime then tbl.MatchDay = 1 util_vars.setVar('MatchDay', 1) elseif (thistime - lasttime) > 43200 then tbl.MatchDay = lastday + 1 util_vars.setVar('MatchDay', lastday + 1) else tbl.MatchDay = lastday util_vars.setVar('MatchDay', lastday) end end

function h.castGameArgs(game) game.Blue = game.Blue and m_team.teamlinkname(game.Blue) game.Red = game.Red and m_team.teamlinkname(game.Red) h.castAndValidateWinner(game, 'Blue', 'Red') end

function h.makeCargoGameFields(args, match) local tbl = {} for i, game in ipairs(args) do		tbl[i] = mw.clone(game) thisgame = tbl[i] -- alias for convenience thisgame._table = 'MatchScheduleGame' thisgame.Blue = game.Blue thisgame.Red = game.Red thisgame.MVPPoints = thisgame.MVPPoints or match.MVPPoints thisgame.OverviewPage = match.OverviewPage thisgame.N_GameInMatch = i		thisgame.UniqueMatch = match.UniqueMatch thisgame.N_MatchInTab = match.N_MatchInTab thisgame.N_TabInPage = match.N_TabInPage thisgame.N_Page = match.N_Page thisgame.WrittenSummary = game.Summary thisgame.Reddit = game.Reddit thisgame.MatchHistory = thisgame.MatchHistory or match.qq_mh h.setGameIds(thisgame, match) thisgame.UniqueLine = match.UniqueMatch .. '_' .. i		if thisgame.Selection then h.sideSelection(thisgame) end local allowed_teams = { [match.Team1] = true, [match.Team2] = true } if thisgame.Blue and not allowed_teams[thisgame.Blue] then error(('%s: Invalid blue team (%s) in match %s game %s'):format(match.Tab, thisgame.Blue, thisgame.N_MatchInTab, i)) end if thisgame.Red and not allowed_teams[thisgame.Red] then error(('%s: Invalid red team (%s) in game %s in match %s'):format(match.Tab, thisgame.Red, thisgame.N_MatchInTab, i)) end end return tbl end

function h.setGameIds(thisgame, match) thisgame.GameID_Wiki = ('%s_%s_%s_%s'):format(		match.OverviewPage,		match.Tab,		thisgame.N_MatchInTab,		thisgame.N_GameInMatch	) thisgame.ScoreboardID_Wiki = ('%s_%s_%s_%s'):format(		match.OverviewPage,		ScoreboardTab:_get('tab') or match.Tab,		ScoreboardTab:match(thisgame.N_GameInMatch) or thisgame.N_MatchInTab,		thisgame.N_GameInMatch	) end

function h.sideSelection(thisgame) if thisgame.Selection == '1' or thisgame.Selection == '2' then h.selectionFromNumber(thisgame, match) else thisgame.Selection = m_team.teamlinkname(thisgame.Selection) end end

function h.selectionFromNumber(thisgame) if thisgame.Selection == '1' then thisgame.Selection = thisgame.Blue elseif thisgame.Selection == '2' then thisgame.Selection = thisgame.Red end end

function h.makeMatchDisplay(tbl, args) local display = mw.clone(tbl) local tzdata = h.getTZData(args) if not tbl.WinnerScoreUnknown then display.Result = ("%s - %s"):format(			tbl.Winner == '1' and ("%s"):format(tbl.Team1Score or ) or tbl.Team1Score or ,			tbl.Winner == '2' and ("%s"):format(tbl.Team2Score or ) or tbl.Team2Score or 		) else display.Result = ("%s - %s"):format(			tbl.WinnerScoreUnknown == '1' and "W" or "L" or ,			tbl.WinnerScoreUnknown == '2' and "W" or "L" or 		) end display.Team1 = m_team.plainlinked(tbl.Team1) display.Team2 = m_team.plainlinked(tbl.Team2) display.DateTime_UTC = tbl.DateTime_UTC and lang:formatDate('D Y-m-d H:i', tbl.DateTime_UTC) display.DateTime_PST = h.getTZDisplay(tzdata.PST) display.DateTime_CET = h.getTZDisplay(tzdata.CET) display.DateTime_KST = h.getTZDisplay(tzdata.KST) display.Points = (tbl.Team1Points or tbl.Team2Points) and ('%s - %s'):format(tbl.Team1Points or , tbl.Team2Points or ) display.PointsTB = (tbl.Team1PointsTB or tbl.Team2PointsTB) and ('%s - %s'):format(tbl.Team1PointsTB or , tbl.Team2PointsTB or ) display.PBP = util_esports.playersLinked(args.pbp) display.Color = util_esports.playersLinked(args.color) display.MVP = util_esports.playersLinked(args.mvp) display.With = util_esports.playersLinked(args.with) display.Reddit = args.reddit and ('[%s]'):format(args.reddit) display.Recap = args.recap and ('[%s]'):format(args.recap) display.VodInterview = args.vodinterview and ('[%s]'):format(args.vodinterview) display.Vod = args.vod and ('[%s]'):format(args.vod) display.Vod2 = args.vod2 and ('[%s]'):format(args.vod2) display.Vod3 = args.vod3 and ('[%s]'):format(args.vod3) display.Vod4 = args.vod4 and ('[%s]'):format(args.vod4) display.Vod5 = args.vod5 and ('[%s]'):format(args.vod5) display.Vod6 = args.vod6 and ('[%s]'):format(args.vod6) display.Vod7 = args.vod7 and ('[%s]'):format(args.vod7) return display end

function h.getTZDisplay(str) if not str then return nil end return str:match('(%d%d:%d%d)') end

function h.makeGameDisplay(game) local display = mw.clone(game) display.Blue = game.Blue and m_team.short(game.Blue) or '' display.Red = game.Red and m_team.short(game.Red) or '' display.Vod = h.printExternalLink(game.Vod) display.VodPB = h.printExternalLink(game.VodPB) display.VodGameStart = h.printExternalLink(game.VodGameStart) display.VodPostgame = h.printExternalLink(game.VodPostgame) display.VodHighlights = h.printExternalLink(game.VodHighlights) display.Recap = h.printExternalLink(game.recap) display.VodInterview = h.printExternalLink(game.VodInterview) display.MatchHistory = h.printExternalLink(game.MatchHistory) display.MVP = util_esports.playersLinked(game.MVP) display.InterviewWith = util_esports.playersLinked(game.InterviewWith) display.Summary = game.Summary and 'Y' or '' return display end

function h.printExternalLink(url) if not url then return nil end return ('[%s]'):format(url) end

function h.addGameTotalScoreToMatchAndValidate(match_tbl, games_cargo, ignorewarnings) local team1 = match_tbl.Team1 local team2 = match_tbl.Team2 local matchScores = { [team1] = match_tbl.Team1Score, [team2] = match_tbl.Team2Score, }	local gameScores = { [team1] = 0, [team2] = 0, hasTotals = false, }	h.countGameScores(gameScores, games_cargo) if match_tbl.Winner then h.validateTotalScores(matchScores, gameScores, match_tbl, ignorewarnings) elseif gameScores.hasTotals then match_tbl.Team1Score = gameScores[team1] match_tbl.Team2Score = gameScores[team2] end end

function h.countGameScores(gameScores, games_cargo) for _, game in ipairs(games_cargo) do		local winKey = (game.Winner == '1' and 'Blue') or (game.Winner == '2' and 'Red') if winKey then gameScores.hasTotals = true local winTeam = game[winKey] gameScores[winTeam] = (gameScores[winTeam] or 0) + 1 end end end

function h.validateTotalScores(matchScores, gameScores, match_tbl, ignorewarnings) if not gameScores.hasTotals then return end if ignorewarnings then return end if match_tbl.FF then return end for team, v in pairs(matchScores) do		v = v and tonumber(v) if gameScores[team] ~= v then error(('Non-matching match (%s) & game (%s) scores for team '):format( v, gameScores[team] ) .. team) end end end

function h.printMatchRow(display_match, games) if not games then games = { {} } end local ngames = #games local tbl = mw.html.create for i, game in ipairs(games) do		local tr = tbl:tag('tr') if i == 1 then for _, v in ipairs(MATCH_FIELDS) do				tr:tag('td'):attr('rowspan',ngames):wikitext(display_match[v]) end end h.printGameRow(tr, game) end return tbl end

function h.printGameRow(tr, game) for _, v in ipairs(GAME_FIELDS) do		tr:tag('td'):wikitext(game[v]) end return end

return p