Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
Revision as of 02:13, 3 March 2026 by Esportsamaze (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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

local p = {}
local html = mw.html
local cargo = mw.ext.cargo

local function sqlEscape(s)
    if not s then return "" end
    s = s:gsub("\\", "\\\\")
    s = s:gsub("'", "\\'")
    return s
end

-- HELPER: Smart Tournament Name Detection
local function getTournamentName(args)
    if args.tournament and args.tournament ~= "" then return args.tournament end
    local pageTitle = mw.title.getCurrentTitle().text
    local parts = mw.text.split(pageTitle, '/')
    if parts[2] == "Tournaments" and parts[3] then return parts[3] end
    return mw.title.getCurrentTitle().baseText
end

-- INTERNAL: Builds the HTML for a single card
local function buildCard(data, seedOverride)
    local root = html.create('div'):addClass('roster-card')

    -- HEADER
    local header = root:tag('div'):addClass('roster-header')
    local headerContent = header:tag('div'):addClass('header-content')

    -- LOGO LOGIC
    -- Priority: 1. Tournament Entry Custom Logo -> 2. Master DB Custom Logo -> 3. Master DB Default Name -> 4. Shield
    local lightLogo = "Shield_team.png"
    local darkLogo = "Shield_team_dark.png"

    -- Check Entry (Tournament specific) Override first
    if data.entryImg and data.entryImg ~= "" then
        lightLogo = data.entryImg
        darkLogo = (data.entryImgDark and data.entryImgDark ~= "") and data.entryImgDark or lightLogo
    -- Check Master DB
    elseif data.masterImg and data.masterImg ~= "" then
        lightLogo = data.masterImg
        darkLogo = (data.masterImgDark and data.masterImgDark ~= "") and data.masterImgDark or lightLogo
    end

    local logoDiv = headerContent:tag('div'):addClass('roster-logo')
    logoDiv:tag('div'):addClass('logo-lightmode'):wikitext('[[File:' .. lightLogo .. '|link=]]')
    logoDiv:tag('div'):addClass('logo-darkmode'):wikitext('[[File:' .. darkLogo .. '|link=]]')

    -- NAME LOGIC
    local displayName = data.displayName
    if not displayName or displayName == "" then displayName = data.team end
    headerContent:tag('div'):addClass('roster-name'):wikitext('[[' .. data.team .. '|' .. displayName .. ']]')

    -- SEEDING
    local finalSeed = seedOverride
    if not finalSeed or finalSeed == "" then finalSeed = data.seeding end
    if finalSeed and finalSeed ~= "" then
        root:tag('div'):addClass('roster-subheader'):wikitext(finalSeed)
    end

    -- PLAYERS
    local contentRows = root:tag('div'):addClass('roster-content-rows')
    local players = {data.p1, data.p2, data.p3, data.p4, data.p5, data.p6}
    local playerCount = 0
    for _, pl in ipairs(players) do if pl and pl ~= "" then playerCount = playerCount + 1 end end

    local playerInner = contentRows:tag('div'):addClass('roster-players-inner'):addClass('count-' .. playerCount)
    for _, pl in ipairs(players) do
        if pl and pl ~= "" then
            playerInner:tag('div'):addClass('roster-row player'):wikitext('[[' .. pl .. ']]')
        end
    end

    -- STAFF
    if (data.coach and data.coach ~= "") or (data.analyst and data.analyst ~= "") then
        local staffInner = contentRows:tag('div'):addClass('roster-staff-inner')
        if data.coach and data.coach ~= "" then staffInner:tag('div'):addClass('roster-row staff'):wikitext('C: [[' .. data.coach .. ']]') end
        if data.analyst and data.analyst ~= "" then staffInner:tag('div'):addClass('roster-row staff'):wikitext('A: [[' .. data.analyst .. ']]') end
    end

    return tostring(root)
end

-- PUBLIC 1: ENTRY MODULE
function p.entry(frame)
    local args = frame:getParent().args
    local count = tonumber(args.count) or 20
    local tournamentName = getTournamentName(args)

    for i = 1, count do
        local prefix = 't' .. i
        local team = args[prefix]
        if team and team ~= "" then
            if cargo and cargo.store then
                cargo.store("Tournament_Teams", {
                    tournament = tournamentName,
                    team = team,
                    display_name = args[prefix .. 'name'],
                    image = args[prefix .. 'img'],
                    image_dark = args[prefix .. 'imgdark'],
                    seeding = args[prefix .. 'seed'],
                    p1 = args[prefix .. 'p1'],
                    p2 = args[prefix .. 'p2'],
                    p3 = args[prefix .. 'p3'],
                    p4 = args[prefix .. 'p4'],
                    p5 = args[prefix .. 'p5'],
                    p6 = args[prefix .. 'p6'],
                    coach = args[prefix .. 'c'],
                    analyst = args[prefix .. 'a']
                })
            end
        end
    end
    return "<div style='display:none;'>Roster Data Saved Successfully.</div>"
end

-- PUBLIC 2: DISPLAY MODULE
function p.display(frame)
    local args = frame:getParent().args
    local tournamentName = getTournamentName(args)
    local count = tonumber(args.count) or 24

    -- 1. Gather Requested Teams
    local requestedTeams = {}
    local orderedRequests = {}

    for i = 1, count do
        local team = args['t' .. i]
        if team and team ~= "" then
            local cleanTeam = sqlEscape(team)
            table.insert(requestedTeams, "'" .. cleanTeam .. "'")
            table.insert(orderedRequests, { name = team, seed = args['t' .. i .. 'seed'] })
        end
    end

    if #requestedTeams == 0 then return "" end
    local teamListSql = table.concat(requestedTeams, ", ")

    -- 2. MEMORY MAP A: Fetch Rosters (Tournament Specific)
    local rosterDb = {}
    if cargo and cargo.query then
        local rResults = cargo.query(
            "Tournament_Teams",
            "team, display_name, image, image_dark, seeding, p1, p2, p3, p4, p5, p6, coach, analyst",
            { where = "tournament='" .. sqlEscape(tournamentName) .. "' AND team IN (" .. teamListSql .. ")", limit = count }
        )
        for _, row in ipairs(rResults) do
            rosterDb[row.team] = row
        end
    end

    -- 3. MEMORY MAP B: Fetch Master Logos (Global Teams Table)
    -- FIXED: We now query 'name' instead of '_pageName' to avoid underscore mismatches
    local masterDb = {}
    if cargo and cargo.query then
        local mResults = cargo.query(
            "Teams",
            "name, image, image_dark", 
            { where = "name IN (" .. teamListSql .. ")", limit = count }
        )
        for _, row in ipairs(mResults) do
            masterDb[row.name] = row
        end
    end

    -- 4. BUILD HTML
    local container = html.create('div')
        :addClass('participant-group-container')
        :css('display', 'flex')
        :css('flex-wrap', 'wrap')
        :css('gap', '15px')
        :css('justify-content', 'center')

    for _, req in ipairs(orderedRequests) do
        local teamName = req.name
        local rosterData = rosterDb[teamName] or { team = teamName }

        -- Merge Master Logos
        if masterDb[teamName] then
            -- 1. If DB has specific image set, use it
            if masterDb[teamName].image and masterDb[teamName].image ~= "" then
                rosterData.masterImg = masterDb[teamName].image
            else
                -- 2. If DB exists but field is blank, assume TeamName.png (Instead of Shield)
                rosterData.masterImg = teamName .. ".png"
            end
            
            -- Dark Mode Logic
            if masterDb[teamName].image_dark and masterDb[teamName].image_dark ~= "" then
                rosterData.masterImgDark = masterDb[teamName].image_dark
            else
                rosterData.masterImgDark = rosterData.masterImg -- Fallback to light
            end
        end

        rosterData.entryImg = rosterData.image
        rosterData.entryImgDark = rosterData.image_dark
        rosterData.displayName = rosterData.display_name

        container:wikitext(buildCard(rosterData, req.seed))
    end

    return tostring(container)
end

return p