468 lines
18 KiB
Lua
468 lines
18 KiB
Lua
--[[
|
|
Auctioneer Addon for World of Warcraft(tm).
|
|
Version: 5.9.4961 (WhackyWallaby)
|
|
Revision: $Id: BeanCounterSearch.lua 4933 2010-10-13 17:16:14Z Nechckn $
|
|
|
|
BeanCounterSearch - Search routines for BeanCounter data
|
|
URL: http://auctioneeraddon.com/
|
|
|
|
License:
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program(see GPL.txt); if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
Note:
|
|
This AddOn's source code is specifically designed to work with
|
|
World of Warcraft's interpreted AddOn system.
|
|
You have an implicit license to use this AddOn with these facilities
|
|
since that is it's designated purpose as per:
|
|
http://www.fsf.org/licensing/licenses/gpl-faq.html#InterpreterIncompat
|
|
]]
|
|
LibStub("LibRevision"):Set("$URL: http://svn.norganna.org/auctioneer/branches/5.9/BeanCounter/BeanCounterSearch.lua $","$Rev: 4933 $","5.1.DEV.", 'auctioneer', 'libs')
|
|
|
|
local lib = BeanCounter
|
|
local private, print, get, set, _BC = lib.getLocals()
|
|
|
|
local ipairs,pairs,select,type,next = ipairs,pairs,select,type,next
|
|
local tinsert = tinsert
|
|
local tonumber,tostring = tonumber,tostring
|
|
local abs = abs
|
|
local strsplit = strsplit
|
|
|
|
local function debugPrint(...)
|
|
if get("util.beancounter.debugSearch") then
|
|
private.debugPrint("BeanCounterSearch",...)
|
|
end
|
|
end
|
|
|
|
|
|
local data = {}
|
|
local style = {}
|
|
local temp ={}
|
|
local tbl = {}
|
|
|
|
|
|
--This is all handled by ITEMIDS need to remove/rename this to be a utility to convert text searches to itemID searches
|
|
function private.startSearch(itemName, settings, queryReturn, count, itemTexture) --queryReturn is passed by the externalsearch routine, when an addon wants to see what data BeanCounter knows
|
|
--Run the compression function once per session, use first search as trigger
|
|
--Check the postedDB tables and remove any entries that are older than 31 Days
|
|
if not private.compressed then private.refreshItemIDArray() private.sortArrayByDate() private.compactDB() private.prunePostedDB() private.sumDatabase() private.compressed = true end
|
|
|
|
if not itemName then return end
|
|
if not settings then settings = private.getCheckboxSettings() end
|
|
|
|
tbl = {}
|
|
for itemKey, data in pairs(BeanCounterDBNames) do
|
|
if data:lower():find(itemName:lower(), 1, true) then
|
|
if settings.exact and private.frame.searchBox:GetText() ~= "" then --if the search field is blank do not exact check
|
|
local _, name = strsplit(";", data)
|
|
if itemName:lower() == name:lower() then
|
|
local itemID, suffix = strsplit(":", itemKey)--Create a list of itemIDs that match the search text
|
|
settings.suffix = suffix -- Store Suffix used to later filter unwated results from the itemID search
|
|
tbl[itemID] = itemID --Since its possible to have the same itemID returned multiple times this will only allow one instance to be recorded
|
|
break
|
|
end
|
|
else
|
|
local itemID = strsplit(":", itemKey)--Create a list of itemIDs that match the search text
|
|
tbl[itemID] = itemID --Since its possible to have the same itemID returned multiple times this will only allow one instance to be recorded
|
|
end
|
|
end
|
|
end
|
|
|
|
if queryReturn then --need to return the ItemID results to calling function
|
|
return private.searchByItemID(tbl, settings, queryReturn, count, itemTexture, itemName)
|
|
else
|
|
--get the itemTexture for display in the drop box
|
|
for i, data in pairs(BeanCounterDBNames) do
|
|
local _, name = strsplit(";", data)
|
|
if name:lower() == itemName:lower() then
|
|
local itemID = strsplit(":", i) or ""
|
|
_, itemTexture = private.getItemInfo(itemID, "name")
|
|
break
|
|
end
|
|
end
|
|
private.searchByItemID(tbl, settings, queryReturn, count, itemTexture, itemName)
|
|
end
|
|
end
|
|
|
|
|
|
function private.searchByItemID(id, settings, queryReturn, count, itemTexture, classic)
|
|
if not id then return end
|
|
if not settings then settings = private.getCheckboxSettings() end
|
|
if not count then count = get("numberofdisplayedsearchs") end --count determines how many results we show or display High # ~to display all
|
|
|
|
tbl = {}
|
|
if type(id) == "table" then --we can search for a sinlge itemID or an array of itemIDs
|
|
for i,v in pairs(id)do
|
|
tinsert(tbl, tostring(v))
|
|
end
|
|
else
|
|
tbl[1] = tostring(id)
|
|
end
|
|
|
|
data = {}
|
|
style = {}
|
|
|
|
local profit, low, high, serverName, playerName
|
|
--serverName and playerName are used as part of our cache ID string
|
|
if settings.servers and settings.servers[1] then
|
|
serverName = settings.servers[1]
|
|
else
|
|
serverName = GetRealmName()
|
|
end
|
|
if settings.selectbox and settings.selectbox[2] then
|
|
playerName = settings.selectbox[2]
|
|
else
|
|
playerName = "server"
|
|
end
|
|
|
|
--check if we have a cache of this search
|
|
local cached = private.checkSearchCache(classic or tbl[1], serverName, playerName)
|
|
if cached then
|
|
data = cached
|
|
else
|
|
data = private.searchServerData(serverName, data, tbl, settings)
|
|
--format raw into displayed data, the cached version is already in this format
|
|
data = private.formatServerData(data, settings)
|
|
end
|
|
|
|
--add item to cache
|
|
if not cached then
|
|
private.addSearchCache(classic or tbl[1], data, serverName, playerName)
|
|
end
|
|
|
|
--If query return
|
|
if queryReturn then --this lets us know it was not an external addon asking for beancounter data
|
|
return data --All results are now returned, calling addons can filter
|
|
end
|
|
|
|
--if BeanCounters frame is not visible then store till we are and cease processing
|
|
if not private.frame:IsVisible() then
|
|
private.storedQuery = id
|
|
return
|
|
end
|
|
|
|
--store profit for this item, need to do this before we reduce number of results for display
|
|
local player = private.frame.SelectBoxSetting[2]
|
|
profit, low, high = lib.API.getAHProfit(player, data)
|
|
|
|
--reduce results to the latest XXXX ammount based on how many user wants displayed
|
|
if #data > count then
|
|
data = private.reduceSize(data, count)
|
|
end
|
|
|
|
style = private.styleServerData(data) --create a style sheet for this data
|
|
|
|
--Adds itemtexture to display box and if possible the gain/loss on the item
|
|
if itemTexture then
|
|
private.frame.icon:SetNormalTexture(itemTexture)
|
|
else
|
|
private.frame.icon:SetNormalTexture(nil)
|
|
end
|
|
|
|
--display profit for the search term
|
|
if profit then
|
|
local change = "|CFF33FF33Gained"
|
|
if profit < 0 then change = "|CFFFF3333Lost" profit = abs(profit) end-- if profit negative ABS to keep tiplib from missrepresenting #
|
|
profit = private.tooltip:Coins(profit)
|
|
private.frame.slot.help:SetTextColor(.8, .5, 1)
|
|
private.frame.slot.help:SetText(change..(" %s from %s to %s"):format(profit or "", date("%x", low) or "", date("%x", high) or ""))
|
|
else
|
|
private.frame.slot.help:SetTextColor(1, 0.8, 0)
|
|
private.frame.slot.help:SetText(_BC('HelpGuiItemBox')) --"Drop item into box to search."
|
|
end
|
|
|
|
private.frame.resultlist.sheet:SetData(data, style) --Set the GUI scrollsheet
|
|
return data, style
|
|
end
|
|
|
|
--Helper functions for the Search
|
|
function private.searchServerData(serverName, data, tbl, settings)
|
|
local server = BeanCounterDB[serverName]
|
|
if not server then return end
|
|
|
|
--Retrives all matching results
|
|
for i in pairs(server) do
|
|
if settings.selectbox[2] == "alliance" and server[i]["faction"] and server[i]["faction"]:lower() ~= settings.selectbox[2] then
|
|
--If looking for alliance and player is not alliance fall into this null
|
|
elseif settings.selectbox[2] == "horde" and server[i]["faction"] and server[i]["faction"]:lower() ~= settings.selectbox[2] then
|
|
--If looking for horde and player is not horde fall into this null
|
|
elseif (settings.selectbox[2] ~= "server" and settings.selectbox[2] ~= "alliance" and settings.selectbox[2] ~= "horde" and settings.selectbox[2] ~= "neutral") and i ~= settings.selectbox[2] then
|
|
--If we are not doing a whole server search and the chosen search player is not "i" then we fall into this null
|
|
--otherwise we search the server or toon as normal
|
|
else
|
|
--flag on how we handle neutral AH nil = no filter 1 = remove neutral AH 2 = remove NON neutral
|
|
local filterNeutral = 1 --by default HIDE neutral trxns
|
|
if settings.neutral then filterNeutral = nil end --GUI check to display neutral trxn over ridden by select box
|
|
if settings.selectbox[2] == "neutral" then filterNeutral = 2 end
|
|
for _, id in pairs(tbl) do
|
|
if settings.auction and server[i]["completedAuctions"][id] and filterNeutral ~= 2 then
|
|
data = private.searchDB(data, server, i, "completedAuctions", id)
|
|
end
|
|
if settings.failedauction and server[i]["failedAuctions"][id] and filterNeutral ~= 2 then
|
|
data = private.searchDB(data, server, i, "failedAuctions", id)
|
|
end
|
|
if settings.bid and server[i]["completedBidsBuyouts"][id] and filterNeutral ~= 2 then
|
|
data = private.searchDB(data, server, i, "completedBidsBuyouts", id)
|
|
end
|
|
if settings.failedbid and server[i]["failedBids"][id] and filterNeutral ~= 2 then
|
|
data = private.searchDB(data, server, i, "failedBids", id)
|
|
end
|
|
--neutral AH handling
|
|
if settings.auction and server[i]["completedAuctionsNeutral"][id] and filterNeutral ~= 1 then
|
|
data = private.searchDB(data, server, i, "completedAuctionsNeutral", id)
|
|
end
|
|
if settings.failedauction and server[i]["failedAuctionsNeutral"][id] and filterNeutral ~= 1 then
|
|
data = private.searchDB(data, server, i, "failedAuctionsNeutral", id)
|
|
end
|
|
if settings.bid and server[i]["completedBidsBuyoutsNeutral"][id] and filterNeutral ~= 1 then
|
|
data = private.searchDB(data, server, i, "completedBidsBuyoutsNeutral", id)
|
|
end
|
|
if settings.failedbid and server[i]["failedBidsNeutral"][id] and filterNeutral ~= 1 then
|
|
data = private.searchDB(data, server, i, "failedBidsNeutral", id)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return data
|
|
end
|
|
function private.searchDB(data, server, player, DB, itemID)
|
|
for index, itemKey in pairs(server[player][DB][itemID]) do
|
|
DB = DB:gsub("Neutral", "")--remove the Neutral part so we send it to the proper function
|
|
for _, text in ipairs(itemKey) do
|
|
tinsert(data, {DB:upper(), itemID, index, text})
|
|
end
|
|
end
|
|
return data
|
|
end
|
|
|
|
function private.formatServerData(data, settings)
|
|
local formatedData = {}
|
|
--Format Data for display via scroll private.frame
|
|
for i,v in pairs(data) do
|
|
local match = true
|
|
--to provide exact match filtering for of the tems we compare names to the itemKey on API searches
|
|
if settings.exact and settings.suffix then
|
|
local _, suffix = lib.API.decodeLink(v[3])
|
|
if suffix == settings.suffix then
|
|
-- do nothing and add item to data table
|
|
else
|
|
match = false --we want exact matches and this is not one
|
|
end
|
|
end
|
|
if match and v[1] then
|
|
local database = v[1]
|
|
--just a wrapper to call the correct function for the database we are wanting to format. Example function private.FAILEDBIDS(...) == private["FAILEDBIDS"](...)
|
|
local store = private[database]
|
|
local entry = store(v[2], v[3], v[4], settings)
|
|
tinsert(formatedData, entry)
|
|
end
|
|
end
|
|
|
|
return formatedData
|
|
end
|
|
--take collected data and format
|
|
local function styleColors(database) --helper takes formated data table and looks to what colors we use for style
|
|
-- style colors for the various databases
|
|
if database == _BC('UiAucSuccessful') then
|
|
return 0.3, 0.9, 0.8
|
|
elseif database == _BC('UiAucExpired') then
|
|
return 1, 0, 0
|
|
elseif database == _BC('UiWononBuyout') or database == _BC('UiWononBid') then
|
|
return 1, 1, 0
|
|
elseif database == _BC('UiOutbid') then
|
|
return 1, 1, 1
|
|
else --return default
|
|
return 1, .5, .1
|
|
end
|
|
end
|
|
function private.styleServerData(data)
|
|
--create style data for entries that are going to be displayed, created seperatly to allow us to reduce the data table entries
|
|
local dateString = get("dateString") or "%c"
|
|
for i,v in pairs(data) do
|
|
local database = v[2]
|
|
local r, g, b = styleColors(database)
|
|
style[i] = {}
|
|
if get("colorizeSearch") then style[i][1] = {["rowColor"] = {r, g, b, 0, get("colorizeSearchopacity") or 0, "Horizontal"}} end
|
|
style[i][12] = {["date"] = dateString}
|
|
style[i][2] = {["textColor"] = {r, g, b}}
|
|
style[i][8] ={["textColor"] = {r, g, b}}
|
|
end
|
|
return style
|
|
end
|
|
|
|
function private.reduceSize(tbl, count)
|
|
--The data provided is from multiple toons tables, so we need to resort the merged data back into sequential time order
|
|
table.sort(tbl, function(a, b)
|
|
return a[12] > b[12]
|
|
end)
|
|
local data = {} -- this will be a new table, this prevents chages from being propagated back to the cached "data" refrence
|
|
for i = 1, count do
|
|
tinsert(data, tbl[i])
|
|
end
|
|
return data
|
|
end
|
|
|
|
--To simplify having two seperate search routines, the Data creation of each table has been made a local function
|
|
function private.COMPLETEDAUCTIONS(id, itemKey, text)
|
|
local uStack, uMoney, uDeposit , uFee, uBuyout , uBid, uSeller, uTime, uReason, uMeta = private.unpackString(text)
|
|
if uSeller == "0" then uSeller = "..." end
|
|
if uReason == "0" then uReason = "..." end
|
|
|
|
local pricePer = 0
|
|
local stack = tonumber(uStack) or 0
|
|
local profit = (uMoney - uDeposit + uFee)
|
|
if stack > 0 then pricePer = profit/stack end
|
|
|
|
local itemID, suffix, uniqueID = lib.API.decodeLink(itemKey)
|
|
local itemLink = lib.API.createItemLinkFromArray(itemID..":"..suffix, uniqueID)
|
|
|
|
if not itemLink then itemLink = private.getItemInfo(id, "name") end--if not in our DB ask the server
|
|
|
|
return {
|
|
itemLink or "Failed to get Link", --itemname
|
|
_BC('UiAucSuccessful'), --status
|
|
|
|
tonumber(uBid) or 0, --bid
|
|
tonumber(uBuyout) or 0, --buyout
|
|
tonumber(uMoney), --Net
|
|
tonumber(stack), --stacksize
|
|
tonumber(pricePer), --Profit/per
|
|
|
|
uSeller, --seller/seller
|
|
|
|
tonumber(uDeposit), --deposit
|
|
tonumber(uFee), --fee
|
|
uReason, --reason bought
|
|
tonumber(uTime), --time, --Make this a user choosable option.
|
|
tonumber(profit), --Profit
|
|
uMeta or "",
|
|
}
|
|
end
|
|
--STACK; BUY; BID; DEPOSIT; TIME; DATE; WEALTH
|
|
function private.FAILEDAUCTIONS(id, itemKey, text)
|
|
local uStack, uMoney, uDeposit , uFee, uBuyout , uBid, uSeller, uTime, uReason, uMeta = private.unpackString(text)
|
|
if uSeller == "0" then uSeller = "..." end
|
|
if uReason == "0" then uReason = "..." end
|
|
local status =_BC('UiAucExpired')
|
|
if uReason == _BC('Cancelled') then status = _BC('UiAucCancelled') end --if its a cancel rather than true expired auction
|
|
|
|
local itemID, suffix, uniqueID = lib.API.decodeLink(itemKey)
|
|
local itemLink = lib.API.createItemLinkFromArray(itemID..":"..suffix, uniqueID)
|
|
if not itemLink then itemLink = private.getItemInfo(id, "name") end--if not in our DB ask the server
|
|
|
|
return {
|
|
itemLink, --itemname
|
|
status,
|
|
|
|
tonumber(uBid) or 0, --bid
|
|
tonumber(uBuyout) or 0, --buyout
|
|
0, --money,
|
|
tonumber(uStack) or 0,
|
|
0, --Profit/per
|
|
|
|
uSeller, --seller/buyer
|
|
|
|
tonumber(uDeposit) or 0, --deposit
|
|
0, --fee
|
|
uReason, --reason bought
|
|
tonumber(uTime), --time, --Make this a user choosable option.
|
|
0, --Profit
|
|
uMeta or "",
|
|
}
|
|
end
|
|
function private.COMPLETEDBIDSBUYOUTS(id, itemKey, text)
|
|
--local value = "stack"], "money"], p"fee"], buyout"], "bid"], p"Seller/buyer"], ["time"], reason)
|
|
|
|
local uStack, uMoney, uDeposit , uFee, uBuyout , uBid, uSeller, uTime, uReason, uMeta = private.unpackString(text)
|
|
if uSeller == "0" then uSeller = "..." end
|
|
if uReason == "0" then uReason = "..." end
|
|
|
|
local pricePer, stack, text = 0, tonumber(uStack), _BC('UiWononBuyout')
|
|
local profit
|
|
--If the auction was won on bid change text, and adjust ProfitPer
|
|
if uBuyout ~= uBid then
|
|
text = _BC('UiWononBid')
|
|
profit = (uBid - uMoney + uFee)
|
|
if stack > 0 then pricePer = profit/stack end
|
|
else --Devide by BUY price if it was won on Buy
|
|
profit = (uBuyout - uMoney + uFee)
|
|
if stack > 0 then pricePer = profit/stack end
|
|
end
|
|
|
|
--replace reason with DE info
|
|
if not uMeta then uMeta = "" end
|
|
local mat, count, value = uMeta:match("DE:(%d-):(%d-):(%d-)|")
|
|
if mat and count and value then
|
|
local _, link = GetItemInfo(mat)
|
|
if link then
|
|
uReason = link.." X "..count
|
|
--change the profit to be the diff between bought and what we DE into
|
|
profit = count*value - profit
|
|
end
|
|
end
|
|
|
|
local itemID, suffix, uniqueID = lib.API.decodeLink(itemKey)
|
|
local itemLink = lib.API.createItemLinkFromArray(itemID..":"..suffix, uniqueID)
|
|
if not itemLink then itemLink = private.getItemInfo(id, "name") end--if not in our DB ask the server
|
|
|
|
return {
|
|
itemLink, --itemname
|
|
text, --status
|
|
|
|
tonumber(uBid), --bid
|
|
tonumber(uBuyout), --buyout
|
|
0, --money,
|
|
tonumber(stack), --stacksize
|
|
tonumber(pricePer), --Profit/per
|
|
|
|
uSeller, --seller/buyer
|
|
|
|
tonumber(uDeposit), --deposit
|
|
tonumber(uFee), --fee
|
|
uReason, --reason bought
|
|
tonumber(uTime), --time, --Make this a user choosable option.
|
|
tonumber(profit), --Profit/per
|
|
uMeta,
|
|
}
|
|
end
|
|
function private.FAILEDBIDS(id, itemKey, text)
|
|
|
|
local uStack, uMoney, uDeposit , uFee, uBuyout , uBid, uSeller, uTime, uReason, uMeta = private.unpackString(text)
|
|
if uSeller == "0" then uSeller = "..." end
|
|
if uReason == "0" then uReason = "..." end
|
|
|
|
local itemID, suffix, uniqueID = lib.API.decodeLink(itemKey)
|
|
local itemLink = lib.API.createItemLinkFromArray(itemID..":"..suffix, uniqueID)
|
|
if not itemLink then itemLink = private.getItemInfo(id, "name") end--if not in our DB ask the server
|
|
|
|
return {
|
|
itemLink, --itemname
|
|
_BC('UiOutbid'), --status
|
|
|
|
tonumber(uBid), --bid
|
|
0, --buyout
|
|
tonumber(uMoney), --money,
|
|
tonumber(uStack), --stack
|
|
0, --Profit/per
|
|
|
|
uSeller, --seller/buyer
|
|
|
|
tonumber(uDeposit), --deposit
|
|
tonumber(uFee), --fee
|
|
uReason, --reason bought
|
|
tonumber(uTime), --time, --Make this a user choosable option.
|
|
0, --Profit/per
|
|
uMeta or "",
|
|
}
|
|
end
|