Module:PlayerCurrentTeam

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_map = require("Module:MapUtil") local util_news = require("Module:NewsUtil") local util_sort = require("Module:SortUtil") local util_source = require("Module:SourceUtil") local util_table = require("Module:TableUtil") local util_text = require("Module:TextUtil") local util_title = require("Module:TitleUtil") local util_vars = require("Module:VarsUtil") local i18n = require('Module:i18nUtil')

local LCS = require('Module:LuaClassSystem')

local OD = require('Module:OrderedDict')

local PCT = LCS.class local QB = LCS.class

local h = {}

local p = {}

-- for testing to be called from MW function p.test(frame) local args = util_args.merge local result = p.main(args[1]) local output = mw.html.create('table') :addClass('wikitable') for _, row in ipairs(result) do		output:tag('tr') :tag('td'):wikitext(row.team) :tag('td'):wikitext(tostring(row.role)) :tag('td'):wikitext(row.role:images) end return output end

-- intended to be called by Infobox/Player -- so this does not apply any processing to the output -- and instead just returns a data table function p.main(player) return PCT:init(player) end

function PCT:init(subject) self.CONTRACT_DATES = {} self.PREVIOUS_RESIDENCIES = {} self.last_team_change_index = nil local listOfChanges = self:queryForChanges(subject) self:processChangesRows(listOfChanges) if #listOfChanges == 0 then return self:defaultOutput end local netStatuses = self:computeNetStatuses(listOfChanges) local listOfSubjects = self:getFinalListOfSubjects(netStatuses) return self:makeOutput(listOfSubjects, listOfChanges) end

function PCT:defaultOutput return { last = {}, contractDates = {} } end

function PCT:queryForChanges(subject) return util_cargo.queryAndCast(self:getQuery(subject)) end

-- start cargo shit local QBRosters = QB:extends local QBContracts = QB:extends local QBResidency = QB:extends

function PCT:getQuery(subject) local rosBuilder = QBRosters local contractsBuilder = QBContracts local resBuilder = QBResidency local query = { union = true, {			tables = rosBuilder:getTables, join = rosBuilder:getJoin, where = rosBuilder:getWhere(subject), fields = rosBuilder:getFields, complexTypes = { Role = { type = 'RoleList', args = { 'Roles', modifier = 'RoleModifier', }				}			},		},		{			tables = contractsBuilder:getTables, join = contractsBuilder:getJoin, where = contractsBuilder:getWhere(subject), fields = contractsBuilder:getFields, },		{			tables = resBuilder:getTables, join = resBuilder:getJoin, where = resBuilder:getWhere(subject), fields = resBuilder:getFields, },		sortKey = { 'Date_Sort', 'N_LineInDate', 'N_LineInNews' }, sortOrder = { true, true, true }, }	return query end

function QB:getWhere(player) local where = { ('PR.OverviewPage="%s"'):format(player), }	return util_cargo.concatWhere(where) end

function QB:getFields local ret = { 'News.Date_Display', 'News.Region', 'News._pageName', 'News.Date_Sort', 'News.N_LineInDate', 'PR.OverviewPage=PlayerLink', }	return ret end

function QBRosters:getTables local ret = { 'NewsItems=News', 'RosterChanges=RC', 'PlayerRedirects=PR', 'TeamRedirects=TRed', 'SisterTeams=ST', }	return ret end

function QBRosters:getJoin local ret = { 'News.NewsId=RC.NewsId', 'RC.Player=PR.AllName', -- roster changes need to discover the org so we can pull contracts 'RC.Team=TRed.AllName', 'TRed._pageName=ST.Team', }	return ret end

function QBRosters:getFields local fields = self:super('getFields') local tbl = { 'RC.Player', 'RC.Team', 'RC.Roles', 'RC.RoleModifier', 'RC.Direction', 'RC.CurrentTeamPriority=Priority', 'RC.Preload', 'RC.Direction', 'RC.N_LineInNews', 'COALESCE(ST._pageName, RC.Team)=SisterTeamPage', }	util_table.mergeArrays(fields, tbl) return fields end

function QBContracts:getTables local ret = { 'NewsItems=News', 'Contracts', 'PlayerRedirects=PR', 'TeamRedirects=TRed', 'SisterTeams=ST', }	return ret end

function QBContracts:getJoin local ret = { 'News.NewsId=Contracts.NewsId', 'Contracts.Player=PR.AllName', -- contracts need to respect contracts from the same org 'Contracts.Team=TRed.AllName', 'TRed._pageName=ST.Team', }	return ret end

function QBContracts:getFields local fields = self:super('getFields') local tbl = { 'COALESCE(ST._pageName, Contracts.Team)=SisterTeamPage', 'Contracts.IsRemoval=IsContractRemoval [boolean]', 'Contracts.ContractEnd', }	util_table.mergeArrays(fields, tbl) return fields end

function QBResidency:getTables local ret = { 'NewsItems=News', 'ResidencyChanges=ResC', 'PlayerRedirects=PR', }	return ret end

function QBResidency:getJoin local ret = { -- residency changes are just the same news id that's it		'News.NewsId=ResC.NewsId', 'ResC.Player=PR.AllName', }	return ret end

function QBResidency:getFields local fields = self:super('getFields') local tbl = { 'ResC.ResidencyOld', }	util_table.mergeArrays(fields, tbl) return fields end

-- end cargo shit

function PCT:processChangesRows(listOfChanges) util_map.selfRowsInPlace(self, listOfChanges, self.processOneChangeRow) end

function PCT:processOneChangeRow(row) row.Subject = row.Team row.team = row.Team row.role = row.Role if h.isContractRemoval(row) then self.CONTRACT_DATES[row.SisterTeamPage] = nil end if row.ContractEnd then self.CONTRACT_DATES[row.SisterTeamPage] = row.ContractEnd end if h.isRosterChange(row) then self.last_team_change_index = row.index util_vars.log(self.last_team_change_index) end -- this is plaintext so that we can cast it easily as a list when we're done self.PREVIOUS_RESIDENCIES[#self.PREVIOUS_RESIDENCIES+1] = row.ResidencyOld end

function h.isContractRemoval(row) -- In contrast to "Module:PlayerTeamHistoryAbstract" we look at the preload to decide whether -- or not we have to remove contracts. PTHA instead does this weird reverse-lookup thingy -- working backwards through history in two phases. PTHA's approach is significantly more complex -- but maybe not unreasonable because it's doing a ton of other things at the same time. But -- this approach is hopefully sufficient for this smaller, less-complex use case here. -- that comment is so hilariously incorrect that I'm going to leave it there just to laugh at it -- forever. PTHA had a bug for *years* where it needed to run this code but wasn't. It now also -- runs an identical copy of this code (sans this comment). if row.IsContractRemoval then return true end if row.Direction == 'Join' then return false end if not row.Preload then return false end return not util_news.CONTRACT_MAINTAINED_ON_LEAVE[row.Preload] end

function h.isRosterChange(row) return row.Direction end

-- get dictionary keyed by subject function PCT:computeNetStatuses(listOfChanges) local currentStatuses = {} for _, row in ipairs(listOfChanges) do		self:updateEntryForThis(currentStatuses, row) end return currentStatuses end

function PCT:updateEntryForThis(currentStatuses, row) if currentStatuses[row.Subject] then row.Priority = row.Priority or currentStatuses[row.Subject].Priority end if row.Subject then currentStatuses[row.Subject] = row end end

-- get ordered list of subjects function PCT:getFinalListOfSubjects(netStatuses) local subjects = {} for _, status in pairs(netStatuses) do		self:addSubjectToOutputIfNeeded(subjects, status) end util_sort.tablesByKeys(subjects, 'Priority', true) return subjects end

function PCT:addSubjectToOutputIfNeeded(subjects, status) if not self:doWeAddSubjectToOutput(status) then return end subjects[#subjects+1] = status end

function PCT:doWeAddSubjectToOutput(status) return status.Direction == 'Join' end

-- make output function PCT:makeOutput(listOfSubjects, listOfChanges) listOfSubjects.last = self:getLastTeamList(listOfChanges) listOfSubjects.contractDates = self.CONTRACT_DATES listOfSubjects.resPrevList = self.PREVIOUS_RESIDENCIES return listOfSubjects end

function PCT:getLastTeamList(listOfChanges) if self.last_team_change_index == nil then return {} end return h.getLastTeamInfo(listOfChanges[self.last_team_change_index]) end

function h.getLastTeamInfo(row) local ret = { team = row.Team, role = row.Role, }	return ret end

return p