VALORANT Esports Wiki
Advertisement

Documentation for this module may be created at Module:Standings/doc

local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_footnote = require('Module:FootnoteUtil')
local util_html = require('Module:HtmlUtil')
local util_map = require('Module:MapUtil')
local util_math = require('Module:MathUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_tournament = require('Module:TournamentUtil')
local util_vars = require('Module:VarsUtil')
local m_team = require('Module:Team')
local Region = require('Module:Region')
local i18n = require('Module:I18nUtil')

local Legend = require('Module:Legend')._main
local PopupButton = require('Module:PopupButton')

local lang = mw.getLanguage('en')
local sep = '%s*,%s*'
local argsep = '%s*;;;%s*'

local PRELOADS = {
	bo1 = {
		columns = 'bo1',
		sortmethod = 'record',
	},
	bo1points = {
		columns = 'bo1points',
		sortmethod = 'points',
	},
	bo2 = {
		isbo2 = true,
		columns = 'bo2',
		sortmethod = 'bo2points'
	},
	bo2onlypoints = {
		isbo2 = true,
		columns = 'bo2',
		sortmethod = 'points'
	},
	bo2nopoints = {
		isbo2 = true,
		columns = 'bo2nopoints',
		sortmethod = 'recordgames'
	},
	bo3 = {
		columns = 'series',
		sortmethod = 'record',
	},
	bo3diff = {
		columns = 'bo3diff',
		sortmethod = 'recordwithgames'
	},
	bo3points = {
		columns = 'seriespt',
		sortmethod = 'recordwithpoints',
	},
	bo3gamepoints = {
		columns = 'bo3gamepoints',
		sortmethod = 'points'
	},
	bo3hiddenpoints = {
		columns = 'series',
		sortmethod = 'recordwithpoints'
	},
	bo3fakepoints = {
		columns = 'series',
		sortmethod = 'recordwithgames'
	},
	bo3orderbygames = {
		columns = 'series',
		sortmethod = 'recordwithgamesnotb'
	}
}

local HEADING_DATA = {
	Place = { name = '', colspan = 1 },
	Games = { colspan = 2, fields = { 'Games', 'GamesPct' } },
	GamesBO1 = { colspan = 2, fields = { 'Series', 'SeriesPct' } },
	GamesDiff = { colspan = 3, fields = { 'Games', 'GamesPct', 'Diff' } },
	Team = { colspan = 1 },
	Series = { colspan = 2, fields = { 'Series', 'SeriesPct' } },
	SeriesBO2 = { colspan = 1 },
	Points = { colspan = 1 },
	PointsTB = { colspan = 1 },
	Group = { colspan = 1 },
	Streak = { colspan = 1 },
	RoundDifference = { colspan = 1 },
}

local FIELD_CLASSES = {
	Place = 'standings-place',
	Team = 'standings-team',
}

local COL_PRELOADS = {
	seriespt = { 'Place', 'Team', 'Series', 'Games', 'PointsTB', 'Streak', 'RoundDifference' },
	series = { 'Place', 'Team', 'Series', 'Games', 'Streak', 'RoundDifference' },
	bo1 = { 'Place', 'Team', 'GamesBO1', 'Streak', 'RoundDifference' },
	bo1points = { 'Place', 'Team', 'Points', 'GamesBO1', 'Streak', 'RoundDifference' },
	bo2 = { 'Place', 'Team', 'Points', 'SeriesBO2', 'Games', 'Streak', 'RoundDifference' },
	bo3diff = { 'Place', 'Team', 'Series', 'GamesDiff', 'Streak', 'RoundDifference' },
	bo2nopoints = { 'Place', 'Team', 'SeriesBO2', 'Games', 'Streak', 'RoundDifference' },
	bo3gamepoints = { 'Place', 'Team', 'Points', 'Games', 'Series', 'Streak', 'RoundDifference' }, -- OPL thing
}

local ARG_ORDER = { 'team', 'w', 't', 'l', 'wg', 'lg', 'p', 'tied', 'Group', 'place', 'footnotes' }

local ARG_ZEROES = { w = true, t = true, l = true, wg = true, lg = true, p = true }

local kv_sep = ':;:'
local arg_sep = ';:;'

--[[
	Structure:
	dataByTeams = {
		team1, team2, team3
		team1 = { data },
		team2 = { data },
	}
]]

util_cargo.setStoreNamespace('')

local p = {}
local h = {}

function p.fromCargo(frame)
	i18n.init('Standings')
	local args = util_args.merge()
	if util_args.castAsBool(args.forFL) then
		i18n.print = i18n.printForInclusion
	end
	local overviewPage = util_esports.getOverviewPage(args.page)
	if util_args.castAsBool(args.storeargs) then
		h.storeArgs(args, overviewPage)
	end
	if util_args.castAsBool(args.argsfromcargo) then
		local exists, message = h.queryArgs(args, overviewPage)
		if util_args.castAsBool(args.forceargquery) and not exists then
			return message
		end
	end
	h.setPreload(args)
	local data = h.getData(overviewPage, args)
	local processed = h.processData(data, args.isbo2, args)
	local fields = h.pickFields(args)
	if h.doWeStoreResultsCargo(args) then
		h.storeResultsCargo(processed, args)
	end
	if h.doWeStoreStandingsCargo(args) then
		h.storeStandingsCargo(processed, args)
	end
	local includeButton = not util_args.castAsBool(args.nobutton)
	return h.makeOutput(processed, fields, args, includeButton, overviewPage)
end

function p.fromArgs(frame)
	i18n.init('Standings')
	local args = util_args.merge()
	h.setPreload(args)
	local data = h.getDataFromArgs(args)
	local processed = h.processData(data, args.isbo2, args)
	local fields = h.pickFields(args)
	if h.doWeStoreResultsCargo(args) then
		h.storeResultsCargo(processed, args)
	end
	if h.doWeStoreStandingsCargo(args) then
		h.storeStandingsCargo(processed, args)
	end
	return h.makeOutput(processed, fields, args, overviewPage)
end

function h.storeArgs(args, page)
	local allArgs = {}
	local rowArgs = {}
	for k, v in pairs(args) do
		allArgs[k] = v
		if k:sub(1,3) == 'row' then
			rowArgs[k] = v
		end
	end
	local store = {
		_table = 'StandingsArgs',
		OverviewPage = page,
		Args = util_cargo.concatArgsForStore(allArgs),
		RowArgs = util_cargo.concatArgsForStore(rowArgs),
		Finalorder = args.finalorder,
		TournamentGroup = args.onlygroup,
		N = util_vars.setGlobalIndex('standingsCargoN'),
		IsOver = util_args.castAsBool(args.isover),
	}
	store.UniqueLine = ('%s_%s'):format(store.OverviewPage,store.N)
	util_cargo.store(store)
end

function h.queryArgs(args, page)
	local query = {
		tables = 'StandingsArgs',
		fields = {'Args','TournamentGroup'},
		where = h.queryArgsWhere(args, page)
	}
	local data = util_cargo.queryAndCast(query)
	if #data == 0 then
		return nil, 'Unable to retrieve standings data'
	elseif data[1].TournamentGroup and not args.onlygroup then
		return nil, 'Query does not currently support multiple groups'
	elseif #data > 1 then
		return nil, 'Multiple Results Found - Cannot print single standings table'
	end
	local newArgs = util_cargo.extractArgs(data[1].Args)
	util_table.mergeDontOverwrite(args, newArgs)
	return true
end

function h.queryArgsWhere(args, page)
	local tbl = {
		('OverviewPage="%s"'):format(page),
		util_cargo.whereFromArg('TournamentGroup="%s"', args.onlygroup)
	}
	return util_table.concat(tbl, ' AND ')
end

function h.setPreload(args)
	if not args.preload then
		return
	end
	local preload = lang:lc(args.preload)
	if not PRELOADS[preload] then
		error('Invalid preload')
	end
	args.isbo2 = util_args.castAsBool(args.isbo2) or PRELOADS[preload].isbo2
	args.columns = args.columns or PRELOADS[preload].columns
	args.sortmethod = args.sortmethod or PRELOADS[preload].sortmethod
end

-- from args
function h.getDataFromArgs(args)
	local i = 1
	local data = h.argsToTable(args)
	h.processArgData(data)
	return data
end

function h.argsToTable(args)
	local tbl = {}
	for i, arg in ipairs(args) do
		local thisdata = util_text.split(arg, argsep)
		local thisteam = m_team.teamlinkname(thisdata[1])
		tbl[i] = thisteam
		tbl[thisteam] = {}
		for k, v in ipairs(thisdata) do
			local key = ARG_ORDER[k]
			if v ~= '' then
				if key == 'footnotes' then
					tbl[thisteam][key] = util_text.split(v,'%s*;;%s*')
				else
					tbl[thisteam][key] = tonumber(v) or v
				end
			elseif ARG_ZEROES[key] then
				tbl[thisteam][key] = 0
			elseif key == 'footnotes' then
				tbl[thisteam][key] = {}
			end
		end
	end
	return tbl
end

function h.processArgData(data)
	local curplace = 1
	for i, team in ipairs(data) do
		local row = data[team]
		if util_args.castAsBool(row.tied) then
			row.sort = curplace
		else
			row.sort = i
			curplace = i
		end
		row.tb = row.p
	end
end

-- from cargo
function h.getData(overviewPage, args)
	local query = h.makeQuery(overviewPage, args)
	local result = util_cargo.queryAndCast(query)
	local teams = h.teamsFromList(args.teamlist)
	local dataByTeams = h.compileTeams(result, teams, util_args.castAsBool(args.onlylist))
	if util_args.castAsBool(args.groups) or args.onlygroup then
		h.addGroupData(dataByTeams, overviewPage, args.onlygroup)
	end
	h.adjustProcessedFromArgs(dataByTeams, args)
	if args.finalorder then
		h.sortTeamsByArg(dataByTeams, args.finalorder, args.finalplaces)
	else
		h.sortTeamsByCargo(dataByTeams, lang:lc(args.sortmethod or 'record'))
	end
	return dataByTeams
end

function h.makeQuery(page, args)
	local query = {
		tables = h.getTables(),
		join = h.getJoin(),
		fields = h.getCargoFields(args),
		where = h.makeWhere(page, args),
		orderBy = 'N_Page ASC, N_TabInPage ASC, N_MatchInTab ASC',
		groupBy = 'UniqueMatch',
	}
	return query
end

function h.getTables()
	return {
		'MatchSchedule=MS',
		'TeamRedirects=TR1',
		'Teams=T1',
		'TeamRedirects=TR2',
		'Teams=T2',
		'TournamentRosters=Ros1',
		'TournamentRosters=Ros2',
	}
end

function h.getJoin()
	return {
		'MS.Team1 = TR1.AllName',
		'TR1._pageName=T1._pageName',
		'MS.Team2 = TR2.AllName',
		'TR2._pageName=T2._pageName',
		'MS.PageAndTeam1 = Ros1.PageAndTeam',
		'MS.PageAndTeam2 = Ros2.PageAndTeam',
	}
end

function h.getCargoFields(args)
	local tbl = {
		'MS.Team1Final=Team1',
		'MS.Team2Final=Team2',
		'MS.Winner [number]',
		'MS.Team1Score [number]',
		'MS.Team2Score [number]',
		'MS.Team1Points [number]',
		'MS.Team2Points [number]',
		'MS.Team1PointsTB [number]',
		'MS.Team2PointsTB [number]',
		'MS.Team1Rounds [number]',
		'MS.Team2Rounds [number]',
		'MS.Tab',
		'COALESCE(Ros1.Region, T1.Region)=Team1Region',
		'COALESCE(Ros2.Region, T2.Region)=Team2Region',
		'MS.FF [number]',
	}
	if not util_args.castAsBool(args.nofootnotes) then
		util_table.mergeArrays(tbl, { 'Team1Footnote', 'Team2Footnote' })
	end
	return tbl
end

function h.makeWhere(page, args)
	local tbl = {
		('MS.OverviewPage="%s"'):format(page),
		-- 'Winner IS NOT NULL',
		args.special_where,
	}
	if lang:lc(args.tiebreakers or '') == 'only' then
		tbl[#tbl+1] = '(IsTiebreaker = "1")'
	elseif not util_args.castAsBool(args.tiebreakers) then
		tbl[#tbl+1] = '(IsTiebreaker != "1" OR IsTiebreaker IS NULL)'
	end
	if args.excludetabs then
		for v in util_text.gsplit(args.excludetabs, sep) do
			tbl[#tbl+1] = ('Tab != "%s"'):format(v)
		end
	end
	if args.onlytabs then
		local onlyrounds_tbl = {}
		for v in util_text.gsplit(args.onlytabs, sep) do
			onlyrounds_tbl[#onlyrounds_tbl+1] = ('Tab = "%s"'):format(v)
		end
		tbl[#tbl+1] = ('(%s)'):format(util_table.concat(onlyrounds_tbl, ' OR '))
	end
	return util_table.concat(tbl, ' AND ')
end

function h.teamsFromList(teamlist)
	if not teamlist then
		return {}
	end
	local teams = util_map.split(teamlist, sep, m_team.teamlinkname)
	for _, team in ipairs(teams) do
		h.addTeamZeros(teams, team)
	end
	return teams
end

function h.compileTeams(result, teams, onlylist)
	local hasteams = next(teams) and true
	local tbl = mw.clone(teams)
	for _, row in ipairs(result) do
		local team1 = m_team.teamlinkname(row.Team1)
		local team2 = m_team.teamlinkname(row.Team2)
		if not hasteams then
			h.initializeTeam(tbl, team1)
			h.initializeTeam(tbl, team2)
			h.addTeamData(tbl[team1], tbl[team2], row)
		elseif onlylist and tbl[team1] and tbl[team2] then
			h.addTeamData(tbl[team1], tbl[team2], row)
		elseif not onlylist then
			if tbl[team1] then
				h.addTeam1Data(tbl[team1], row)
			end
			if tbl[team2] then
				h.addTeam2Data(tbl[team2], row)
			end
		end
	end
	return tbl
end

function h.initializeTeam(tbl, team)
	if team and not tbl[team] then
		tbl[#tbl+1] = team
		h.addTeamZeros(tbl, team)
	end
	return
end

function h.addTeamZeros(tbl, team)
	tbl[team] = {
		w = 0,
		t = 0,
		l = 0,
		p = 0,
		tb = 0,
		wg = 0,
		lg = 0,
		strN = 0,
		rDiff = 0,
		footnotes = {},
	}
	return
end

function h.addTeamData(team1, team2, row)
	-- here is where all incrementing happens
	-- if no winner is specified in the cell, unconditionally nothing will happen here
	-- this is important because we populate incomplete series results
	-- while a series is underway
	h.addTeam1Data(team1, row)
	h.addTeam2Data(team2, row)
end

function h.addTeam1Data(team, row)
	team.region = row.Team1Region
	if not row.Winner then return end
	team.w = team.w + (row.Winner == 1 and 1 or 0)
	team.l = team.l + (row.Winner == 2 and 1 or 0)
	
	-- in the unique case that both teams FF, the winner will be 0 but we add a loss
	team.l = team.l + (row.FF == 0 and 1 or 0)
	
	team.t = team.t + (row.Winner == 0 and 1 or 0)
	team.p = team.p + (row.Team1Points or 0)
	team.wg = team.wg + (row.Team1Score or 0)
	team.lg = team.lg + (row.Team2Score or 0)
	team.tb = team.tb + (row.Team1PointsTB or 0)
	team.footnotes[#team.footnotes+1] = h.footnoteText(row.Tab, row.Team1Footnote)
	h.addStreak(team, row.Winner == 1, row.Winner == 0, row.Winner == 2)
	h.addDifference(team.rDiff, row.Team1Rounds, row.Team2Rounds)
end

function h.addTeam2Data(team, row)
	team.region = row.Team2Region
	if not row.Winner then return end
	team.w = team.w + (row.Winner == 2 and 1 or 0)
	team.l = team.l + (row.Winner == 1 and 1 or 0)
	team.l = team.l + (row.FF == 0 and 1 or 0)
	team.t = team.t + (row.Winner == 0 and 1 or 0)
	team.p = team.p + (row.Team2Points or 0)
	team.wg = team.wg + (row.Team2Score or 0)
	team.lg = team.lg + (row.Team1Score or 0)
	team.tb = team.tb + (row.Team2PointsTB or 0)
	team.footnotes[#team.footnotes+1] = h.footnoteText(row.Tab, row.Team2Footnote)
	h.addStreak(team, row.Winner == 2, row.Winner == 0, row.Winner == 1)
	h.addDifference(team.rDiff, row.Team2Rounds, row.Team1Rounds)
end

function h.addStreak(team, isWin, isDraw, isLoss)
	local result = isWin and 'W' or isDraw and 'D' or isLoss and 'L'
	team.strN = result == team.strResult and team.strN + 1 or 1
	team.strResult = result
end

function h.addDifference(rDiff, Team1Rounds, Team2Rounds)
	--if not Team1Rounds and not Team2Rounds then return nil end
	return rDiff + (Team1Rounds - Team2Rounds)
end

function h.footnoteText(tab, footnote)
	if not footnote then return nil end
	return ('%s: %s'):format(tab, footnote)
end

-- adjust from args
function h.adjustProcessedFromArgs(data, args)
    local arg_adjust = {
        footnotes = h.getAdjustmentArgData(args.footnotes),
        p = h.getAdjustmentArgData(args.pointadjust),
        tb = h.getAdjustmentArgData(args.tbpointadjust),
        w = h.getAdjustmentArgData(args.wadjust),
        l = h.getAdjustmentArgData(args.ladjust),
        wg = h.getAdjustmentArgData(args.wgadjust),
        lg = h.getAdjustmentArgData(args.lgadjust),
    }
    for _, teamstr in ipairs(data) do
        local team = data[teamstr]
        team.p = team.p + (tonumber(arg_adjust.p[teamstr] or 0))
        team.tb = team.tb + (tonumber(arg_adjust.tb[teamstr] or 0))
        team.w = team.w + (tonumber(arg_adjust.w[teamstr] or 0))
        team.l = team.l + (tonumber(arg_adjust.l[teamstr] or 0))
        team.wg = team.wg + (tonumber(arg_adjust.wg[teamstr] or 0))
        team.lg = team.lg + (tonumber(arg_adjust.lg[teamstr] or 0))
        team.footnotes = h.processFootnotes(team.footnotes, arg_adjust.footnotes[teamstr])
    end 
end

function h.getAdjustmentArgData(arg)
	if not arg then
		return {}
	end
	local tbl = {}
	for val in arg:gmatch('%(%(%((.-)%)%)%)') do
		k, v = val:match('(.*)===(.*)')
		tbl[m_team.teamlinkname(k)] = v
	end
	return tbl
end

function h.processFootnotes(from_team, from_arg)
	from_team[#from_team+1] = from_arg
	local tbl = { Team = from_team }
	return tbl
end

-- sort
function h.sortTeamsByCargo(data, sortmethod)
	local f = util_tournament.getSortMethod(sortmethod)
	util_map.dictRowsInPlace(data, f)
	h.sortTeams(data)
end

function h.sortTeamsByArg(data, finalorder, placesArg)
	local order_tbl = util_map.split(finalorder, nil, m_team.teamlinkname)
	local places_tbl = placesArg and util_text.split(placesArg, sep) or {}
	for i, v in ipairs(order_tbl) do
		local team = data[v]
		if not team then
			error(('%s is not a valid team code'):format(v))
		end
		-- not sure why i would re-sort by place if finalorder is given
		-- that seems 100% wrong
		-- but leaving that here & commented just in case theres some reason
		-- team.sort = places_tbl[i] and (tonumber(places_tbl[i]) * -1) or (i * -1)
		team.sort = i * -1
		team.place = places_tbl[i]
	end
	h.sortTeams(data)
end

function h.sortTeams(data)
	table.sort(data,
		function(a,b)
			if data[a].sort == data[b].sort then
				return lang:lc(a) < lang:lc(b)
			else
				return data[a].sort > data[b].sort
			end
		end
	)
end

-- process after sort
function h.addGroupData(data, page, onlygroup)
	local groupdata = h.groupsFromCargo(page)
	for i, team in ipairs(data) do
		if onlygroup and groupdata[team] ~= onlygroup then
			data[i] = false
		else
			data[team].group = groupdata[team]
		end
	end
	util_table.removeFalseEntries(data)
end

function h.groupsFromCargo(page)
	local result = util_tournament.getGroups(page)
	return util_cargo.makeConstDict(result, 'Team', 'GroupName')
end

function h.processData(data, isbo2, args)
	local processed = {}
	local place = 1
	local lastsort
	for k, teamstr in ipairs(data) do
		local team = data[teamstr]
		local thissort = team.sortdisplay or team.sort
		if thissort ~= lastsort then
			place = k
			lastsort = thissort
		end
		processed[#processed+1] = {
			Place = team.place or place,
			Team = h.getTeamDisplay(args, teamstr, data[teamstr]),
			TeamStr = teamstr,
			Games = ('%s - %s'):format(team.wg, team.lg),
			wg = team.wg,
			lg = team.lg,
			w = team.w,
			l = team.l,
			t = team.t,
			GamesPct = util_esports.winrate(team.wg, team.lg, 1) .. '%',
			Points = team.p,
			PointsTB = team.tb,
			Group = team.group,
			Diff = util_math.printWithSign(team.wg - team.lg),
			footnotes = team.footnotes,
			Streak = team.strResult and i18n.print('streak' .. team.strResult, team.strN),
			strN = team.strN,
			strResult = team.strResult,
			RoundDifference = util_math.printWithSign(team.rDiff)
		}
		local thisline = processed[#processed]
		if isbo2 then
			thisline.SeriesBO2 = ('%s - %s - %s'):format(team.w, team.t, team.l)
			thisline.SeriesBO2Store = ('%s-%s-%s'):format(team.w, team.t, team.l)
		else
			thisline.Series = ('%s - %s'):format(team.w, team.l)
			thisline.SeriesPct = util_esports.winrate(team.w, team.l, 1) .. '%'
		end
	end
	return processed
end

function h.getTeamDisplay(args, team, teamData)
	local tbl = {}
	tbl[#tbl+1] = h.getRegionDisplay(args, teamData.region)
	tbl[#tbl+1] = m_team[args.teamstyle or 'rightlonglinked'](team)
	return util_table.concat(tbl, '')
end

function h.getRegionDisplay(args, region)
	if util_vars.getVar('Event Region') ~= 'International' and not util_args.castAsBool(args.forceregion) then
		return false
	end
	return Region(region):image()
end

-- start output stuff
function h.pickFields(args)
	local tbl = {
		headings = h.headingsFromArgs(args),
		fields = {}
	}
	h.addFieldsFromHeadings(tbl.headings, tbl.fields)
	if util_args.castAsBool(args.groups) then
		table.insert(tbl.headings,2,'Group')
		table.insert(tbl.fields,2,'Group')
	end
	return tbl
end

function h.headingsFromArgs(args)
	if args.columnlist then
		return util_text.split(args.columnlist,sep)
	elseif args.columns then
		return COL_PRELOADS[lang:lc(args.columns)]
	else
		return COL_PRELOADS.bo1
	end
end

function h.addFieldsFromHeadings(headings, fields)
	for _, v in ipairs(headings) do
		if HEADING_DATA[v].fields then
			for _, field in ipairs(HEADING_DATA[v].fields) do
				fields[#fields+1] = field
			end
		else
			fields[#fields+1] = v
		end
	end
end

-- print output
function h.makeOutput(processed, fields, args, includeButton, page)
	util_footnote.init()
	local output = mw.html.create('div'):addClass('standings-outer-div')
	local tbl_div = output:tag('div')
	local tbl = tbl_div:tag('table')
		:addClass('wikitable2')
		:addClass('standings')
	h.addFirstHeading(tbl, args, page, #fields.fields)
	h.addHeadings(tbl, fields.headings)
	local classes = h.getClasses(args)
	h.printTable(tbl, processed, fields, classes, includeButton, page)
	util_footnote.printTexts(output)
	return output
end

function h.addFirstHeading(tbl, args, page, colspan)
	local th = tbl:tag('tr'):tag('th'):attr('colspan',colspan)
	args.display = h.getDisplay(args, page)
	if util_args.castAsBool(args.legend) then
		Legend(th, args)
	else
		th:wikitext(args.display or i18n.print('StandingsPlain'))
	end
end

function h.getDisplay(args, page)
	if args.display then
		return args.display
	else
		local eventName = h.getEventName(page)
		if eventName then
			return i18n.print('Standings', eventName)
		end
	end
end

function h.getEventName(page)
	if not page then return nil end
	local query = {
		tables = 'Tournaments',
		fields = 'StandardName',
		where = ('OverviewPage="%s"'):format(page)
	}
	return util_cargo.getOneResult(query)
end

function h.addHeadings(tbl, headings)
	local tr = tbl:tag('tr')
	for _, v in ipairs(headings) do
		tr:tag('th')
			:attr('colspan',HEADING_DATA[v].colspan)
			:wikitext(i18n.print(v))
			:addClass('column-label-small')
	end
end

function h.getClasses(args)
	local classes = {
		places = args.places and util_map.split(args.places,sep, h.getClassName) or {}
	}
	local max = #classes.places
	classes.rows = util_args.numberedArgsToTable(args, 'row', true, max) or {}
	util_map.inPlace(classes.rows, h.getClassName, max)
	return classes
end

function h.getClassName(class)
	-- prepend every individual "word" in the class with 'standings-'
	return class:gsub('([^ ]+)','standings-%1')
end

function h.printTable(tbl, processed, fields, classes, includeButton, page)
	for i, row in ipairs(processed) do
		local tr = tbl:tag('tr')
			:addClass(classes.rows[i])
		util_esports.addTeamHighlighter(tr, row.TeamStr)
		for _, v in ipairs(fields.fields) do
			local td = tr:tag('td')
				:wikitext(row[v])
				:addClass(FIELD_CLASSES[v])
			if row.footnotes[v] then
				util_footnote.tag(td, row.footnotes[v])
			end
			if v == 'Place' then
				td:addClass(classes.places[i])
			elseif v == 'Team' and includeButton then
				PopupButton.tth(td, page, m_team.short(row.TeamStr) .. ' Schedule', row.TeamStr)
			end
		end
	end
end

-- store cargo
function h.doWeStoreResultsCargo(args)
	local nocargo = util_args.castAsBool(args.nocargo)
	local isover = util_args.castAsBool(args.isover)
	local useasresults = util_args.castAsBool(args.useasresults)
	local argsfromcargo = util_args.castAsBool(args.argsfromcargo)
	return not nocargo and isover and useasresults and not argsfromcargo
end

function h.storeResultsCargo(data, args)
	local title = mw.title.getCurrentTitle().text
	local N = util_vars.setGlobalIndex('standingsN')
	for i, team in ipairs(data) do
		local tbl = {
			_table = 'TournamentResults',
			Event = util_vars.getVar('Event Name'),
			Phase = util_args.castAsBool(args.groupasphase) and (args.onlygroup or team.Group) or args.phase,
			Tier = util_vars.getVar('Event Tier'),
			Date = args.date or util_vars.getVar('Event Date'),
			Place = team.Place,
			['Place_Number'] = team.Place,
			Team = team.TeamStr,
			IsAchievement = true,
			UniqueLine = ('%s_%s_%s'):format(title, N, i),
			LastResult = team.SeriesBO2Store or team.Series,
			GroupName = team.Group,
			-- this should be fixed to not rely on any vardefine, need to add real group support
			LastOpponent_Markup = m_team.rightshort('group stage'),
			-- this should probably display group
			RosterPage = args.rosterpage or title,
			OverviewPage = util_esports.getOverviewPage(),
		}
		tbl.PageAndTeam = ('%s_%s'):format(tbl.RosterPage, tbl.Team)
		util_cargo.store(tbl)
	end
end

function h.doWeStoreStandingsCargo(args)
	if util_args.castAsBool(args.nocargo) then return false end
	if not util_vars.getBool('hasInfobox') then return false end
	return true
end

function h.storeStandingsCargo(processed, args)
	local title = mw.title.getCurrentTitle().text
	for i, team in ipairs(processed) do
		local tbl = {
			_table = "Standings",
			OverviewPage = util_esports.getOverviewPage(),
			Team = team.TeamStr,
			PageAndTeam = ('%s_%s'):format(args.rosterpage or title, team.TeamStr),
			N = i,
			Place = team.Place,
			WinGames = team.wg,
			LossGames = team.lg,
			WinSeries = team.w,
			LossSeries = team.l,
			TieSeries = team.t,
			Points = team.Points,
			PointsTiebreaker = team.PointsTB,
			Streak = team.strN,
			StreakDirection = team.strResult,
			-- Footnotes = util_table.concat(team.footnotes,'; '),
		}
		util_cargo.store(tbl)
	end
end

return p
Advertisement