Module:StormforgedController: Difference between revisions

From Against the Storm Official Wiki
m (Updated a few comments and an error-type message.)
(Fixed duplication)
Line 23: Line 23:
local ARG_NAME = "name"
local ARG_NAME = "name"
local ARG_DESCRIPTION = "description"
local ARG_DESCRIPTION = "description"
local ARG_UPGRADABLE_ID = "upgrade_from_id"
local ARGS_EXCLUDE_LIST = "exclude"
local ARGS_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_CAPTION = "caption"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES_FLAG_VALUE = "skip"
local ARG_SKIP_PRICES_FLAG_VALUE = "skip"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_REGULAR_FLAG_VALUE = "show"


--local DISPLAY_OPTION_TABLE = "table"
--local DISPLAY_OPTION_TABLE = "table"


local TEMPLATE_PARAMETER_CAPTION = "caption"
local TEMPLATE_PARAMETER_SKIP_PRICES = "skip_prices"
local TEMPLATE_PARAMETER_ID = "id"
local TEMPLATE_PARAMETER_ID = "id"
local TEMPLATE_PARAMETER_DESC = "description"
local TEMPLATE_PARAMETER_DESC = "description"
Line 52: Line 57:
local currentFrame = {}
local currentFrame = {}
local altarIDs = {}
local altarIDs = {}
local isIDAlreadyAdded = {}


--endregion
--endregion
Line 83: Line 89:
---
---
---@param list table the list of unique identifiers for which to look up names
---@param list table the list of unique identifiers for which to look up names
local function validateNames(list)
local function validateNamesFromIDs()


     for _, id in ipairs(list) do
     for _, id in ipairs(altarIDs) do


       --Validate the names. This should never happen, but this is here to save hours of troubleshooting.
       --Validate the names. This should never happen, but this is here to save hours of troubleshooting.
Line 102: Line 108:


     for _, id in ipairs(newIDs) do
     for _, id in ipairs(newIDs) do
         if AltarEffectsData.isIDValid(id) and not excludeList[id] then
         if AltarEffectsData.isIDValid(id) and not excludeList[id] and not isIDAlreadyAdded[id] then
 
             table.insert(altarIDs, id)
             table.insert(altarIDs, id)
            isIDAlreadyAdded[id] = true
         end
         end
     end
     end
Line 113: Line 121:
---@param searchName string search term to look in cornerstone names
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
---@param excludeList table list of ids
local function loadIDs(selectedID, searchName, searchDesc, excludeList)
local function loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)


     if not altarIDs or #altarIDs < 1 then
     if not altarIDs or #altarIDs < 1 then


         altarIDs = {}
         altarIDs = {}
        isIDAlreadyAdded = {}
         local attemptedSearch = false
         local attemptedSearch = false


Line 139: Line 149:
             loadStormforgedIDs(newIDs, excludeList)
             loadStormforgedIDs(newIDs, excludeList)
             attemptedSearch = true
             attemptedSearch = true
        end
        -- Add any upgrade matches
        if regularID and regularID ~= "" then
            loadStormforgedIDs({ AltarEffectsData.getUpgradeWhereRegularID(regularID) }, excludeList)
         end
         end


         -- Or, if no searching was even attempted (regardless of result), show them all
         -- Or, if no searching was even attempted (regardless of result), show them all
         if not attemptedSearch then
         if not attemptedSearch then
             altarIDs = AltarEffectsData.getAllAltarIDs()
             local newIDs = AltarEffectsData.getAllAltarIDs()
            loadStormforgedIDs(newIDs, excludeList)
         end
         end
     end
     end
Line 149: Line 165:
     if #altarIDs > 0 then
     if #altarIDs > 0 then
         -- Remove all IDs that aren't for Stormforged Cornerstones--there were probably extra pulled from PerksData if there were search terms.
         -- Remove all IDs that aren't for Stormforged Cornerstones--there were probably extra pulled from PerksData if there were search terms.
         validateNames(altarIDs)
         validateNamesFromIDs()
 
         --Alphabetize by name
         --Alphabetize by name
         table.sort(altarIDs, compareNames)
         table.sort(altarIDs, compareNames)
     end
     end
end
end
Line 179: Line 193:
---@param searchName string the second search parameter, a name
---@param searchName string the second search parameter, a name
---@param searchDesc string the third search parameter, a term in a description
---@param searchDesc string the third search parameter, a term in a description
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param desiredCaption string the caption requested, if any
---@param desiredCaption string the caption requested, if any
---@return string an appropriate caption, or blank if it should be default
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(selectedID, searchName, searchDesc, desiredCaption)
local function resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)


     if desiredCaption and desiredCaption ~= "" then
     if desiredCaption and desiredCaption ~= "" then
Line 196: Line 211:
     if searchName and searchName ~= "" then
     if searchName and searchName ~= "" then
         return "Stormforged Cornerstones named '" .. searchName .. "'"
         return "Stormforged Cornerstones named '" .. searchName .. "'"
    end
    if regularID and regularID ~= "" then
        return "Stormforged Cornerstones upgraded from '" .. regularID .. "'"
     end
     end


     -- Delegate to the template for the default
     -- Delegate to the template for the default
     return ""
     return ""
end
---resolveStartTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveStartTemplate(skippingPrice)
    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""
    return TEMPLATE_CONTAINER_START .. suffixIfSkipping
end
---resolveRowTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveRowTemplate(skippingPrice)
    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""
    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_ROW .. suffixIfSkipping
end
---resolveEndTemplate
---@return string the template name to use
local function resolveEndTemplate()
    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_END
end
end


Line 207: Line 252:
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@return string the wiki markup to display, now longer
---@return string the wiki markup to display, now longer
local function makeMarkupForTableStart(desiredCaption, skippingPrice)
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)


     local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""
     local templateParameters = {
     local startTemplate = TEMPLATE_CONTAINER_START .. suffixIfSkipping
        [TEMPLATE_PARAMETER_CAPTION] = desiredCaption,
        [TEMPLATE_PARAMETER_SKIP_PRICES] = skippingPrice
     }


     return currentFrame:expandTemplate{
     return currentFrame:expandTemplate{ title = resolveStartTemplate(skippingPrice), args = templateParameters }
        title = startTemplate,
        args = { caption = desiredCaption, skip_prices = skippingPrice } }
end
end


Line 224: Line 269:
local function makeMarkupPerRow(skippingPrice, id)
local function makeMarkupPerRow(skippingPrice, id)


     local rowTemplate = TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_ROW
     local templateParameters = {
 
    templateParameters = {
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_ID] = id,
         [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id)
         [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id)
Line 232: Line 275:


     if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
     if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILL] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_PRICE_VILL] = AltarEffectsData.getPriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_VILL] = AltarEffectsData.getUpgradePriceInVillagers(id)
         templateParameters[TEMPLATE_PARAMETER_UPGRA_VILL] = AltarEffectsData.getUpgradePriceInVillagers(id)
    else
        rowTemplate = rowTemplate .. TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT
     end
     end


     return currentFrame:expandTemplate{
     return currentFrame:expandTemplate{ title = resolveRowTemplate(skippingPrice), args = templateParameters }
        title = rowTemplate, args = templateParameters }
end
end


Line 265: Line 303:
local function makeMarkupForTableEnd()
local function makeMarkupForTableEnd()


    local endTemplate = TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_END
     return currentFrame:expandTemplate{ title = resolveEndTemplate(), args = {} }
 
     return currentFrame:expandTemplate{
        title = endTemplate,
        args = {} }
end
end


Line 279: Line 313:
---@param searchName string search term to look in cornerstone names
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
---@param excludeList table list of ids
---@param desiredCaption string override the table caption
---@param desiredCaption string override the table caption
---@param skippingPrice string flag if some columns should be skipped
---@param skippingPrice string flag if some columns should be skipped
---@param showingRegular string flag if columns should be added
---@return string the wiki markup assembled by the view (other templates)
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(selectedID, searchName, searchDesc, excludeList, desiredCaption, skippingPrice)
local function renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)


     loadIDs(selectedID, searchName, searchDesc, excludeList)
     loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)


     if #altarIDs < 1 then
     if #altarIDs < 1 then
Line 291: Line 327:
     end
     end


     desiredCaption = resolveCaption(selectedID, searchName, searchDesc, desiredCaption)
     desiredCaption = resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)
 
    local startMarkup = makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
    local rowsMarkup =  makeMarkupForTableRows(skippingPrice, showingRegular)


     return makeMarkupForTableStart(desiredCaption, skippingPrice) .. makeMarkupForTableRows(skippingPrice) .. "\n" .. makeMarkupForTableEnd()
     return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
end
end


Line 311: Line 350:
     local searchName = frame.args[ARG_NAME]
     local searchName = frame.args[ARG_NAME]
     local searchDesc = frame.args[ARG_DESCRIPTION]
     local searchDesc = frame.args[ARG_DESCRIPTION]
    local regularID = frame.args[ARG_UPGRADABLE_ID]
     local exclusions = frame.args[ARGS_EXCLUDE_LIST]
     local exclusions = frame.args[ARGS_EXCLUDE_LIST]
     local desiredCaption = frame.args[ARG_CAPTION]
     local desiredCaption = frame.args[ARG_CAPTION]
     local skippingPrice = frame.args[ARG_SKIP_PRICES]
     local skippingPrice = frame.args[ARG_SKIP_PRICES]
    local showingRegular = frame.args[ARG_SHOW_REGULAR]


     --TODO make displayOverride == DISPLAY_OPTION_LIST
     --TODO make displayOverride == DISPLAY_OPTION_LIST
Line 323: Line 364:


     currentFrame = frame
     currentFrame = frame
     return renderTable(selectedID, searchName, searchDesc, excludeList, desiredCaption, skippingPrice)
     return renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)
end
end



Revision as of 21:33, 1 May 2024

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

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by onken.
--- DateTime: 4/29/2024 9:27 PM
---
---@module StormforgedController
local StormforgedController = {}



--region Dependencies

local AltarEffectsData = require("Module:AltarEffectsData")
local PerksData = require("Module:PerksData")

--endregion



--region Private constants

local ARG_ID = "id"
local ARG_NAME = "name"
local ARG_DESCRIPTION = "description"
local ARG_UPGRADABLE_ID = "upgrade_from_id"
local ARGS_EXCLUDE_LIST = "exclude"
local ARG_CAPTION = "caption"
local ARG_SKIP_PRICES = "skip_prices"
local ARG_SKIP_PRICES_FLAG_VALUE = "skip"
local ARG_SHOW_REGULAR = "show_regular"
local ARG_SHOW_REGULAR_FLAG_VALUE = "show"

--local DISPLAY_OPTION_TABLE = "table"

local TEMPLATE_PARAMETER_CAPTION = "caption"
local TEMPLATE_PARAMETER_SKIP_PRICES = "skip_prices"
local TEMPLATE_PARAMETER_ID = "id"
local TEMPLATE_PARAMETER_DESC = "description"
local TEMPLATE_PARAMETER_PRICE_META = "price_in_meta_resources"
local TEMPLATE_PARAMETER_PRICE_VILL = "price_in_villagers"
local TEMPLATE_PARAMETER_UPGRA_META = "price_for_upgrade_in_meta_resources"
local TEMPLATE_PARAMETER_UPGRA_VILL = "price_for_upgrade_in_villagers"

local TEMPLATE_CONTAINER_START = "StormforgedCornerstonesTable"
local TEMPLATE_CONTAINER_SUFFIX_ROW = "/row"
local TEMPLATE_CONTAINER_SUFFIX_END = "/end"
local TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT = "/SkipPrices"

local ERROR_PREFIX_NAME_NOT_FOUND = "StormforgedController attempted to retrieve the display name of a Stormforged Cornerstones, but it was not found. Double-check that the data is up-to-date and loaded correctly:"

--endregion



--region Private member variables

local currentFrame = {}
local altarIDs = {}
local isIDAlreadyAdded = {}

--endregion



--region Private methods

--- Helper comparison function to give to table.sort to sort the perk names alphabetically that correspond to the identifiers of Stormforged Cornerstones.
---
---@param altarID1 string the identifier of a Stormforged Cornerstone
---@param altarID2 string the identifier of a Stormforged Cornerstone
---@return boolean to sort the corresponding display names alphabetically
local function compareNames(altarID1, altarID2)

    local name1 = PerksData.getNameByID(altarID1)
    local name2 = PerksData.getNameByID(altarID2)

    if not name1 then
        error(ERROR_PREFIX_NAME_NOT_FOUND .. " id=" .. altarID1 .. ".")
    end
    if not name2 then
        error(ERROR_PREFIX_NAME_NOT_FOUND .. " id=" .. altarID2 .. ".")

    end

    return name1 < name2
end

--- Runs through the list of perk IDs and checks that a name exists for each one. If not, it throws an error identifying the offending ID.
---
---@param list table the list of unique identifiers for which to look up names
local function validateNamesFromIDs()

    for _, id in ipairs(altarIDs) do

       --Validate the names. This should never happen, but this is here to save hours of troubleshooting.
        local name = PerksData.getNameByID(id)
        if not name then
            error(ERROR_PREFIX_NAME_NOT_FOUND .. "id=" .. id)
        end
    end
end

--- Takes a list of possible IDs and only loads the valid ones (Stormforged ones) to the member variable altardIDs. Skips all ids present in the exclude list.
---
---@param newIDs table a list of possible IDs to add to main list
---@param excludeList table where keys are ids to skip and the values are `true`
local function loadStormforgedIDs(newIDs, excludeList)

    for _, id in ipairs(newIDs) do
        if AltarEffectsData.isIDValid(id) and not excludeList[id] and not isIDAlreadyAdded[id] then

            table.insert(altarIDs, id)
            isIDAlreadyAdded[id] = true
        end
    end
end

--- Requests the lists of IDs from both AltarEffects and Perks data models, applies some post-processing, and stores them in the member variable.
---
---@param selectedID string the id of the cornerstone to include
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
local function loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)

    if not altarIDs or #altarIDs < 1 then

        altarIDs = {}
        isIDAlreadyAdded = {}
        local attemptedSearch = false

        -- Load the selected ID
        if selectedID and selectedID ~= "" then
            loadStormforgedIDs( { selectedID }, excludeList )
            attemptedSearch = true
        end

        -- Add any name matches
        if searchName and searchName ~= "" then
            local newIDs = PerksData.getAllPerkIDsWhereName(searchName)
            loadStormforgedIDs(newIDs, excludeList)
            attemptedSearch = true
        end

        -- Add any description matches
        if searchDesc and searchDesc ~= "" then
            local newIDs = PerksData.getAllPerkIDsWhereDescription(searchDesc)
            loadStormforgedIDs(newIDs, excludeList)
            attemptedSearch = true
        end

        -- Add any upgrade matches
        if regularID and regularID ~= "" then
            loadStormforgedIDs({ AltarEffectsData.getUpgradeWhereRegularID(regularID) }, excludeList)
        end

        -- Or, if no searching was even attempted (regardless of result), show them all
        if not attemptedSearch then
            local newIDs = AltarEffectsData.getAllAltarIDs()
            loadStormforgedIDs(newIDs, excludeList)
        end
    end

    if #altarIDs > 0 then
        -- Remove all IDs that aren't for Stormforged Cornerstones--there were probably extra pulled from PerksData if there were search terms.
        validateNamesFromIDs()
        --Alphabetize by name
        table.sort(altarIDs, compareNames)
    end
end


---expandExclusions
---@param exclusions string the list of ids, separated by commas
---@return table the ids now as keys in the table and each value is `true`
local function expandExclusions(exclusions)

    local excludeList = {}
    for idToExclude in string.gmatch(exclusions, "[^,]+") do
        excludeList[idToExclude] = true
    end

    return excludeList
end


--- Ensures that if a caption is not defined, there is a suitable fallback in case the author has specified an id, name, or search term to use, so readers know what they're looking at.
---
--- If no caption was specified and also none of those filtering parameters, then leave it up to the template by returning a blank caption.
---
---@param selectedID string the first search parameter, an id
---@param searchName string the second search parameter, a name
---@param searchDesc string the third search parameter, a term in a description
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param desiredCaption string the caption requested, if any
---@return string an appropriate caption, or blank if it should be default
local function resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)

    if desiredCaption and desiredCaption ~= "" then
        return desiredCaption
    end

    if selectedID and selectedID ~= "" then
        return "Stormforged Cornerstone with id '" .. selectedID .. "'"
    end
    -- Do this first since mentioning could also imply name, but not the other way around.
    if searchDesc and searchDesc ~= "" then
        return "Stormforged Cornerstones mentioning '" .. searchDesc .. "'"
    end
    if searchName and searchName ~= "" then
        return "Stormforged Cornerstones named '" .. searchName .. "'"
    end
    if regularID and regularID ~= "" then
        return "Stormforged Cornerstones upgraded from '" .. regularID .. "'"
    end

    -- Delegate to the template for the default
    return ""
end

---resolveStartTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveStartTemplate(skippingPrice)

    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_CONTAINER_START .. suffixIfSkipping
end

---resolveRowTemplate
---@param skippingPrice string the flag deciding whether to skip some columns
---@return string the template name to use
local function resolveRowTemplate(skippingPrice)

    local suffixIfSkipping = (skippingPrice == ARG_SKIP_PRICES_FLAG_VALUE and TEMPLATE_CONTAINER_SKIP_PRICES_VARIANT) or ""

    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_ROW .. suffixIfSkipping
end

---resolveEndTemplate
---@return string the template name to use
local function resolveEndTemplate()

    return TEMPLATE_CONTAINER_START .. TEMPLATE_CONTAINER_SUFFIX_END
end

--- Calls the view (other templates) to render the beginning of the table.
---
---@param desiredCaption string the caption for the table, if any
---@param skippingPrice string the flag for skipping prices in the table, if any
---@return string the wiki markup to display, now longer
local function makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)

    local templateParameters = {
        [TEMPLATE_PARAMETER_CAPTION] = desiredCaption,
        [TEMPLATE_PARAMETER_SKIP_PRICES] = skippingPrice
    }

    return currentFrame:expandTemplate{ title = resolveStartTemplate(skippingPrice), args = templateParameters }
end

--- Calls the view (other templates) to render a single row of the table with data based on the provided identifier.
---
---@param skippingPrice string the flag for skipping prices in the table, if any
---@param id string the unique identifier of a Stormforged Cornerstone to use to add data to a new table row
---@return string the wiki markup to display, now longer
local function makeMarkupPerRow(skippingPrice, id)

    local templateParameters = {
        [TEMPLATE_PARAMETER_ID] = id,
        [TEMPLATE_PARAMETER_DESC] = PerksData.getDescriptionByID(id)
    }

    if skippingPrice ~= ARG_SKIP_PRICES_FLAG_VALUE then
        templateParameters[TEMPLATE_PARAMETER_PRICE_META] = AltarEffectsData.getPriceInMetaResources(id)
        templateParameters[TEMPLATE_PARAMETER_PRICE_VILL] = AltarEffectsData.getPriceInVillagers(id)
        templateParameters[TEMPLATE_PARAMETER_UPGRA_META] = AltarEffectsData.getUpgradePriceInMetaResources(id)
        templateParameters[TEMPLATE_PARAMETER_UPGRA_VILL] = AltarEffectsData.getUpgradePriceInVillagers(id)
    end

    return currentFrame:expandTemplate{ title = resolveRowTemplate(skippingPrice), args = templateParameters }
end

--- Handles assembling the rows for all of the IDs in the member variable list altarIDs.
---
---@param skippingPrice string the flag for skipping prices in the table, if any
---@return string the wiki markup to display, now longer
local function makeMarkupForTableRows(skippingPrice)

    local markup = ""
    for _, id in ipairs(altarIDs) do
        markup = markup .. makeMarkupPerRow(skippingPrice, id)
    end

    return markup
end

--- Calls the view (other templates) to render the end of the table.
---
---@return string the wiki markup to display, now longer
local function makeMarkupForTableEnd()

    return currentFrame:expandTemplate{ title = resolveEndTemplate(), args = {} }
end

---Calls the view (other templates) to render the content and appends it to the wiki markup string that will replace this controller's template.
---
--- Calls several methods to build pieces of the table's markup based on the author's requests.
---
---@param selectedID string the id of the cornerstone to include
---@param searchName string search term to look in cornerstone names
---@param searchDesc string search term to look in cornerstone descriptions
---@param regularID string the id of the cornerstone that gets upgraded to a Stormforged version
---@param excludeList table list of ids
---@param desiredCaption string override the table caption
---@param skippingPrice string flag if some columns should be skipped
---@param showingRegular string flag if columns should be added
---@return string the wiki markup assembled by the view (other templates)
local function renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)

    loadIDs(selectedID, searchName, searchDesc, regularID, excludeList)

    if #altarIDs < 1 then
        return "No matching Stormforged Cornerstones found."
    end

    desiredCaption = resolveCaption(selectedID, searchName, searchDesc, regularID, desiredCaption)

    local startMarkup = makeMarkupForTableStart(desiredCaption, skippingPrice, showingRegular)
    local rowsMarkup =  makeMarkupForTableRows(skippingPrice, showingRegular)

    return startMarkup .. rowsMarkup .. makeMarkupForTableEnd()
end

--endregion



--region Public methods

---main
---@param frame table the MediaWiki frame provided by the template call
---@return string wiki markup to display
function StormforgedController.main(frame)

    -- Extract template parameters
    local selectedID = frame.args[ARG_ID]
    local searchName = frame.args[ARG_NAME]
    local searchDesc = frame.args[ARG_DESCRIPTION]
    local regularID = frame.args[ARG_UPGRADABLE_ID]
    local exclusions = frame.args[ARGS_EXCLUDE_LIST]
    local desiredCaption = frame.args[ARG_CAPTION]
    local skippingPrice = frame.args[ARG_SKIP_PRICES]
    local showingRegular = frame.args[ARG_SHOW_REGULAR]

    --TODO make displayOverride == DISPLAY_OPTION_LIST

    local excludeList = {}
    if exclusions and exclusions ~= "" then
        excludeList = expandExclusions(exclusions)
    end

    currentFrame = frame
    return renderTable(selectedID, searchName, searchDesc, regularID, excludeList, desiredCaption, skippingPrice, showingRegular)
end

--endregion

return StormforgedController