Module:RosterChangePortal

local util_args = require('Module:ArgsUtil') local util_cargo = require("Module:CargoUtil") local util_esports = require("Module:EsportsUtil") local util_form = require("Module:FormUtil") local util_html = require("Module:HtmlUtil") local util_map = require("Module:MapUtil") local util_news = require("Module:NewsUtil") 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_toggle = require("Module:ToggleUtil") local util_vars = require("Module:VarsUtil") local i18n = require('Module:i18nUtil')

local m_team = require('Module:Team') local RegionList = require('Module:RegionList')

local GroupedRosterChangesAbstract = require('Module:GroupedRosterChangesAbstract') local RosterChangePortal = GroupedRosterChangesAbstract:extends

local lang = mw.getLanguage('en')

local PARTS = { 'Leave', 'Join' }

local PART_COLUMNS = { 'RegionDisplay', 'Date', 'Team', 'Role', 'Ref' }

local FORM_INFO = { form = 'RosterChangeQuery', template = 'RCQ' }

local DEBUG = false

local PRELOADS_TO_IGNORE = { 'opportunities', 'set_to_leave', 'remain', 'extended', 'gcd_remain', 'gcd_extended', 'loan_end_and_join', 'gcd_remove_notleave', join = { 'set_to_leave_already_joined', 'to_academy_also_stay', 'to_main_also_stay' }, leave = {}, }

local h = {}

local p = {}

function p.main(frame) local args = util_args.merge i18n.init('RosterChangePortal') local formArgs = h.getFormArgs(args) h.castArgs(args) h.setConstants(args) args.listOfPlayersToQuery = h.makeAndRunListOfPlayersQuery(args) if #args.listOfPlayersToQuery == 0 then return (":%s"):format(i18n.print('noChanges')) end return h.makeIntro(args, formArgs), RosterChangePortal:run(args), h.makeOutro(args, formArgs) end

function h.getFormArgs(args) local formArgs = mw.clone(args) formArgs.showformlink = nil return formArgs end

function h.castArgs(args) args.region = RegionList(args.region) args.teams = args.teams and util_map.split(args.teams, nil, m_team.teamlinkname) args.debug = util_args.castAsBool(args.debug) end

function h.setConstants(args) DEBUG = args.debug end

function h.makeAndRunListOfPlayersQuery(args) return util_cargo.getOrderedList(h.getListOfPlayersQuery(args), 'player') end

function h.getListOfPlayersQuery(args) local ret = { tables = h.getListOfPlayersTables, join = h.getListOfPlayersJoin, where = h.getListOfPlayersWhere(args), fields = 'PR._pageName=player', groupBy = 'PR._pageName', }	return ret end

function h.getListOfPlayersTables local ret = { 'RosterChanges=RC', 'NewsItems=News', 'PlayerRedirects=PR', 'RosterChangePortalDates=Dates', }	return ret end

function h.getListOfPlayersJoin local ret = { 'RC.NewsId=News.NewsId', 'RC.Player=PR.AllName', 'News.Region=Dates.Region' }	return ret end

function h.getListOfPlayersWhere(args) local argWhere = { util_cargo.whereFromCompoundEntity('News.Region="%s"', args.region), h.getTeamsWhereCondition(args.teams), 'News.ExcludePortal IS NULL OR News.ExcludePortal != "1"', }	util_table.mergeArrays(argWhere, h.getDateWhereCondition(args)) local where = util_cargo.concatWhere(argWhere) util_vars.setVar('where', where) return where end

function h.getDateWhereCondition(args) return util_news.getRosterPortalDatesWhereCondition(args.period, 'RC.Date_Sort') end

function h.getTeamsWhereCondition(teams) if not teams then return false end return util_map.formatAndConcat(teams, ' OR ', 'RC.Team="%s"') end

function RosterChangePortal:getTables local ret = { 'RosterChanges=RC', 'NewsItems=News', 'PlayerRedirects=PR', 'RosterChangePortalDates=Dates', 'Retirements=R', }	return ret end

function RosterChangePortal:getJoin local ret = { 'News.NewsId=RC.NewsId', 'News.Region=Dates.Region', 'News.NewsId=R.NewsId', 'RC.Player=PR.AllName', }	return ret end

function RosterChangePortal:getFields -- super local fields = GroupedRosterChangesAbstract:getFields local extraFields = { 'R.Player=R_Player', 'R.Unretires', 'R._pageName=R_pageName', }	return util_table.mergeArrays(fields, extraFields) end

function RosterChangePortal:getWhere(args) local tbl = { 'RC._pageName IS NOT NULL OR R._pageName IS NOT NULL', h.getMainWhereConditionFromListOfPlayers(args.listOfPlayersToQuery), 'News.ExcludePortal IS NULL OR News.ExcludePortal != "1"', util_news.getExcludedPreloadsWhereCondition(PRELOADS_TO_IGNORE), util_cargo.fakeHolds('RC.Tags', args.tag), }	util_table.mergeArrays(		tbl,		h.getDateWhereCondition(args)	) return util_cargo.concatWhere(tbl) end

function h.getMainWhereConditionFromListOfPlayers(listOfPlayers) return util_table.concat(listOfPlayers, ' OR ', h.playerToWhere) end

function h.playerToWhere(player) return ('PR._pageName="%s"'):format(player) end

function RosterChangePortal:getGroupBy return 'News.NewsId, RC.Team, RC.Direction, RC.Player' end

function RosterChangePortal:getKey(row) return row.PlayerLink end

- -- make changesByLine -

function RosterChangePortal:formatOneRawDataRow(row) row.PlayerLink = row.PlayerLink or row.Player or row.R_Player self:super('formatOneRawDataRow', row) end

function RosterChangePortal:isOriginalNews(changesByLine, row, index) -- check to see if this piece of news has already been reported (e.g. gcd then confirmation) -- if it has then we want to return out of updating based on this row completely --if not row.PlayerLink then return false end if not index then return true end if row.Preload and row.Preload:find('loan') then return h.getLoanNewsStatus(row) end for _, info in ipairs(index) do		if self:teamsAreIdentical(row, self:getOldRowFromIndex(changesByLine, row, info), 'Leave') then return false elseif self:teamsAreIdentical(row, self:getOldRowFromIndex(changesByLine, row, info), 'Join') then return false end end return true end

function RosterChangePortal:doWeNeedANewLine(changesByLine, row, index) return changesByLine[self:getMostRecentLineNumberFromIndex(index)].TeamJoin end

function h.getLoanNewsStatus(row) if row.Preload:find('loaned_from') and row.TeamLeave then return false end if row.Preload:find('loan_return') and row.TeamLeave then return false end if row.Preload:find('loaned_to') and row.TeamJoin then return false end if row.Preload:find('loan_end') and row.TeamJoin then return false end return true end

function RosterChangePortal:teamsAreIdentical(row, oldrow, when) if not row['Team' .. when] then return false end for _, key in ipairs({ 'Team', 'RoleModifier' }) do		if not h.keyIsIdentical(row, oldrow, key, when) then return false end end return true end

function h.keyIsIdentical(row, oldrow, key, when) return row[key .. when] == oldrow[key .. when] end

function RosterChangePortal:getMostRecentLineNumberFromIndex(index) return index[#index].changeNumber end

function RosterChangePortal:updateIndexExisting(changesByLine, row, index) self:updateIndex(changesByLine, row, index) end

function RosterChangePortal:updateIndex(changesByLine, row, index) index[#index+1] = { changeNumber = #changesByLine } end

function RosterChangePortal:moveExistingLine(changesByLine, oldIndex) changesByLine[#changesByLine+1] = changesByLine[oldIndex] self.CHANGES_TO_REMOVE[#self.CHANGES_TO_REMOVE+1] = oldIndex end

function RosterChangePortal:formatRowForOutput(row) row.PlayerLinked = util_esports.playerLinked(row.Player) row.TeamLeave = h.getTeamDisplay(row, 'Leave') row.TeamJoin = h.getTeamDisplay(row, 'Join') row.RefLeave = util_news.getSentenceAndRefDisplay(row, 'Leave') row.RefJoin = util_news.getSentenceAndRefDisplay(row, 'Join') row.RegionDisplayLeave = h.getRegionDisplay(row, 'Leave') row.RegionDisplayJoin = h.getRegionDisplay(row, 'Join') end

function h.getTeamDisplay(row, when) if DEBUG then return row['Team' .. when] end if not row['Team' .. when] then return end return m_team.onlyimagelinked(row['Team' .. when]) end

function h.getRegionDisplay(row, when) if not row['Region' .. when] then return nil end if DEBUG then return row['Region' .. when]:name end return row['Region' .. when]:image end

-- filter

function RosterChangePortal:isLineWanted(row, args) if h.isIncompleteAcademyMainTransitionLine(row) then return false end if not args.region:exists then return true end if row.RegionLeave and args.region:has(nil, row.RegionLeave:get) then return true end if row.RegionJoin and args.region:has(nil, row.RegionJoin:get) then return true end return false end

function h.isIncompleteAcademyMainTransitionLine(row) if not h.isAcademyMainTransitionLine(row) then return false end return not row.TeamJoin or not row.TeamLeave end

function h.isAcademyMainTransitionLine(row) local academy_main_transfers = { 'to_academy', 'to_main', 'from_academy', 'from_main' } return util_table.keyOf(academy_main_transfers, row.PreloadJoin) or util_table.keyOf(academy_main_transfers, row.PreloadLeave) end

-- output function h.makeIntro(args, formArgs) return util_form.makeIntroSentence(FORM_INFO, args, formArgs) end

function RosterChangePortal:makeOutput(changesByLine) util_table.reverseInPlace(changesByLine) local output = mw.html.create local tbl = output:tag('table') :addClass('wikitable') :addClass('hoverable-rows') h.printHeading(tbl) h.printTable(tbl, changesByLine) return output end

function h.printHeading(tbl) local tr = tbl:tag('tr') tr:tag('th') :attr('rowspan', 2) :wikitext(i18n.print('Player')) h.printPartHeadings(tr) h.printPartSubheadings(tbl) end

function h.printPartHeadings(tr) for _, v in ipairs(PARTS) do		tr:tag('th') :attr('colspan', #PART_COLUMNS) :wikitext(i18n.print(v)) end end

function h.printPartSubheadings(tbl) local tr = tbl:tag('tr') for _, _ in ipairs(PARTS) do		h.printOnePartHeading(tr) end end

function h.printOnePartHeading(tr) for _, v in ipairs(PART_COLUMNS) do		tr:tag('th') :wikitext(i18n.print(v)) end end

function h.printTable(tbl, changesByLine) for _, row in ipairs(changesByLine) do		h.printRow(tbl, row) end end

function h.printRow(tbl, row) local tr = tbl:tag('tr') :addClass('roster-portal-row') h.printPlayer(tr, row) h.printRowParts(tr, row) h.printEditButtons(util_html.lastChild(tr), row) end

function h.printPlayer(tr, row) local td = tr:tag('td'):wikitext(row.PlayerLinked) end

function h.printRowParts(tr, row) for _, part in ipairs(PARTS) do		h.printOneRowPart(tr, row, part) end end

function h.printOneRowPart(tr, row, part) if not row['Team' .. part] then h.pickAndPrintNoTeamCell(tr, row) return end for _, v in ipairs(PART_COLUMNS) do		tr:tag('td') :wikitext(row[v .. part]) end end

function h.pickAndPrintNoTeamCell(tr, row) if row.R_Player then h.printNoTeamCell(tr, 'retired') return end h.printNoTeamCell(tr, 'free agent') end

function h.printNoTeamCell(tr, text) tr:tag('td') :attr('colspan', #PART_COLUMNS) :addClass('roster-portal-fa') :wikitext(m_team.rightmedium(text)) end

function h.printEditButtons(td, row) td:addClass('roster-portal-lastcell') local div = td:tag('div') :addClass('roster-portal-edit') h.printOneEditButton(div, row._pageNameLeave, 'el') h.printOneEditButton(div, row._pageNameJoin, 'ej') end

function h.printOneEditButton(div, link, text) if not link then return end div:tag('span') :addClass('roster-portal-edit-' .. text) :addClass('logged-in-link') :wikitext(text) :attr('data-href', link) end

function h.makeOutro(args, formArgs) if util_args.castAsBool(args.showformlink) then return '' end local output = mw.html.create h.printPermalink(output, args, formArgs) h.printWhere(output) return output end

function h.printPermalink(output, args, formArgs) output:wikitext(		i18n.print('permalink', util_form.fullURL(FORM_INFO, formArgs))	) end

function h.printWhere(output) output:tag('br') output:wikitext(i18n.print('where', util_vars.getVar('where'))) end

return p