Module:PerkSearchController

From Against the Storm Official Wiki
Revision as of 15:11, 3 December 2023 by Aeredor (talk | contribs) (Created to manage searching perks)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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 intersection of the two. Slightly more
--- efficient if the second list is smaller than the first.
---
---@param list1 table a flat table (list of values)
---@param list2 table another flat table
---@return table a similarly flat table consisting only of the values that are in both provided lists
local function findIntersection(list1, list2)

	local intersection = {}

	-- Create a new mapping to efficiently check for existence in list2 by
	-- checking the same ID in the next loop.
	local setList2 = {}
	for _, value in ipairs(list2 or {}) do
		setList2[value] = true
	end

	-- Check for intersection and populate the result table.
	for _, valueToFind in ipairs(list1 or {}) do
		if setList2[valueToFind] then
			table.insert(intersection, valueToFind)
		end
	end

	if #intersection == 0 then
		return nil
	end

	return intersection
end



---
--- 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 union = {}

	for _, value in ipairs(list2) do
		table.insert(union, value)
	end

	-- Have to check before adding them to not add duplicates.
	for _, value in ipairs(list1) do
		for _, alreadyValue in ipairs(list2) do
			if value ~= alreadyValue then
				table.insert(union, value)
			end
		end
	end

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



local function buildRowsForPerks(perkList, displayOverride)

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



local function filterAllSources(listOfIDs, source)

	-- Remove any that do not have the specified source.
	for i, perkID in pairs(listOfIDs) do

		if not PerksData.isAnySource(perkID, source) then
			listOfIDs[i] = nil
		end
	end
end



local function filterAllRarities(listOfIDs, rarity)

	-- Remove any that do not have the specified rarity.
	for i, perkID in pairs(listOfIDs) do

		if not PerksData.isRarityMatchByID(perkID, rarity) then
			listOfIDs[i] = nil
		end
	end
end



function PerkSearchController.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 )

	return PerkSearchResultsView.endView(displayOverride)
end



function PerkSearchController.renderFromName(name, displayOverride)

	local perkIDsList = PerksData.getAllPerkIDsByName(name)

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

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

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

	buildRowsForPerks(perkIDsList, displayOverride)

	return PerkSearchResultsView.endView(displayOverride)
end



function PerkSearchController.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 = #perkIDsList
	local isFromTrader = isAnyFromTrader(perkIDsList)

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

	buildRowsForPerks(filteredList, displayOverride)

	return PerkSearchResultsView.endView(displayOverride)
end

--endregion



--region Public methods

function PerkSearchController.searchResults(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

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

--endregion

return PerkSearchController