Module:TournamentResults

From Leaguepedia | League of Legends Esports Wiki
Jump to: navigation, search

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

local util_args = require('Module:ArgsUtil')
local util_cargo = require('Module:CargoUtil')
local util_esports = require('Module:EsportsUtil')
local util_html = require('Module:HTMLUtil')
local util_math = require('Module:MathUtil')
local util_table = require('Module:TableUtil')
local util_text = require('Module:TextUtil')
local util_toggle = require('Module:ToggleUtil')
local util_vars = require('Module:VarsUtil')

local m_currency = require('Module:Currency')
local m_team = require('Module:Team')

local lang = mw.getLanguage('en')

local i18n = {
	intro = 'are spread among the teams as seen below:',
	temp_date = '(as of %s)',
	col_place = 'Place',
	col_prize = 'Prize',
	col_usd = '≈Prize (USD)',
	col_eur = '≈Prize (EUR)',
	col_prizepct = 'Prize (%)',
	col_qual = 'Qualification',
	col_points = 'CP',
	col_team = 'Team',
	col_player = 'Player',
	show_button = 'Show More Results',
	hide_button = 'Show Fewer Results',
	credit_xe = 'Converted prizes calculated with values provided by http://www.xe.com on %s, as follows:',
	unknown_date = '[Date Unknown]',
	invalid_currency = "Invalid %s number. Make sure you're using American separators!"
}

local ROWSPANS = {
	place = true,
	prize = true,
	usd = true,
	eur = true,
	prizepct = true,
	qual = true,
	points = true
}

local CLASSES = {
	place = 'tournament-results-place',
	team = 'tournament-results-team',
	player = 'tournament-results-player'
}

local CURRENCY_ORDER = { 'usd', 'euro' }

local LINE_ARG_ORDER = { 'place', 'forcenewplace', 'sameplaces', 'date', 'prize', 'otherprize', 'prizepct', 'prizeunit', 'points', 'qual', 'quallink', 'qual2', 'qual2link', 'team', 'nocargo', 'date', 'rosterpage', 'groupstage', 'lastresult', 'lastopponent', 'lastopponentlink', 'lastopponentteam', 'lastoutcome', 'lastresultpoints', 'player', 'playerlink', 'hide' }

local TOGGLES = {
	class = 'TRL_toggle%s',
	show_text = i18n.show_button,
	hide_text = i18n.hide_button,
}

local sep = '%s*;;;%s*'

local h = {}

function h.getProcessedArgs(args)
	h.checkConversions({ args.usdrate, args.eurorate })
	local processedArgs = {
		prizeunit = args.prizeunit or 'USD',
		totalprize = util_math.formatNumber(args.totalprize),
		totalprizenum = args.totalprize and util_math.tonumber(args.totalprize),
		usdrate = tonumber(args.usdrate),
		eurorate = tonumber(args.eurorate),
		phase = args.phase,
		nocargo = util_args.castAsBool(args.nocargo),
		preload = args.preload or 'Team',
		showprize = util_args.castAsBool(args.prize),
		showusd = util_args.castAsBool(args.usdrate),
		showeuro = util_args.castAsBool(args.eurorate),
		showpoints = util_args.castAsBool(args.points),
		showqual = util_args.castAsBool(args.qual),
		showteam = util_args.castAsBool(args.showteam),
		showplayer = util_args.castAsBool(args.showplayer),
		combinequal = util_args.castAsBool(args.combinequal),
	}
	processedArgs.hasconversion = processedArgs.usdrate or processedArgs.eurorate
	return processedArgs
end

function h.checkConversions(tbl)
	for _, v in ipairs(tbl) do
		if v and not tonumber(v) then
			error(i18n.invalid_currency:format('conversion rate'))
		end
	end
end
			

function h.getCols(args, processedArgs)
	local cols = {
		'place',
		processedArgs.showprize and 'prize',
		h.pctCol(args),
		processedArgs.showusd and 'usd',
		processedArgs.showeuro and 'eur',
		processedArgs.showpoints and 'points',
		processedArgs.showqual and 'qual',
		(processedArgs.showteam or processedArgs.preload == 'Team') and 'team',
		(processedArgs.showplayer or processedArgs.preload == 'Player') and 'player',
		
	}
	util_table.removeFalseEntries(cols)
	local names = h.getNames(args)
	cols.displays = {}
	for i, v in ipairs(cols) do
		cols.displays[i] = names[v] or i18n['col_' .. v]
	end
	return cols
end

function h.pctCol(args)
	if util_args.castAsBool(args.prize) and not util_args.castAsBool(args.nomoney) then
		return 'prizepct'
	else
		return false
	end
end

function h.getNames(args)
	return {
		points = args.pointstitle,
		team = args.teamtitle
	}
end

function h.getLinesData(args, processedArgs)
	local rowData = {}
	for i, v in ipairs(args) do
		rowData[i] = h.processArgRow(v, processedArgs)
	end
	h.determineRowspans(rowData)
	return rowData
end

function h.processArgRow(str, processedArgs)
	local thisLine = util_args.splitArgs(str, LINE_ARG_ORDER)
	local lineDisplay = h.makeDisplayLineFromArgs(thisLine, processedArgs)
	return {
		display = lineDisplay,
		cargo = h.argsToCargoLine(thisLine, processedArgs, lineDisplay)
	}
end

function h.makeDisplayLineFromArgs(thisLine, processedArgs)
	local lineDisplay = {
		place = thisLine.place and util_esports.placementIcon(thisLine.place),
		placeraw = thisLine.place,
		team = m_team.rightmediumlinked(thisLine.team),
		player = h.getPlayerDisplay(thisLine, processedArgs),
		points = thisLine.points,
		qual = h.getQual(thisLine),
		forcenewplace = util_args.castAsBool(thisLine.forcenewplace),
		hide = util_args.castAsBool(thisLine.hide),
	}
	local prizes = h.getPrizeDisplay(thisLine, processedArgs)
	util_table.merge(lineDisplay, prizes)
	if processedArgs.combinequal then
		lineDisplay.points = lineDisplay.points or lineDisplay.qual or ''
	end
	return lineDisplay
end

function h.getPlayerDisplay(thisLine, processedArgs)
	local output = {
		thisLine.team and m_team.onlyimagelinkedshort(thisLine.team),
		util_text.intLink(thisLine.playerlink, thisLine.player)
	}
	return util_table.concat(output, ' ', nil, 2)
end

function h.getQual(thisLine)
	local quals = util_args.numberedArgsToTable(thisLine, 'qual') or {}
	thisLine.qual1link = thisLine.quallink
	for i, qual in ipairs(quals) do
		local link = thisLine['qual' .. i .. 'link']
		quals[i] = util_text.intLink(link, qual)
	end
	return util_table.concat(quals,'<br>')
end

function h.getPrizeDisplay(thisLine, processedArgs)
	if not (thisLine.prize or thisLine.prizepct) then
		return { prize = thisLine.otherprize }
	end
	local prizeNum = h.getPrizeNum(thisLine, processedArgs)
	if not prizeNum then
		return { prize = thisLine.otherprize, prizepct = thisLine.prizepct .. '%' }
	end
	local prizes = {
		prize = h.getPrize(prizeNum, thisLine, processedArgs),
		usd_number = h.getPrizeConverted(prizeNum, processedArgs.prizeunit, processedArgs.usdrate, 'USD'),
		eur_number = h.getPrizeConverted(prizeNum, processedArgs.prizeunit, processedArgs.eurorate, 'Euro'),
		prizepct = h.getPrizePct(prizeNum, thisLine, processedArgs),
	}
	prizes.usd = m_currency.short(prizes.usd_number, 'usd')
	prizes.eur = m_currency.short(prizes.eur_number, 'euro')
	return prizes
end

function h.getPrizeNum(thisLine, processedArgs)
	local prize = thisLine.prize
	if prize then
		if not util_math.tonumber(prize) then
			error(i18n.invalid_currency:format('prize'))
		end
		return util_math.tonumber(prize)
	end
	local prizepct = thisLine.prizepct
	local totalprize = processedArgs.totalprizenum
	if totalprize then
		return util_math.roundnum(prizepct / 100 * totalprize, .01)
	end
	return nil
end
	

function h.getPrize(prizeNum, thisLine, processedArgs)
	local fullPrize = {
		m_currency.short(prizeNum, processedArgs.prizeunit),
		thisLine.otherprize
	}
	return util_table.concat(fullPrize, ' +&nbsp;',nil,2)
end

function h.getPrizeConverted(prize, prizeunit, rate, unitToGet)
	if prizeunit == unitToGet then
		return prize
	elseif prize and rate then
		return util_math.roundnum(prize * tonumber(rate), .01)
	else
		return nil
	end
end

function h.getPrizePct(prizeNum, thisLine, processedArgs)
	if thisLine.prizepct then
		return thisLine.prizepct .. '%'
	elseif processedArgs.totalprizenum then
		return util_math.roundnum(prizeNum / processedArgs.totalprizenum * 100, .01) .. '%'
	else
		return nil
	end
end

function h.argsToCargoLine(thisLine, processedArgs, lineDisplay)
	if processedArgs.nocargo or thisLine.nocargo then return end
	local cargoData = {
		Event = util_vars.getVar('Event Name'),
		Tier = util_vars.getVar('Event Tier'),
		Date = thisLine.date or util_vars.getVar('Event Date'),
		Place = util_math.deserialize(thisLine.place) or thisLine.place,
		Prize = thisLine.prize,
		PrizeUnit = processedArgs.prizeunit,
		Prize_Markup = thisLine.prize and m_currency.short(thisLine.prize, processedArgs.prizeunit),
		Prize_USD = lineDisplay.usd_number,
		Prize_Euro = lineDisplay.eur_number,
		Prize_Other = thisLine.otherprize,
		Team = thisLine.team and m_team.teamlinkname(thisLine.team),
		UniqueLine = mw.title.getCurrentTitle().text .. '_' .. util_vars.setGlobalIndex('TRL_line'),
		Phase = processedArgs.phase,
	}
	
	local extraCargoData
	if processedArgs.preload == 'Player' then
		extraCargoData = h.getPlayerSpecificCargo(thisLine, processedArgs, lineDisplay)
	elseif processedArgs.preload == 'Team' then
		extraCargoData = h.getTeamSpecificCargo(thisLine, processedArgs, lineDisplay)
	end
	util_table.merge(cargoData, extraCargoData)
	-- return a table containing the table because maybe we want 2 dif cargo tables
	-- storing per line, e.g. TournamentResults & TournamentRosters
	return { cargoData }
end

function h.getPlayerSpecificCargo(thisLine, processedArgs, lineDisplay)
	local playerData = {
		_table = 'TournamentResults1v1',
		Player = thisLine.player,
		PlayerLink = thisLine.playerlink or thisLine.player,
	}
	local lastResult = h.playerLastResultCargo(thisLine)
	util_table.merge(playerData, lastResult)
	return playerData
end

function h.playerLastResultCargo(thisLine)
	local lastResult = {
		LastResult = thisLine.lastresult,
		LastOpponent = thisLine.lastopponent,
		LastOpponentLink = thisLine.lastopponentlink or thisLine.lastopponent,
		LastOutcome = thisLine.lastoutcome and util_esports.outcomes[lang:lc(thisLine.lastoutcome)],
		LastOpponentTeam = thisLine.lastopponentteam and m_team.teamlinkname(thisLine.lastopponentteam),
		OverviewPage = mw.title.getCurrentTitle().text,
	}
	return lastResult
end

function h.getTeamSpecificCargo(thisLine, processedArgs, lineDisplay)
	local teamData = {
		_table = 'TournamentResults',
		['Place-Number'] = util_math.deserialize(thisLine.place),
		RosterPage = thisLine.rosterpage or mw.title.getCurrentTitle().text,
		TeamLink = thisLine.team and m_team.teamlinkname(thisLine.team) or '',
	}
	teamData.PageAndTeam = teamData.RosterPage .. '_' .. teamData.TeamLink
	local lastResult = h.teamLastResultCargo(thisLine)
	util_table.merge(teamData, lastResult)
	return teamData
end

function h.teamLastResultCargo(thisLine)
	if thisLine.groupstage then
		return h.lastResultGroupstage(thisLine)
	elseif thisLine.lastresultpoints then
		return h.lastResultPoints(thisLine)
	else
		return h.lastResultDefault(thisLine)
	end
end

function h.lastResultGroupstage(thisLine)
	return {
		LastResult = thisLine.lastresult or thisLine.groupstage,
		GroupName = thisLine.group or 'Group Stage',
		LastOpponent_Markup = m_team.rightshortlinked('group stage')
	}
end

function h.lastResultPoints(thisLine)
	return {
		LastResult = thisLine.lastresultpoints,
		LastOpponent_Markup = m_team.rightshortlinked('points')
	}
end

function h.lastResultDefault(thisLine)
	local lastResult = {
		LastResult = thisLine.lastresult,
		LastOutcome = util_esports.getOutcomeName(thisLine.lastoutcome)
	}
	if thisLine.lastopponent then
		lastResult.LastTeam = m_team.teamlinkname(thisLine.lastopponent)
		lastResult.LastOpponent_Markup = m_team.rightshortlinked(thisLine.lastopponent)
	end
	return lastResult
end

function h.determineRowspans(rowData)
	local curPlace, curRow, count
	for _, row in ipairs(rowData) do
		local display = row.display
		if curPlace ~= display.placeraw or display.forcenewplace then
			if curRow then
				curRow.rowspan = count
			end
			curRow = display
			count = 1
			curPlace = display.placeraw
		else
			count = count + 1
		end
	end
	if count or 0 > 1 then
		curRow.rowspan = count
	end
end

-- cargo
function h.storeCargo(linesData)
	if h.doWeStoreCargo() then
		for _, line in ipairs(linesData) do
			local cargoData = line.cargo
			if cargoData then
				for _, tbl in ipairs(cargoData) do
					util_cargo.store(tbl)
				end
			end
		end
	end
end

function h.doWeStoreCargo()
	return mw.title.getCurrentTitle().nsText == ''
end

-- make output
function h.makeOutput(args, processedArgs, cols, linesData)
	h.initializeToggleData()
	local output = mw.html.create()
	output:wikitext(h.introSentence(args, processedArgs))
	h.printTable(output, cols, linesData)
	h.creditCurrencyRates(output, args, processedArgs)
	return output
end

function h.initializeToggleData()
	local i = util_vars.setGlobalIndex('TRL_i')
	TOGGLES.class = TOGGLES.class:format(i)
end

function h.introSentence(args, processedArgs)
	if not args.totalprize then return '' end
	local tempdate = util_args.nilToFalse(args.tempprizedate)
	local sentenceParts = {
		m_currency.long(processedArgs.totalprize, processedArgs.prizeunit),
		tempdate and i18n.temp_date:format(tempdate),
		i18n.intro,
	}
	return util_table.concat(sentenceParts, ' ')
end

function h.printTable(output, cols, linesData)
	local tbl = output:tag('table')
		:addClass('wikitable2')
		:addClass('tournament-results')
		:addClass('zebra-manual')
	h.printStartCols(tbl, cols)
	local hidden = h.printLines(tbl, cols, linesData)
	if hidden then
		h.endHiddenResults(tbl, #cols)
	end
end

function h.printStartCols(tbl, cols)
	local tr = tbl:tag('tr')
	for i, v in ipairs(cols) do
		tr:tag('th')
			:wikitext(cols.displays[i])
	end
end

function h.printLines(tbl, cols, linesData)
	local hidden = false
	local rowspanLeft = 0
	local odd = false
	for _, row in ipairs(linesData) do
		local lineDisplay = row.display
		if lineDisplay.hide then
			hidden = true
			h.printShowButton(tbl, #cols)
		end
		local tr = tbl:tag('tr')
		if hidden then
			util_toggle.sepCellClasses(tr, TOGGLES)
		end
		local isFullRow = h.printOneLine(tr, cols, lineDisplay, rowspanLeft, odd)
		if rowspanLeft == 1 then odd = not odd end
		if odd then
			tr:addClass('zebra-manual-odd')
		end
		if lineDisplay.rowspan then
			rowspanLeft = lineDisplay.rowspan
		else
			rowspanLeft = rowspanLeft - 1
		end
	end
	return hidden
end

function h.printShowButton(tbl, colspan)
	local tr = tbl:tag('tr')
	local th = tr:tag('th')
		:attr('colspan', colspan)
	util_toggle.printSepToggler(th, TOGGLES)
	util_toggle.sepCellClasses(tr, TOGGLES, true)
end

function h.printOneLine(tr, cols, lineDisplay, rowspanLeft, odd)
	local isFullRow = false
	for _, col in ipairs(cols) do
		if rowspanLeft > 1 and ROWSPANS[col] then
			-- pass
		else
			local td = tr:tag('td')
				:wikitext(lineDisplay[col])
				:addClass(CLASSES[col])
			if ROWSPANS[col] then
				td:attr('rowspan', lineDisplay.rowspan)
			end
		end
	end
end

function h.endHiddenResults(tbl, colspan)
	local tr = tbl:tag('tr')
	local th = tr:tag('th')
		:attr('colspan', colspan)
	util_toggle.sepCellClasses(tr, TOGGLES, false)
	util_toggle.printSepToggler(th, TOGGLES, true)
end

function h.creditCurrencyRates(output, args, processedArgs)
	if not (args.conversionsource and processedArgs.hasconversion) then
		return nil
	end
	local source = lang:lc(args.conversionsource)
	local date = args.conversiondate
	local rates = {
		usd = processedArgs.usdrate,
		euro = processedArgs.eurorate,
	}
	local originalUnit = processedArgs.prizeunit
	output:wikitext(i18n['credit_' .. source]:format(date or i18n.unknown_date))
	local ul = output:tag('ul')
	for _, v in ipairs(CURRENCY_ORDER) do
		if rates[v] then
			ul:tag('li')
				:wikitext(m_currency.long(1, originalUnit))
				:wikitext(' = ')
				:wikitext(m_currency.long(rates[v], v))
		end
	end
	return output
end

local p = {}
function p.main(frame)
	local args = util_args.merge(true)
	local processedArgs = h.getProcessedArgs(args)
	local cols = h.getCols(args, processedArgs)
	local linesData = h.getLinesData(args, processedArgs)
	h.storeCargo(linesData)
	return h.makeOutput(args, processedArgs, cols, linesData)
end
return p