Module:StormforgedController

--- --- 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