-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster -- -- https://tradeskillmaster.com -- -- All Rights Reserved - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- local _, TSM = ... local GroupSearch = TSM.Shopping:NewPackage("GroupSearch") local L = TSM.Include("Locale").GetTable() local Log = TSM.Include("Util.Log") local TempTable = TSM.Include("Util.TempTable") local ItemString = TSM.Include("Util.ItemString") local Threading = TSM.Include("Service.Threading") local ItemInfo = TSM.Include("Service.ItemInfo") local GroupSearchContext = TSM.Include("LibTSMClass").DefineClass("GroupSearchContext", TSM.Shopping.ShoppingSearchContext) local private = { groups = {}, itemList = {}, maxQuantity = {}, scanThreadId = nil, seenMaxPrice = {}, searchContext = nil, queries = {}, } -- ============================================================================ -- Module Functions -- ============================================================================ function GroupSearch.OnInitialize() -- initialize thread private.scanThreadId = Threading.New("GROUP_SEARCH", private.ScanThread) private.searchContext = GroupSearchContext(private.scanThreadId, private.MarketValueFunction) end function GroupSearch.GetSearchContext(groupList) return private.searchContext:SetScanContext(L["Group Search"], groupList, nil, L["Max Price"]) end -- ============================================================================ -- Scan Thread -- ============================================================================ function private.ScanThread(auctionScan, groupList) wipe(private.seenMaxPrice) -- create the list of items, and add filters for them wipe(private.itemList) wipe(private.maxQuantity) wipe(private.queries) for _, groupPath in ipairs(groupList) do private.groups[groupPath] = true for _, itemString in TSM.Groups.ItemIterator(groupPath) do local isValid, maxQuantityOrErr = TSM.Operations.Shopping.ValidAndGetRestockQuantity(itemString) if isValid then private.maxQuantity[itemString] = maxQuantityOrErr tinsert(private.itemList, itemString) elseif maxQuantityOrErr then Log.PrintfUser(L["Invalid custom price source for %s. %s"], ItemInfo.GetLink(itemString), maxQuantityOrErr) end end end if #private.itemList == 0 then return false end auctionScan:AddItemListQueriesThreaded(private.itemList) for _, query in auctionScan:QueryIterator() do query:SetIsBrowseDoneFunction(private.QueryIsBrowseDoneFunction) query:AddCustomFilter(private.QueryFilter) tinsert(private.queries, query) end -- run the scan if not auctionScan:ScanQueriesThreaded() then Log.PrintUser(L["TSM failed to scan some auctions. Please rerun the scan."]) end return true end -- ============================================================================ -- GroupSearchContext Class -- ============================================================================ function GroupSearchContext.GetMaxCanBuy(self, itemString) return private.maxQuantity[itemString] end function GroupSearchContext.OnBuy(self, itemString, quantity) self.__super:OnBuy(itemString, quantity) if not private.maxQuantity[itemString] then return end private.maxQuantity[itemString] = private.maxQuantity[itemString] - quantity if private.maxQuantity[itemString] <= 0 then private.maxQuantity[itemString] = nil local toRemove = TempTable.Acquire() for _, query in ipairs(private.queries) do for _, row in query:BrowseResultsIterator() do if row:HasItemInfo() then for _, subRow in row:SubRowIterator() do if subRow:GetItemString() == itemString then tinsert(toRemove, subRow) end end for _, subRow in ipairs(toRemove) do row:RemoveSubRow(subRow) end wipe(toRemove) end end end TempTable.Release(toRemove) end end -- ============================================================================ -- Private Helper Functions -- ============================================================================ function private.QueryIsBrowseDoneFunction(query) local isDone = true for itemString in query:ItemIterator() do if TSM.Operations.Shopping.ShouldShowAboveMaxPrice(itemString) then -- need to scan all the auctions isDone = false elseif not private.seenMaxPrice[itemString] then -- we haven't seen any auctions above the max price, so need to keep scanning isDone = false end end return isDone end function private.QueryFilter(query, row) local baseItemString = row:GetBaseItemString() local itemString = row:GetItemString() local _, itemBuyout, minItemBuyout = row:GetBuyouts() itemBuyout = itemBuyout or minItemBuyout if not itemBuyout then return false elseif itemBuyout == 0 then return true end if itemString then local isFiltered, aboveMax = TSM.Operations.Shopping.IsFiltered(itemString, itemBuyout) private.seenMaxPrice[itemString] = private.seenMaxPrice[itemString] or aboveMax return isFiltered else local allFiltered = true for queryItemString in query:ItemIterator() do if ItemString.GetBaseFast(queryItemString) == baseItemString and not TSM.Operations.Shopping.IsFiltered(queryItemString, itemBuyout) then allFiltered = false end end return allFiltered end end function private.MarketValueFunction(row) local itemString = row:GetItemString() return itemString and TSM.Operations.Shopping.GetMaxPrice(itemString) or nil end