Module:PerkSearchController

From Against the Storm Official Wiki

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

---
--- Module for searching data on perks and displaying results
---
--- @module PerkSearchController
local PerkSearchController = {}



local PerkSearchResultsView = require("Module:PerkSearchResultsView")

local PerksData = require("Module:PerksData")



--region Private member variables

--endregion



--region Private constants

--endregion



--region Private methods

---
--- Takes two lists and returns the union of the two.
---
---@param list1 table a flat table (list of values)
---@param list2 table another flat table
---@return table a similarly flat table consisting of the values of both lists
local function findUnion(list1, list2)

	local unionList = {}

	-- Have to check before adding them to not add duplicates.
	local checkList = {}
	for _, value in ipairs(list2) do
		table.insert(unionList, value)
		checkList[value] = true
	end


	for _, value in ipairs(list1) do
		if not checkList[value] then
			table.insert(unionList, value)
			checkList[value] = true
		end
	end

	return unionList
end



---
--- Runs through the provided list of IDs and returns true if any are from
--- a Trader.
---
---@param perkIDsList table list of perkIDs
---@return boolean whether any in the list are from a Trader
local function isAnyFromTrader(perkIDsList)

	-- Should never be nil at runtime.
	if not perkIDsList then
		error("Invalid list of perk IDs.")
	end

	for _, perkID in ipairs(perkIDsList) do

		if PerksData.isFromTraderByID(perkID) then
			return true
		end
	end

	return false
end



---
--- Searches through perks for matches in descriptions and names and returns
--- the results of both merged into one list.
---
---@param searchTerm string the terms to search for
---@return table a list of perk IDs that match
local function searchAllNamesAndDescriptions(searchTerm)

	local listFromSearchingNames = PerksData.getAllPerkIDsWhereName(searchTerm)
	local listFromSearchingDescriptions = PerksData.getAllPerkIDsWhereDescription(searchTerm)

	return findUnion(listFromSearchingDescriptions, listFromSearchingNames)
end



---
--- Loops through a list of IDs and filters out any that don't match the
--- specified source.
---
---@param listOfIDs table list of perk IDs
---@param source string the type of source to filter
---@return table the same list, but fewer items
local function filterAllSources(listOfIDs, source)

	-- Should never be nil at runtime.
	if not source then
		error("Invalid parameter for source.")
	end

	local newList = {}
	-- Remove any that do not have the specified source.
	for _, perkID in ipairs(listOfIDs) do

		if PerksData.isAnySource(perkID, source) then
			table.insert(newList, perkID)
		end
	end

	return newList
end



---
--- Loops through a list of IDs and filters out any that don't match the
--- specified rarity.
---
---@param listOfIDs table list of perk IDs
---@param rarity string a rarity constant to filter
---@return table the same list, but fewer items
local function filterAllRarities(listOfIDs, rarity)

	-- Should never be nil at runtime.
	if not rarity then
		error("Invalid parameter for rarity.")
	end

	local newList = {}
	-- Remove any that do not have the specified rarity.
	for _, perkID in ipairs(listOfIDs) do

		if PerksData.isRarityMatchByID(perkID, rarity) then
			table.insert(newList, perkID)
		end
	end

	return newList
end



---
--- Main engine converting the list of IDs into calls to the View to render
--- rows (or whatever based on list override).
---
---@param perkList table list of perk IDs
---@param displayOverride string how to display, if not default
---@param hasLastColumn boolean whether to write the last column
local function buildRowsForPerks(perkList, displayOverride, hasLastColumn)

	for _, perkID in ipairs(perkList or {}) do

		local perkName = PerksData.getNameByID(perkID)
		local description = PerksData.getDescriptionByID(perkID)
		local iconFilename = PerksData.getIconByID(perkID)
		local rarity = PerksData.getRarityByID(perkID)
		local price = PerksData.getPriceByID(perkID)

		local sourceCornerstone = PerksData.isFromCornerstoneByID(perkID)
		local sourceEvent = PerksData.isFromEventByID(perkID)
		local sourceOrder = PerksData.isFromOrderByID(perkID)
		local sourceTrader = PerksData.isFromTraderByID(perkID)

		PerkSearchResultsView.addRowForPerk(displayOverride, perkName,
				description, iconFilename, rarity, price,
				sourceCornerstone, sourceEvent, sourceOrder, sourceTrader, hasLastColumn)
	end
end



---
--- Organizes a list of IDs to send to the build method. Calls the View's
--- setup, builds, and end.
---
---@param perkID string a single perk's ID
---@param displayOverride string how to display, if not default
local function renderFromID(perkID, displayOverride)

	local perkName = PerksData.getNameByID(perkID)

	if not perkName then
		return "No perk found with ID " .. perkID .. "."
	end

	local isFromTrader = PerksData.isFromTraderByID(perkID)

	PerkSearchResultsView.startViewForPerk(perkName, displayOverride, isFromTrader)

	buildRowsForPerks( { perkID }, displayOverride, isFromTrader)

	return PerkSearchResultsView.endView(displayOverride)
end



---
--- Organizes a list of IDs to send to the build method. Calls the View's
--- setup, builds, and end.
---
---@param perkName string the name of a Perk
---@param displayOverride string how to display, if not default
local function renderFromName(perkName, displayOverride)

	local perkIDsList = PerksData.getAllPerkIDsByName(perkName)

	if not perkIDsList or #perkIDsList == 0 then
		return "No perk found with name " .. perkName .. "."
	end

	local numPerks = #perkIDsList
	local isFromTrader = isAnyFromTrader(perkIDsList)

	PerkSearchResultsView.startViewForName(perkName, displayOverride, numPerks, isFromTrader)

	buildRowsForPerks(perkIDsList, displayOverride, isFromTrader)

	return PerkSearchResultsView.endView(displayOverride)
end



---
--- Organizes a list of IDs to send to the build method. Calls the View's
--- setup, builds, and end.
---
---@param searchTerm string the text to search from all perks
---@param source string the type of source to filter, if any
---@param rarity string a rarity constant to filter, if any
---@param displayOverride string how to display, if not default
---@return table
local function renderSearch(searchTerm, source, rarity, displayOverride)

	local starterList = searchAllNamesAndDescriptions(searchTerm)

	local filteredList = starterList
	if source ~= nil then
		filteredList = filterAllSources(filteredList, source)
	end
	if rarity ~= nil then
		filteredList = filterAllRarities(filteredList, rarity)
	end

	if not filteredList or #filteredList == 0 then
		return "No perk found with specified search criteria."
	end

	local numPerks = #filteredList
	local isFromTrader = isAnyFromTrader(filteredList)

	PerkSearchResultsView.startViewForSearchResults(searchTerm, source, rarity, displayOverride, numPerks, isFromTrader)

	buildRowsForPerks(filteredList, displayOverride, isFromTrader)

	return PerkSearchResultsView.endView(displayOverride)
end

--endregion



--region Public methods

---
--- Main method invoked from the template.
---
---@param frame table the MediaWiki calling context
---@return string long wiki markup with the results
function PerkSearchController.search(frame)

	-- Extract the template parameters.
	local perkID = frame.args.id or frame.args[1]
	local name = frame.args.name
	local searchTerm = frame.args.search
	local source = frame.args.source
	local rarity = frame.args.rarity
	local displayOverride = frame.args.display

	-- Convert empty strings on these only to nil
	if source == "" then
		source = nil
	end
	if rarity == "" then
		rarity = nil
	end

	if perkID and perkID ~= "" then
		return renderFromID(perkID, displayOverride)
	else
		if name and name ~= "" then
			return renderFromName(name, displayOverride)
		else
			if searchTerm and searchTerm ~= "" then
				return renderSearch(searchTerm, source, rarity, displayOverride)
			else
				return "Unknown parameter in Perk Search template."
			end
		end
	end
end

--endregion

return PerkSearchController