Module:HeroUtil

local cargo = mw.ext.cargo local List = require 'Module:ListUtil' local Datetime = require 'Module:DatetimeUtil' local escq = require 'Module:EscQ'.main1 local toboolean = require 'Module:Bool'.toboolean local memoize = require 'Module:Memoizer'.memoizer

local getLowestRarities = function (args) args = args or {} local useNonfocus = not (args.mask and not args.mask.nonfocus) local useFocus = not (args.mask and not args.mask.focus) local useReward = not (args.mask and not args.mask.reward) local unavailable = function return { nonfocus = useNonfocus and {} or nil, focus = useFocus and {} or nil, reward = useReward and {} or nil, bounds = function (self) local r = {} if self.nonfocus then List.concat_self(r, self.nonfocus) end if self.focus then List.concat_self(r, self.focus) end if self.reward then List.concat_self(r, self.reward) end return List.minmax(r) end, }	end local ret = {}

if useNonfocus then local nonfocusQuery = cargo.query('SummoningAvailability,Units=U', 'U._pageName=page,Rarity', {			join = 'SummoningAvailability._pageName=U._pageName',			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..				" AND IFNULL(Properties__full,) NOT LIKE '%enemy%' AND Rarity IS NOT NULL" ..				(args.current and ' AND (NOW BETWEEN StartTime AND EndTime)' or ) ..				(args.new and ' AND NewHeroes' or ''),			groupBy = 'page,Rarity',			orderBy = 'page,Rarity',			limit = 5000,		}) for page, vs in pairs(List.group_by(nonfocusQuery, function (v) return v.page end)) do			ret[page] = unavailable for _, v in ipairs(vs) do				table.insert(ret[page].nonfocus, tonumber(v.Rarity)) end end end

if useFocus then local focusQuery = cargo.query('SummoningEventFocuses=SEF,Units=U', 'U._pageName=page,Rarity', {			join = 'SEF.Unit=U.WikiName',			where = 'U.WikiName IS NOT NULL AND Rarity IS NOT NULL' .. (args.page and (" AND U._pageName='%s'"):format(escq(args.page)) or ''),			groupBy = 'page,Rarity',			orderBy = 'page,Rarity',			limit = 5000,		}) for page, vs in pairs(List.group_by(focusQuery, function (v) return v.page end)) do			ret[page] = ret[page] or unavailable for _, v in ipairs(vs) do				table.insert(ret[page].focus, tonumber(v.Rarity)) end end end

if useReward then local rewardQuery = cargo.query('Distributions,Units=U', 'U._pageName=page,Rarity', {			join = 'Distributions.Unit=U._pageName',			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND Rarity IS NOT NULL",			groupBy = 'page,Rarity',			orderBy = 'page,Rarity',			limit = 5000,		}) for page, vs in pairs(List.group_by(rewardQuery, function (v) return v.page end)) do			ret[page] = ret[page] or unavailable for _, v in ipairs(vs) do				table.insert(ret[page].reward, tonumber(v.Rarity)) end end end

return args.page and (ret[args.page] or unavailable) or ret end

local getReleaseTimes = function (args) args = args or {} local useNonfocus = not (args.mask and not args.mask.nonfocus) local useFocus = not (args.mask and not args.mask.focus) local useReward = not (args.mask and not args.mask.reward) local unavailable = function return { nonfocus = useNonfocus and 0x7FFFFFFF or nil, focus = useFocus and 0x7FFFFFFF or nil, reward = useReward and 0x7FFFFFFF or nil, earliest = function (self) return select(2, List.min(List.compact {0x7FFFFFFF, self.nonfocus, self.focus, self.reward})) end, }	end local ret = {}

if useNonfocus then local nonfocusQuery = cargo.query('SummoningAvailability,Units=U', 'U._pageName=page,MIN(StartTime)=t', {			join = 'SummoningAvailability._pageName=U._pageName',			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND StartTime IS NOT NULL",			groupBy = 'U.WikiName',			orderBy = 'U.WikiName',			limit = 5000,		}) for _, v in ipairs(nonfocusQuery) do			ret[v.page] = ret[v.page] or unavailable local t = Datetime.from_cargo(v.t)			if t < ret[v.page].nonfocus then ret[v.page].nonfocus = t			end end end

if useFocus then local focusQuery = cargo.query('SummoningEvents=SE,SummoningEventFocuses=SEF,Units=U', 'U._pageName=page,MIN(StartTime)=t', {			join = 'SE.WikiName=SEF.WikiName,SEF.Unit=U.WikiName',			where = 'U.WikiName IS NOT NULL AND StartTime IS NOT NULL' .. (args.page and (" AND U._pageName='%s'"):format(escq(args.page)) or ''),			groupBy = 'U.WikiName',			orderBy = 'U.WikiName',			limit = 5000,		}) for _, v in ipairs(focusQuery) do			ret[v.page] = ret[v.page] or unavailable local t = Datetime.from_cargo(v.t)			if t < ret[v.page].focus then ret[v.page].focus = t			end end end

if useReward then local rewardQuery = cargo.query('Distributions,Units=U', 'U._pageName=page,MIN(StartTime)=t', {			join = 'Distributions.Unit=U._pageName',			where = (args.page and ("U._pageName='%s'"):format(escq(args.page)) or 'U._pageName IS NOT NULL') ..				" AND IFNULL(Properties__full,'') NOT LIKE '%enemy%' AND StartTime IS NOT NULL",			groupBy = 'U.WikiName',			orderBy = 'U.WikiName',			limit = 5000,		}) for _, v in ipairs(rewardQuery) do			ret[v.page] = ret[v.page] or unavailable local t = Datetime.from_cargo(v.t)			if t < ret[v.page].reward then ret[v.page].reward = t			end end end

return args.page and (ret[args.page] or unavailable) or ret end

local getAvail = function (args) if args[1] then local nonfocus = toboolean(args.nonfocus) local focus = toboolean(args.focus) local reward = toboolean(args.reward) local mask = (nonfocus ~= nil or focus ~= nil or reward ~= nil) and { nonfocus = nonfocus, focus = focus, reward = reward, } or nil return getLowestRarities {page = args[1], current = true, mask = mask} end end

local lowestRarity = function (args) local avail = getAvail(args) return avail and (avail:bounds) end

local availabilityText; do	local rarityText = memoize(function (rarity)		return mw.getCurrentFrame:expandTemplate {title = 'Rarity', args = {rarity}}	end) availabilityText = function (args) local avail = type(args.avail) == 'table' and args.avail or getAvail(args) if avail then if avail.nonfocus and #avail.nonfocus > 0 then avail.focus = nil avail.reward = nil elseif avail.focus and #avail.focus > 0 then avail.reward = nil end local lo, hi = avail:bounds if hi then if lo == hi then return rarityText(lo) else return ('%s – %s'):format(rarityText(lo), rarityText(hi)) end end end return 'N/A' end end

local p = require 'Module:MakeMWModule'.makeMWModule { lowestRarity = lowestRarity, availabilityText = availabilityText, } p.getLowestRarities = getLowestRarities p.getReleaseTimes = getReleaseTimes return p