Jump to content
Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

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

local p = {}

local esw = require('Module:ESWords')

local words = esw.words()

local function contains(tbl, val)
    for _, v in ipairs(tbl) do
        if v == val then return true end
    end
    return false
end

local function fixInputs(elements, parts, ops)
    if elements == "all" then
        elements = {}
        for elementName, _ in pairs(words) do
            table.insert(elements, elementName)
        end
    end

    if parts == "all" then
        parts = {}
        local firstElement = next(words)
        if firstElement then
            for partName, _ in pairs(words[firstElement]) do
                table.insert(parts, partName)
            end
        end
    end

    if ops == "all" then
        ops = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    end

    -- Normalize inputs to tables if they are not already
    if type(elements) ~= "table" then
        elements = { elements }
    end
    if type(parts) ~= "table" then
        parts = { parts }
    end
    if type(ops) ~= "table" then
        ops = { ops }
    end
    return elements, parts, ops
end

local function filterWords(elements, parts, ops)
    local outWords = {}
    for elementName, elementData in pairs(words) do
        if contains(elements, elementName) then
            outWords[elementName] = {}
            for _, part in ipairs(parts) do
                if elementData[part] then
                    outWords[elementName][part] = {}
                    for _, op in ipairs(ops) do
                        if elementData[part][op] then
                            outWords[elementName][part][op] = elementData[part][op]
                        end
                    end
                end
            end
        end
    end
    return outWords
end

local bgs = {
    even = {
        op = '#e5a50a1A',
        celestial = '#6135831A',
        flame = '#a51d2d1A',
        storm = '#1a5fb41A',
        life = '#9a99961A',
        necro = '#0000001A',
        nature = '#26a2691A',
    },
    odd = {
        op = '#f9f06b1A',
        celestial = '#dc8add1A',
        flame = '#f661511A',
        storm = '#99c1f11A',
        life = '#ffffff1A',
        necro = '#77767b1A',
        nature = '#8ff0a41A',
    }
}

local function bgHex(rowNum, col)
    -- Determine the background color based on the row number and column type
    local bgColor
    if rowNum % 2 == 0 then
        -- Even row
        bgColor = bgs.even[col]
    else
        -- Odd row
        bgColor = bgs.odd[col]
    end
    return bgColor or '#ffffff1A' -- Fallback to white if no color is defined
end

local function bgStr(rowNum, col)
    -- Generate the background style string for a given row and column
    local bgColor = bgHex(rowNum, col)
    return ' style="background-color: ' .. bgColor .. '" | '
end

function p.getWords(frame, elements, parts, ops)
    elements, parts, ops = fixInputs(elements, parts, ops)
    return filterWords(elements, parts, ops)
end

function p.getTable(frame, elements, parts, ops)
    elements, parts, ops = fixInputs(elements, parts, ops)
    local outWords = filterWords(elements, parts, ops)
    
    local tableTitle = '{{L|Core|Elder Sorcery Words|u=1}}'
    if #elements == 1 then
        -- If there's only one element, part, and op, use a more specific title
        local elementName = elements[1]:gsub("_", " "):gsub("^%l", string.upper)
        if elementName == "Necro" then
            elementName = "Necromancy"
        end
        tableTitle = elementName .. ' ' .. tableTitle
    end
    if #ops == 1 then
        -- If there's only one OP level, use it in the title
        tableTitle = 'OP ' .. tostring(ops[1]) .. ' ' .. tableTitle
    end

    out = '{| class="wikitable sortable"\n|+ style=white-space:nowrap | ' .. frame:preprocess(tableTitle) .. '\n'
    -- Header row
    local rowNum = 0
    out = out .. '!' .. bgStr(rowNum, 'op') .. 'OP'
    local actualColumns = {}
    table.sort(elements, function(a, b) return a < b end)
    for _, elementName in pairs(elements) do
        table.sort(parts, function(a, b) return a < b end)
        for _, part in pairs(parts) do
            if outWords[elementName] and outWords[elementName][part] and (#outWords[elementName][part] > 0) then
                local elementTitle = elementName:gsub("_", " "):gsub("^%l", string.upper)
                local titleLink = elementName .. " Mage"
                if elementTitle == "Necro" then
                    elementTitle = "Necromancy"
                    titleLink = "Necromancer"
                end
                local partTitle = part:gsub("_", " "):gsub("^%l", string.upper)
                local titleText = elementTitle .. ' ' .. partTitle
                local title = '{{L|Class|' .. titleLink .. '|' .. titleText .. '}}'
                if elementName == "celestial" then
                    title = titleText
                end
                out = out .. ' !!' .. bgStr(rowNum, elementName) .. frame:preprocess(title)
                table.insert(actualColumns, {
                    element = elementName,
                    part = part
                })
            end
        end
    end
    rowNum = rowNum + 1
    local opRowNum = 1

    local wordCollections = {}
    -- Collect all words for each OP level
    for opLevel = 1, 10 do
        wordCollections[opLevel] = {}
        local numRows = 0
        for _, column in ipairs(actualColumns) do
            local columnElement = column.element
            local columnPart = column.part
            local columnNumRows = 0
            local columnWords = {}
            if outWords[columnElement] and outWords[columnElement][columnPart] and outWords[columnElement][columnPart][opLevel] then
                columnWords = outWords[columnElement][columnPart][opLevel]
                columnNumRows = #columnWords
            end
            numRows = math.max(numRows, columnNumRows)
            table.sort(columnWords, function(a, b) return a < b end)
            -- Store the words for this column and op level
            wordCollections[opLevel][columnElement .. "_" .. columnPart] = {
                words = columnWords,
                count = columnNumRows
            }
        end
        -- Now we have the max number of rows for this OP level, we can proceed to build the table
        -- Iterate over each column to build the rows for this OP level
        for rowIndex = 1, numRows do
            out = out .. '\n|-\n' -- Start a new row
            if rowIndex == 1 then
                out = out .. '|rowspan="' .. tostring(numRows) .. '" ' ..bgStr(opRowNum, 'op') .. opLevel
                opRowNum = opRowNum + 1
            else
                out = out .. ' '
            end
            for _, column in ipairs(actualColumns) do
                local columnElement = column.element
                local columnPart = column.part
                local cellContent = ''
                if wordCollections[opLevel][columnElement .. "_" .. columnPart] and wordCollections[opLevel][columnElement .. "_" .. columnPart].words[rowIndex] then
                    cellContent = wordCollections[opLevel][columnElement .. "_" .. columnPart].words[rowIndex]
                end
                if cellContent:find("%^") then
                    cellContent = "''" .. cellContent:gsub("%^", "") .. "''"
                    cellContent = frame:preprocess(cellContent)
                end
                -- Add the cell content to the output
                out = out .. '\n|' .. bgStr(rowNum, columnElement) .. cellContent
            end
            rowNum = rowNum + 1
        end
    end
    out = out .. '\n|}'
    return out
end

function p.get(frame)
    -- This function will be the main entry point to get the table
    local args = frame.args
    local elements = args.elements or 'all'
    if elements ~= 'all' then
        elements = mw.text.split(elements, '%s')
    end
    local parts = args.parts or 'all'
    if parts ~= 'all' then
        parts = mw.text.split(parts, '%s')
    end
    local ops = args.ops or 'all'
    if ops ~= 'all' then
        ops = mw.text.split(ops, '%s')
        for i, op in ipairs(ops) do
            ops[i] = tonumber(op)
        end
    end
    
    return p.getTable(frame, elements, parts, ops)
end

function p.all(frame)
    return p.getTable(frame, 'all', 'all', {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
end

function p.testInput(frame)
    local args = frame.args
    local out = ''
    for k, v in pairs(args) do
        out = out .. k .. ': ' .. tostring(v) .. '\n'
    end
    return out
end

return p