Quantcast

major rewrite of scanning and item handling

ckaotik [05-20-10 - 20:39]
major rewrite of scanning and item handling
Filename
Broker_Garbage.toc
Locale/deDE.lua
Locale/enUS.lua
constants.lua
core.lua
helper.lua
options.lua
diff --git a/Broker_Garbage.toc b/Broker_Garbage.toc
index 92d9652..6190a89 100644
--- a/Broker_Garbage.toc
+++ b/Broker_Garbage.toc
@@ -14,7 +14,7 @@
 ## X-Embeds: LibPeriodicTable-3.1
 ## X-Category: Inventory
 ## X-Localizations: enUS, deDE. Works in any language. You can help!
-## X-Credits: GarbageFu(Jaerin/wmrojer), tekKonfig(Tekkub)
+## X-Credits: GarbageFu(Jaerin/wmrojer), tekKonfig(Tekkub), Mirroar (<3)
 ## X-License: GNU GPLv2

 # libraries
diff --git a/Locale/deDE.lua b/Locale/deDE.lua
index cf957fe..5e3fdb5 100644
--- a/Locale/deDE.lua
+++ b/Locale/deDE.lua
@@ -183,7 +183,7 @@ if GetLocale() == "deDE" then
 		"Shift-Klicke, um die globale Einschlussliste zu leeren"

 	BrokerGarbage.locale.LONIncludeAutoSellText = "Automatisch Items der Einschlussliste verkaufen"
-	BrokerGarbage.locale.LONIncludeAutoSellTooltip = "Aktivieren, um Items von deiner Einschlussliste beim Händler zu verkaufen; wenn aktiv hat die Verkaufsliste keinerlei Einfluss.\nItems ohne Wert werden ignoriert."
+	BrokerGarbage.locale.LONIncludeAutoSellTooltip = "Aktivieren, um Items von deiner Einschlussliste beim Händler zu verkaufen.\nItems ohne Wert werden ignoriert."

 		-- Auto Sell List
 	BrokerGarbage.locale.LONAutoSellHeader = "Verkaufsliste - Items hier werden bei Händlern automatisch verkauft."
diff --git a/Locale/enUS.lua b/Locale/enUS.lua
index 28c9eb1..3de3351 100644
--- a/Locale/enUS.lua
+++ b/Locale/enUS.lua
@@ -131,7 +131,7 @@ BrokerGarbage.locale = {
 	defaultListsTooltip = "Click to manually create default local list entries. Right-Click to also create default global lists.",

 	DKTitle = "Temp. disable key",
-	DKTooltip = "Set a key to disable BrokerGarbage temporarily.",
+	DKTooltip = "Set a key to temporarily disable BrokerGarbage.",
 	disableKeys = {
 		["None"] = "None",
 		["SHIFT"] = "SHIFT",
@@ -185,7 +185,7 @@ BrokerGarbage.locale = {
 		"SHIFT-Click to empty your global Include List.",

 	LONIncludeAutoSellText = "Automatically sell include list items",
-	LONIncludeAutoSellTooltip = "Check this to sell items on your include list when at a merchant; using the AutoSell list has no effect then.\nItems without a value will be ignored.",
+	LONIncludeAutoSellTooltip = "Check this to sell items on your include list when at a merchant.\nItems without a value will be ignored.",

 		-- Auto Sell List
 	LONAutoSellHeader = "Sell List - These items will be sold automatically when at a vendor.",
diff --git a/constants.lua b/constants.lua
index 649d5c0..84f9852 100644
--- a/constants.lua
+++ b/constants.lua
@@ -2,7 +2,7 @@ _, BrokerGarbage = ...

 -- default saved variables
 BrokerGarbage.defaultGlobalSettings = {
-	-- lists :: key is either the itemID -or- the PeriodicTable category string
+	-- lists :: key is either the itemID -or- the PeriodicTable category string, value is true -or- limit number
 	exclude = {},
 	include = {},
 	autoSellList = {},
@@ -12,6 +12,7 @@ BrokerGarbage.defaultGlobalSettings = {
 	autoSellToVendor = true,
 	autoRepairAtVendor = true,
 	disableKey = "SHIFT",
+	hideZeroValue = true,
 	sellNotWearable = false,
 	sellNWQualityTreshold = 4,
 	autoSellIncludeItems = false,
@@ -53,22 +54,37 @@ BrokerGarbage.defaultLocalSettings = {
 	moneyEarned = 0,
 }

-BrokerGarbage.tagAuction	= "|cFF2bff58A"		-- green
-BrokerGarbage.tagVendor		= "|cFFff9c5aV"		-- orange
-BrokerGarbage.tagVendorList	= "|cFFff592dV"		-- slightly darker orange
-BrokerGarbage.tagDisenchant	= "|cFFe052ffD"		-- purple
-BrokerGarbage.tagInclude	= "|cFFffffffI"		-- white
-BrokerGarbage.tagUnusableGear	= "|cFF3c73abG"		-- blue
+-- item classification
+BrokerGarbage.EXCLUDE = 0		-- item is excluded. Nothing happened...
+BrokerGarbage.INCLUDE = 1		-- item is on include list
+BrokerGarbage.LIMITED = 2		-- item is on include list, but has a limit value
+BrokerGarbage.UNUSABLE = 3		-- item is gear but not usable
+
+BrokerGarbage.AUCTION = 4		-- auction price is highest value
+BrokerGarbage.VENDOR = 5		-- vendor price is highest value
+BrokerGarbage.VENDORLIST = 6	-- item is on sell list
+BrokerGarbage.DISENCHANT = 7	-- disenchant price is highest value
+
+-- corresponding tags to be used in the LDB tooltip
+BrokerGarbage.tag = {
+	[BrokerGarbage.INCLUDE] 	= "|cFFffffffI",	-- white
+	[BrokerGarbage.LIMITED] 	= "|cFFffffffL",	-- white
+	[BrokerGarbage.UNUSABLE] 	= "|cFF3c73abG",	-- blue
+	[BrokerGarbage.AUCTION] 	= "|cFF2bff58A",	-- green
+	[BrokerGarbage.VENDOR] 		= "|cFFff9c5aV",	-- orange
+	[BrokerGarbage.VENDORLIST] 	= "|cFFff592dV",	-- dark orange
+	[BrokerGarbage.DISENCHANT] 	= "|cFFe052ffD",	-- purple
+}

 BrokerGarbage.clams = {15874, 5523, 5524, 7973, 24476, 36781, 45909}
 BrokerGarbage.playerClass = select(2,UnitClass("player"))
 BrokerGarbage.enchanting = select(1,GetSpellInfo(7411))

 BrokerGarbage.disableKey = {
-	["None"] = function() return false end,
-	["SHIFT"] = IsShiftKeyDown,
-	["ALT"] = IsAltKeyDown,
-	["CTRL"] = IsControlKeyDown,
+	["None"] 	= function() return false end,
+	["SHIFT"] 	= IsShiftKeyDown,
+	["ALT"] 	= IsAltKeyDown,
+	["CTRL"] 	= IsControlKeyDown,
 }

 -- rarity strings (no need to localize)
diff --git a/core.lua b/core.lua
index 4907976..d3c050a 100644
--- a/core.lua
+++ b/core.lua
@@ -13,36 +13,58 @@ local LDB = LibStub("LibDataBroker-1.1"):NewDataObject("Broker_Garbage", {
 	type	= "data source",
 	icon	= "Interface\\Icons\\achievement_bg_returnxflags_def_wsg",
 	label	= "Garbage",
-	text 	= "Text",		-- this is a placeholder until the first scan BrokerGarbage.locale.label
+	text 	= "",

 	OnClick = function(...) BrokerGarbage:OnClick(...) end,
 	OnEnter = function(...) BrokerGarbage:Tooltip(...) end,
 })

---LDB.OnClick = function(...) BrokerGarbage:OnClick(...) end
---LDB.OnEnter = function(...) BrokerGarbage:Tooltip(...) end
+local function UpdateLDB()
+	local cheapestItems = BrokerGarbage:GetCheapest()
+	BrokerGarbage.totalBagSpace, BrokerGarbage.totalFreeSlots = BrokerGarbage:GetBagSlots()	-- TODO: maybe reduce to only the relevant bag
+
+	if cheapestItems[1] then
+		BrokerGarbage.cheapestItem = cheapestItems[1]
+		LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBformat)
+	else
+		BrokerGarbage.cheapestItem = nil
+		LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBNoJunk)
+	end
+end

 -- internal locals
-local locked = false
-local sellValue = 0		-- represents the actual value that we sold stuff for, opposed to BrokerGarbage.toSellValue which shows the maximum we could sell - imagine someone closing the merchant window. sellValue will then hold the real value we're interested in
-local cost = 0
-
-local lastReminder = time()
-
-BrokerGarbage.isAtVendor = false
-BrokerGarbage.optionsModules = {}
+-- local lastReminder = time()
+BrokerGarbage.optionsModules = {}	-- used for ordering/showing entries in the options panel
+local locked = false				-- set to true while selling stuff
+local sellValue = 0					-- represents the actual value that we sold stuff for
+local cost = 0						-- the amount of money that we repaired for

 -- Event Handler
 -- ---------------------------------------------------------
 local function eventHandler(self, event, ...)
-	if event == "ADDON_LOADED" then
-		if arg1 == "Broker_Garbage" then
-			BrokerGarbage:CheckSettings()
-		end
+	if event == "PLAYER_ENTERING_WORLD" then
+		BrokerGarbage:CheckSettings()
+
+		-- some default values initialization
+		BrokerGarbage.isAtVendor = false
+		BrokerGarbage.toSellValue = {}		-- value to show on sell icon
+		BrokerGarbage.totalBagSpace = 0
+		BrokerGarbage.totalFreeSlots = 0
+
+		-- inventory database
+		BrokerGarbage.itemsCache = {}
+		BrokerGarbage.clamInInventory = false
+		BrokerGarbage.containerInInventory = false
+
+		-- full inventory scan to start with
+		BrokerGarbage:ScanInventory()

 	elseif event == "BAG_UPDATE" then
+		if arg1 < 0 or arg1 > 4 then return end
+
+		BrokerGarbage:ScanInventoryContainer(arg1)	-- partial inventory scan
 		if not locked then
-			BrokerGarbage:ScanInventory()
+			UpdateLDB()
 		end

 	elseif event == "MERCHANT_SHOW" then
@@ -57,16 +79,17 @@ local function eventHandler(self, event, ...)
 		-- fallback unlock
 		cost = 0
 		sellValue = 0
-		BrokerGarbage.toSellValue = 0
 		BrokerGarbage.isAtVendor = false
 		locked = false
-		BrokerGarbage:Debug("lock released")
-
-		BrokerGarbage:ScanInventory()
+		BrokerGarbage:Debug("Fallback Unlock: Merchant window closed, scan lock released.")
+		UpdateLDB()
+
+	elseif event == "AUCTION_HOUSE_CLOSED" then
+		-- Update cache auction values if needed
+		BrokerGarbage.itemsCache = {}

 	elseif (locked or cost ~=0) and event == "PLAYER_MONEY" then
 		-- regular unlock
-
 		-- wrong player_money event (resulting from repair, not sell)
 		if sellValue ~= 0 and cost ~= 0 and ((-1)*sellValue <= cost+2 and (-1)*sellValue >= cost-2) then
 			BrokerGarbage:Debug("Not yet ... Waiting for actual money change.")
@@ -92,23 +115,21 @@ local function eventHandler(self, event, ...)
 		end

 		sellValue = 0
-		BrokerGarbage.toSellValue = 0
 		cost = 0
 		locked = false
-		BrokerGarbage:Debug("lock released")
-
-		BrokerGarbage:ScanInventory()
-
+		BrokerGarbage:Debug("Regular Unlock: Money received, scan lock released.")
+		UpdateLDB()
 	end
 end

 -- register events
 local frame = CreateFrame("frame")

-frame:RegisterEvent("ADDON_LOADED")
+frame:RegisterEvent("PLAYER_ENTERING_WORLD")
 frame:RegisterEvent("BAG_UPDATE")
 frame:RegisterEvent("MERCHANT_SHOW")
 frame:RegisterEvent("MERCHANT_CLOSED")
+frame:RegisterEvent("AUCTION_HOUSE_CLOSED")
 frame:RegisterEvent("PLAYER_MONEY")

 frame:SetScript("OnEvent", eventHandler)
@@ -127,6 +148,10 @@ function BrokerGarbage:UpdateRepairButton(...)
 		return
 	end

+	local junkValue = 0
+	for i = 0, 4 do
+		junkValue = junkValue + BrokerGarbage.toSellValue[i]
+	end
 	local iconbutton
 	-- show auto-sell icon on vendor frame
 	if not _G["BrokerGarbage_SellIcon"] then
@@ -138,8 +163,12 @@ function BrokerGarbage:UpdateRepairButton(...)
 		iconbutton:SetScript("OnEnter", function(self)
 			GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
 			local tiptext
-			if BrokerGarbage.toSellValue and BrokerGarbage.toSellValue ~= 0 then
-				tiptext = format(BrokerGarbage.locale.autoSellTooltip, BrokerGarbage:FormatMoney(BrokerGarbage.toSellValue))
+			local junkValue = 0
+			for i = 0, 4 do
+				junkValue = junkValue + BrokerGarbage.toSellValue[i]
+			end
+			if junkValue ~= 0 then
+				tiptext = format(BrokerGarbage.locale.autoSellTooltip, BrokerGarbage:FormatMoney(junkValue))
 			else
 				tiptext = BrokerGarbage.locale.reportNothingToSell
 			end
@@ -169,7 +198,7 @@ function BrokerGarbage:UpdateRepairButton(...)
 	end
 	MerchantRepairText:Hide()

-	if BrokerGarbage.toSellValue and BrokerGarbage.toSellValue ~= 0 then
+	if junkValue ~= 0 then
 		_G["BrokerGarbage_SellIcon"]:GetNormalTexture():SetDesaturated(false)
 	else
 		_G["BrokerGarbage_SellIcon"]:GetNormalTexture():SetDesaturated(true)
@@ -180,10 +209,13 @@ hooksecurefunc("MerchantFrame_UpdateRepairButtons", BrokerGarbage.UpdateRepairBu
 -- Tooltip
 -- ---------------------------------------------------------
 function BrokerGarbage:Tooltip(self)
+	local colNum, lineNum
 	if BG_GlobalDB.showSource then
 		BrokerGarbage.tt = LibStub("LibQTip-1.0"):Acquire("BrokerGarbage_TT", 4, "LEFT", "RIGHT", "RIGHT", "CENTER")
+		colNum = 4
 	else
 		BrokerGarbage.tt = LibStub("LibQTip-1.0"):Acquire("BrokerGarbage_TT", 3, "LEFT", "RIGHT", "RIGHT")
+		colNum = 3
 	end
 	BrokerGarbage.tt:Clear()

@@ -204,24 +236,39 @@ function BrokerGarbage:Tooltip(self)
 	BrokerGarbage.tt:SetFont(tooltipFont)
 	BrokerGarbage.tt:AddLine(BrokerGarbage.locale.headerShiftClick, '', BrokerGarbage.locale.headerCtrlClick)
 	BrokerGarbage.tt:AddSeparator(2)
-
+
+	-- add clam information
+	if IsAddOnLoaded("Broker_Garbage-LootManager") and (
+		(BGLM_GlobalDB.openContainers and BrokerGarbage.containerInInventory) or
+		(BGLM_GlobalDB.openClams and BrokerGarbage.clamInInventory)) then
+
+		if BGLM_GlobalDB.openContainers and BrokerGarbage.containerInInventory then
+			lineNum = BrokerGarbage.tt:AddLine()
+			BrokerGarbage.tt:SetCell(lineNum, 1, BrokerGarbage_LootManager.locale.openPlease, tooltipFont, "CENTER", colNum)
+		end
+		if BGLM_GlobalDB.openClams and BrokerGarbage.clamInInventory then
+			lineNum = BrokerGarbage.tt:AddLine()
+			BrokerGarbage.tt:SetCell(lineNum, 1, BrokerGarbage_LootManager.locale.openClams, tooltipFont, "CENTER", colNum)
+		end
+		BrokerGarbage.tt:AddSeparator(2)
+	end
+
 	-- shows up to n lines of deletable items
-	local lineNum
 	local cheapList = BrokerGarbage:GetCheapest(BG_GlobalDB.tooltipNumItems)
-	for i = 1, #cheapList do
+	for i = 1, #cheapList do
 		-- adds lines: itemLink, count, itemPrice, source
 		lineNum = BrokerGarbage.tt:AddLine(
 			select(2,GetItemInfo(cheapList[i].itemID)),
 			cheapList[i].count,
 			BrokerGarbage:FormatMoney(cheapList[i].value),
-			(BG_GlobalDB.showSource and cheapList[i].source or nil))
+			(BG_GlobalDB.showSource and BrokerGarbage.tag[cheapList[i].source] or nil))
 		BrokerGarbage.tt:SetLineScript(lineNum, "OnMouseDown", BrokerGarbage.OnClick, cheapList[i])
 	end
 	if lineNum == nil then
 		BrokerGarbage.tt:AddLine(BrokerGarbage.locale.noItems, '', BrokerGarbage.locale.increaseTreshold)
 	end

-	-- add useful(?) information
+	-- add statistics information
 	if (BG_GlobalDB.showLost and BG_LocalDB.moneyLostByDeleting ~= 0)
 		or (BG_GlobalDB.showEarned and BG_LocalDB.moneyEarned ~= 0) then
 		BrokerGarbage.tt:AddSeparator(2)
@@ -243,34 +290,34 @@ function BrokerGarbage:Tooltip(self)
 	BrokerGarbage.tt:UpdateScrolling(BG_GlobalDB.tooltipMaxHeight)
 end

--- onClick function for when you ... click. works for both, the LDB plugin -and- tooltip lines
+-- onClick function - works for both, the LDB plugin -and- tooltip lines
 function BrokerGarbage:OnClick(itemTable, button)
 	-- handle LDB clicks seperately
+	local LDBclick = false
 	if not itemTable.itemID or type(itemTable.itemID) ~= "number" then
-		BrokerGarbage:Debug("No itemTable for OnClick, using cheapest item")
+		BrokerGarbage:Debug("Click on LDB")
 		itemTable = BrokerGarbage.cheapestItem
+		LDBclick = true
 	end

 	-- handle different clicks
 	if itemTable and IsShiftKeyDown() then
 		-- delete or sell item, depending on if we're at a vendor or not
-		BrokerGarbage:Debug("SHIFT-Click!")
 		if BrokerGarbage.isAtVendor and itemTable.value > 0 then
-			BrokerGarbage:Debug("@Vendor", "Selling")
-			BG_GlobalDB.moneyEarned = BG_GlobalDB.moneyEarned + itemTable.value
-			BG_LocalDB.moneyEarned = BG_LocalDB.moneyEarned + itemTable.value
-			BG_GlobalDB.itemsSold = BG_GlobalDB.itemsSold + itemTable.count
+			BrokerGarbage:Debug("At vendor, selling "..itemTable.itemID)
+			BG_GlobalDB.moneyEarned	= BG_GlobalDB.moneyEarned + itemTable.value
+			BG_LocalDB.moneyEarned 	= BG_LocalDB.moneyEarned + itemTable.value
+			BG_GlobalDB.itemsSold 	= BG_GlobalDB.itemsSold + itemTable.count

 			ClearCursor()
 			UseContainerItem(itemTable.bag, itemTable.slot)
 		else
-			BrokerGarbage:Debug("Not @Vendor", "Deleting")
+			BrokerGarbage:Debug("Not at vendor", "Deleting")
 			BrokerGarbage:Delete(itemTable)
 		end

 	--[[elseif itemTable and IsAltKeyDown() and IsControlKeyDown() then
 		-- disenchant
-		BrokerGarbage:Debug("CTRL+ALT-Click!")
 		local itemLink = select(2, GetItemInfo(itemTable.itemID))
 		if BrokerGarbage:CanDisenchant(itemLink, true) then
 			-- Disenchant: 13262
@@ -278,11 +325,11 @@ function BrokerGarbage:OnClick(itemTable, button)

 	elseif itemTable and IsControlKeyDown() then
 		-- add to exclude list
-		BrokerGarbage:Debug("CTRL-Click!")
 		if not BG_LocalDB.exclude[itemTable.itemID] then
 			BG_LocalDB.exclude[itemTable.itemID] = true
 		end
 		BrokerGarbage:Print(format(BrokerGarbage.locale.addedToSaveList, select(2,GetItemInfo(itemTable.itemID))))
+		BrokerGarbage.itemsCache = {}

 		if BrokerGarbage.optionsLoaded then
 			BrokerGarbage:ListOptionsUpdate("exclude")
@@ -290,79 +337,103 @@ function BrokerGarbage:OnClick(itemTable, button)

 	elseif itemTable and IsAltKeyDown() then
 		-- add to force vendor price list
-		BrokerGarbage:Debug("ALT-Click!")
 		BG_GlobalDB.forceVendorPrice[itemTable.itemID] = true
 		BrokerGarbage:Print(format(BrokerGarbage.locale.addedToPriceList, select(2,GetItemInfo(itemTable.itemID))))
+		BrokerGarbage.itemsCache = {}

 		if BrokerGarbage.optionsLoaded then
 			BrokerGarbage:ListOptionsUpdate("forceprice")
 		end
-		BrokerGarbage:ScanInventory()

 	elseif button == "RightButton" then
 		-- open config
 		BrokerGarbage:OptionsFirstLoad()
 		InterfaceOptionsFrame_OpenToCategory(BrokerGarbage.options)

-	else
-		-- do nothing
+	elseif LDBclick then
+		-- click on the LDB to rescan
+		BrokerGarbage:ScanInventory()
 	end

-	BrokerGarbage:ScanInventory()
+	BrokerGarbage.debugItemTable = itemTable
 end

 -- Item Value Calculation
 -- ---------------------------------------------------------
 -- calculates the value of a stack/partial stack of an item
-function BrokerGarbage:GetItemValue(itemLink, count)
-	if not itemLink then return nil, nil end
-	local itemID = BrokerGarbage:GetItemID(itemLink)
-	local DE = BrokerGarbage:CanDisenchant(itemLink)
-	local itemQuality = select(3,GetItemInfo(itemLink))
-	local vendorPrice = select(11,GetItemInfo(itemLink))
-	local auctionPrice, disenchantPrice, source
+function BrokerGarbage:GetItemValue(item, count)
+	local itemID
+	if item and type(item) == "number" then
+		itemID = item
+
+	elseif item and type(item) == "string" then
+		itemID = BrokerGarbage:GetItemID(item)
+
+	else
+		-- invalid argument
+		BrokerGarbage:Debug("GetItemValue: Invalid argument "..(item or "<none>").."supplied.")
+		return nil
+	end

-	if vendorPrice == 0 then vendorPrice = nil end
-	if not count then
-		count = GetItemCount(itemLink, false, false)
-		if count == 0 then count = 1 end
+	return BrokerGarbage:GetCached(itemID).value * count
+end
+
+-- returns which of the items values is the highest (value, type)
+function BrokerGarbage:GetSingleItemValue(item)
+	local itemID, itemLink
+	if item and type(item) == "number" then
+		itemID = item
+		itemLink = select(2, GetItemInfo(itemID))
+
+	elseif item and type(item) == "string" then
+		itemID = BrokerGarbage:GetItemID(item)
+		itemLink = item
+
+	else
+		-- invalid argument
+		BrokerGarbage:Debug("GetSingleItemValue: Invalid argument "..(item or "<none>").."supplied.")
+		return nil
 	end

+	local canDE = BrokerGarbage:CanDisenchant(itemLink)
+	local _, _, itemQuality, _, _, _, _, _, _, _, vendorPrice = GetItemInfo(itemID)
+	local auctionPrice, disenchantPrice, source
+
 	-- gray items on the AH?
 	if itemQuality == 0 then
-		return vendorPrice and vendorPrice*count or nil, BrokerGarbage.tagVendor
+		return vendorPrice, BrokerGarbage.VENDOR
 	end

 	-- calculate auction value
 	if IsAddOnLoaded("Auctionator") then
 		BrokerGarbage.auctionAddon = "Auctionator"
 		auctionPrice = Atr_GetAuctionBuyout(itemLink)
-		disenchantPrice = DE and Atr_GetDisenchantValue(itemLink)
+		disenchantPrice = canDE and Atr_GetDisenchantValue(itemLink)

 	elseif IsAddOnLoaded("AuctionLite") then
 		BrokerGarbage.auctionAddon = "AuctionLite"
 		auctionPrice = AuctionLite:GetAuctionValue(itemLink)
-		disenchantPrice = DE and AuctionLite:GetDisenchantValue(itemLink)
+		disenchantPrice = canDE and AuctionLite:GetDisenchantValue(itemLink)

 	elseif IsAddOnLoaded("WOWEcon_PriceMod") then
 		BrokerGarbage.auctionAddon = "WoWecon"
 		auctionPrice = Wowecon.API.GetAuctionPrice_ByLink(itemLink)

-		if DE then
+		if canDE then
 			disenchantPrice = 0
 			local DEData = Wowecon.API.GetDisenchant_ByLink(itemLink)
 			for i,data in pairs(DEData) do
 				-- data[1] = itemLink, data[2] = quantity, data[3] = chance
 				disenchantPrice = disenchantPrice + (Wowecon.API.GetAuctionPrice_ByLink(data[1]) * data[2] * data[3])
 			end
-			disenchantPrice = DE and math.floor(disenchantPrice)
+			disenchantPrice = canDE and math.floor(disenchantPrice)
 		end

 	elseif IsAddOnLoaded("Auc-Advanced") then
 		BrokerGarbage.auctionAddon = "Auc-Advanced"
 		auctionPrice = AucAdvanced.API.GetMarketValue(itemLink)

-		if DE and IsAddOnLoaded("Enchantrix") then
+		if canDE and IsAddOnLoaded("Enchantrix") then
 			disenchantPrice = 0
 			local itemType
 			local weaponString, armorString = GetAuctionItemClasses()
@@ -400,50 +471,54 @@ function BrokerGarbage:GetItemValue(itemLink, count)
 	else
 		BrokerGarbage.auctionAddon = "Unknown/None"
 		auctionPrice = GetAuctionBuyout and GetAuctionBuyout(itemLink) or nil
-		disenchantPrice = DE and GetDisenchantValue and GetDisenchantValue(itemLink) or nil
-
+		disenchantPrice = canDE and GetDisenchantValue and GetDisenchantValue(itemLink) or nil
 	end

 	local maximum = math.max((disenchantPrice or 0), (auctionPrice or 0), (vendorPrice or 0))
 	if vendorPrice and maximum == vendorPrice then
-		return vendorPrice*count, BrokerGarbage.tagVendor
+		return vendorPrice, BrokerGarbage.VENDOR

 	elseif auctionPrice and maximum == auctionPrice then
-		return auctionPrice*count, BrokerGarbage.tagAuction
+		return auctionPrice, BrokerGarbage.AUCTION

 	elseif disenchantPrice and maximum == disenchantPrice then
-		return disenchantPrice, BrokerGarbage.tagDisenchant
+		return disenchantPrice, BrokerGarbage.DISENCHANT

 	else
 		return nil, nil
 	end
 end

--- finds all occurences of the given item and returns the best location to delete from
+-- finds all occurences of the given item and returns the least important location
 function BrokerGarbage:FindSlotToDelete(itemID, ignoreFullStack)
 	local locations = {}
-	local maxStack = select(8, GetItemInfo(itemID))
+	local _, _, _, _, _, _, _, maxStack = GetItemInfo(itemID)

 	local numSlots, freeSlots, ratio, bagType
 	for container = 0,4 do
 		numSlots = GetContainerNumSlots(container)
 		freeSlots, bagType = GetContainerFreeSlots(container)
-		if not numSlots or not freeSlots then break end
-		ratio = #freeSlots/numSlots
+		freeSlots = freeSlots and #freeSlots or 0

-		for slot = 1, numSlots do
-			local _,count,locked,_,_,canOpen,itemLink = GetContainerItemInfo(container, slot)
+		if numSlots then
+			ratio = freeSlots/numSlots

-			if itemLink and BrokerGarbage:GetItemID(itemLink) == itemID then
-				if not ignoreFullStack or (ignoreFullStack and count < maxStack) then
-					-- found one
-					table.insert(locations, {
-						slot = slot,
-						bag = container,
-						count = count,
-						ratio = ratio,
-						bagType = (bagType or 0)
-					})
+			for slot = 1, numSlots do
+				local _,count,_,_,_,_,link = GetContainerItemInfo(container, slot)
+
+				if link and BrokerGarbage:GetItemID(link) == itemID then
+					BrokerGarbage:Debug("item found")
+					if not ignoreFullStack or (ignoreFullStack and count < maxStack) then
+						-- found one
+						BrokerGarbage:Debug("item stack ok")
+						table.insert(locations, {
+							slot = slot,
+							bag = container,
+							count = count,
+							ratio = ratio,
+							bagType = (bagType or 0)
+						})
+					end
 				end
 			end
 		end
@@ -491,7 +566,7 @@ function BrokerGarbage:Delete(itemLink, position)
 	else
 		itemCount = position
 	end
-	local itemValue = BrokerGarbage:GetItemValue(itemLink, itemCount) or 0
+	local itemValue = BrokerGarbage:GetCached(itemID).value * itemCount

 	-- statistics
 	BG_GlobalDB.itemsDropped = BG_GlobalDB.itemsDropped + itemCount
@@ -504,301 +579,172 @@ end

 -- Inventory Scanning
 -- ---------------------------------------------------------
--- scans your inventory for possible junk items and updates LDB display
 function BrokerGarbage:ScanInventory()
-	BrokerGarbage.inventory = {}
-	BrokerGarbage.sellItems = {}
-	BrokerGarbage.unopened = {}
-	local limitedItemsChecked = {}
+	for container = 0,4 do
+		BrokerGarbage:ScanInventoryContainer(container)
+	end
+	UpdateLDB()
+end
+-- scans your inventory bags for possible junk items and updates LDB display
+function BrokerGarbage:ScanInventoryContainer(container)
+	-- container doesn't exist or cannot be scanned
+	if not GetContainerNumSlots(container) then return end

-	BrokerGarbage.toSellValue = 0
-	BrokerGarbage.totalBagSpace = 0
-	BrokerGarbage.totalFreeSlots = 0
+	local numSlots = GetContainerNumSlots(container)
+	BrokerGarbage.toSellValue[container] = 0

-	for container = 0,4 do
-		local numSlots = GetContainerNumSlots(container)
-		if numSlots then
-			freeSlots = GetContainerFreeSlots(container)
-			BrokerGarbage.totalFreeSlots = BrokerGarbage.totalFreeSlots + (freeSlots and #freeSlots or 0)
-			BrokerGarbage.totalBagSpace = BrokerGarbage.totalBagSpace + numSlots
+	for slot = 1, numSlots do
+		local itemID = GetContainerItemID(container,slot)
+
+		if itemID then
+			local item = BrokerGarbage:GetCached(itemID)

+			-- update toSellValue
+			if item.classification == BrokerGarbage.VENDORLIST or
+				(item.classification == BrokerGarbage.UNUSABLE and BG_GlobalDB.sellNotWearable and item.quality <= BG_GlobalDB.sellNWQualityTreshold) or
+				(BG_GlobalDB.autoSellIncludeItems and item.classification == BrokerGarbage.INCLUDE) then
+
+				local itemCount = select(2, GetContainerItemInfo(container, slot))
+				BrokerGarbage.toSellValue[container] = BrokerGarbage.toSellValue[container] + BrokerGarbage:GetCached(itemID).value * itemCount
+			end
+		end
+	end
+end
+
+-- Find Cheap Items
+-- ---------------------------------------------------------
+local function TableSort(a, b)
+	-- put included items even prior to forced vendor price items
+	if (a.source == b.source) or (a.source ~= BrokerGarbage.INCLUDE and b.source ~= BrokerGarbage.INCLUDE) then
+		if a.value == b.value then
+			if a.itemID == b.itemID then
+				return a.count < b.count
+			else
+				return a.itemID < b.itemID
+			end
+		else
+			return a.value < b.value
+		end
+	else
+		return a.source == BrokerGarbage.INCLUDE
+	end
+end
+
+-- returns the n cheapest items in your bags  in a table
+function BrokerGarbage:GetCheapest(number)
+	if not number then number = 1 end
+	local cheapestItems = {}
+	local numSlots, count, quality, canOpen, itemLink, itemID, stackSize
+	local item, maxValue, insert
+
+	BrokerGarbage.clamInInventory = false
+	BrokerGarbage.containerInInventory = false
+
+	for container = 0, 4 do
+		numSlots = GetContainerNumSlots(container)
+		if numSlots then
 			for slot = 1, numSlots do
-				local itemID = GetContainerItemID(container,slot)
-				if itemID then
-					-- GetContainerItemInfo sucks big time ... just don't use it for quality IDs!!!!!!!
-					local _,count,locked,_,_, canOpen,itemLink = GetContainerItemInfo(container, slot)
-					local quality = select(3,GetItemInfo(itemID))
-					local isClam = BrokerGarbage:Find(BrokerGarbage.clams, itemID)
+				-- "Gather Information"
+				_, count, _, _, _, canOpen, itemLink = GetContainerItemInfo(container, slot)
+				if itemLink then
+					itemID = BrokerGarbage:GetItemID(itemLink)
+					item = BrokerGarbage:GetCached(itemID)
+					insert = true
+					local value = count * item.value
+					local classification = item.classification

-					if canOpen or isClam then
-						local _,_,_,_,_,type,subType,_,_,tex = GetItemInfo(itemID)
-						tinsert(BrokerGarbage.unopened, {
-							bag = container,
-							slot = slot,
-							itemID = itemID,
-							clam = isClam,
-						})
-					end
-
-					-- check if this item belongs to an excluded category
-					local isExclude
-					for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.exclude, BG_LocalDB.exclude)) do
-						if type(setName) == "string" then
-							_, isExclude = BrokerGarbage.PT:ItemInSet(itemID, setName)
-						end
-						if isExclude then
-							break
+					-- remember lootable items
+					if canOpen or item.isClam then
+						if item.isClam then
+							BrokerGarbage.clamInInventory = true
+						else
+							BrokerGarbage.containerInInventory = true
 						end
 					end
-
-					local isSell, isInclude, isVendor
-					-- this saves excluded items
-					if not BG_GlobalDB.exclude[itemID] and not BG_LocalDB.exclude[itemID] then
-						local force = false
-
-						-- check if item is in a category of Include List
-						for setName,_ in pairs(BrokerGarbage:JoinTables(BG_LocalDB.include, BG_GlobalDB.include)) do
-							if type(setName) == "string" then
-								_, isInclude = BrokerGarbage.PT:ItemInSet(itemID, setName)
-							end
-							if isInclude then isInclude = setName; break end
-						end
-
-						-- check if item is in a category of Sell List
-						for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.autoSellList, BG_LocalDB.autoSellList)) do
-							if type(setName) == "string" then
-								_, isSell = BrokerGarbage.PT:ItemInSet(itemID, setName)
-							end
-							if isSell then isSell = setName; break end
-						end
-
-						-- check if item is in a category of Force Vendor Price List
-						for setName,_ in pairs(BG_GlobalDB.forceVendorPrice) do
-							if type(setName) == "string" then
-								_, isVendor = BrokerGarbage.PT:ItemInSet(itemID, setName)
-							end
-							if isVendor then isVendor = setName; break end
-						end
-
-						-- ----------------------------------------------------------------------
-						-- get price and tag
-						BrokerGarbage.checkItem = {
-							bag = container,
-							slot = slot,
-							itemID = itemID,
-						}
-						local value, source = BrokerGarbage:GetItemValue(itemLink, count)
-						BrokerGarbage.checkItem = nil
-
-						local _,_,_,_,_,_,subClass,stackSize,invType,_,vendorPrice = GetItemInfo(itemLink)
+
+					-- handle different types of items
+					if item.classification == BrokerGarbage.EXCLUDE then
+						insert = false
+
+					elseif item.classification == BrokerGarbage.LIMITED then
+						local saveStacks = ceil(item.limit/(item.stackSize or 1))
+						local locations = BrokerGarbage:FindSlotToDelete(itemID)

-						if (isInclude and not isExclude)
-							or BG_GlobalDB.include[itemID] or BG_LocalDB.include[itemID] then
-							-- Include List item
-							isInclude = true
-							force = true
+						if #locations > saveStacks then
+							local itemCount = 0

-							local limited = BrokerGarbage:Find(limitedItemsChecked, itemID)
-							if not limited then
-								if (BG_GlobalDB.include[itemID] and type(BG_GlobalDB.include[itemID]) == "number")
-									or (BG_LocalDB.include[itemID] and type(BG_LocalDB.include[itemID]) == "number") then
-
-									-- this is a limited item - only check it once
-									tinsert(limitedItemsChecked, itemID)
-									limited = true
-
-									local limit = tonumber(BG_GlobalDB.include[itemID]) or tonumber(BG_LocalDB.include[itemID])
-									local saveStacks = ceil(limit/(stackSize or 1))
-									local locations = BrokerGarbage:FindSlotToDelete(itemID)
-
-									if #locations > saveStacks then
-										local itemCount = 0
-										for i = #locations, 1, -1 do
-											if itemCount < limit then
-												itemCount = itemCount + locations[i].count
-											else
-												tinsert(BrokerGarbage.inventory, {
-													bag = locations[i].bag,
-													slot = locations[i].slot,
-													itemID = itemID,
-													quality = quality,
-													count = locations[i].count,
-													value = 0,
-													source = BrokerGarbage.tagInclude,
-													force = force,
-												})
-											end
-										end
+							for i = #locations, 1, -1 do
+								if itemCount < item.limit then
+									-- keep this amount
+									itemCount = itemCount + locations[i].count
+									if locations[i].bag == container and locations[i].slot == slot then
+										insert = false
 									end
 								else
-									limited = false
+									break;
 								end
 							end
-
-							if not limited then
-								value = value or 0
-								source = BrokerGarbage.tagInclude
-							else
-								-- this makes limited items not be inserted twice
-								value = nil
-							end
-
-						elseif (isSell and not isExclude)
-							or BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID] then
-							-- AutoSell
-							isSell = true
-							force = false
-
-							value = vendorPrice
-							if value then value = value * count end
-							source = BrokerGarbage.tagVendorList
-
-						elseif quality and quality <= BG_GlobalDB.dropQuality and
-							((isVendor and not isExclude) or BG_GlobalDB.forceVendorPrice[itemID]) then
-							-- Force Vendor Price List item
-							isVendor = true
-							force = false
-
-							value = vendorPrice
-							if value then value = value * count end
-							source = BrokerGarbage.tagVendorList
-
-						elseif not IsUsableSpell(BrokerGarbage.enchanting)	and BrokerGarbage:IsItemSoulbound(itemLink)
-							and BG_GlobalDB.sellNotWearable and quality <= BG_GlobalDB.sellNWQualityTreshold
-							and string.find(invType, "INVTYPE") and not string.find(invType, "BAG")
-							and not BrokerGarbage.usableByClass[BrokerGarbage.playerClass][subClass]
-							and not BrokerGarbage.usableByAll[invType] then
-							-- Sell unusable Gear
-							isSell = true
-							force = false
-
-							value = vendorPrice
-							source = BrokerGarbage.tagUnusableGear
-
-						elseif isExclude or (quality and quality > BG_GlobalDB.dropQuality) or not quality then
-							-- setting the value to nil will prevent the item being inserted to our inventory table
-							value = nil
-
-						-- all 'regular' items would be in the else part but already have their values and attributes set
 						end
-
-						if value then
-							-- save if we have something sellable
-							if quality == 0 or isSell
-								or BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID] then
-								BrokerGarbage.toSellValue = BrokerGarbage.toSellValue + value
-							end
-
-							-- insert into BrokerGarbage.inventory
-							if (quality and quality <= BG_GlobalDB.dropQuality)
-								or (isSell and source ~= BrokerGarbage.tagUnusableGear) or isInclude or isVendor then
-								tinsert(BrokerGarbage.inventory, {
-									bag = container,
-									slot = slot,
-									itemID = itemID,
-									quality = quality,
-									count = count,
-									value = value,
-									source = source,
-									force = force,
-								})
-
-							elseif quality > BG_GlobalDB.dropQuality and
-								(source == BrokerGarbage.tagUnusableGear or source == BrokerGarbage.tagVendorList) then
-								tinsert(BrokerGarbage.sellItems, {
-									bag = container,
-									slot = slot,
-									itemID = itemID,
-									quality = quality,
-									count = count,
-									value = value,
-									source = source,
-									force = force,
-								})
-							end
+						if insert then
+							-- treat like a regular include item
+							value = 0
 						end
+
+					elseif item.classification == BrokerGarbage.DISENCHANT or item.classification == BrokerGarbage.AUCTION then
+						-- check if item is really soulbound
+						if BrokerGarbage:IsItemSoulbound(itemID, container, slot) then
+							-- use vendor price instead
+							value = select(11, GetItemInfo(itemID))
+							classification = BrokerGarbage.VENDOR
+						end
+
+					elseif item.classification == BrokerGarbage.UNUSABLE then
+						if not BG_GlobalDB.sellNotWearable or item.quality > BG_GlobalDB.sellNWQualityTreshold then
+							insert = false
+						end
+
+					elseif item.classification == BrokerGarbage.INCLUDE then
+						value = 0
 					end
-				end
-			end
-		end
-	end
-
-	local cheapestItem = BrokerGarbage:GetCheapest()
-
-	if cheapestItem[1] then
-		BrokerGarbage.cheapestItem = cheapestItem[1]
-		LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBformat)
-	else
-		BrokerGarbage.cheapestItem = nil
-		LDB.text = BrokerGarbage:FormatString(BG_GlobalDB.LDBNoJunk)
-	end
-end
-
--- Find Cheap Items
--- ---------------------------------------------------------
--- returns the n cheapest items in your bags  in a table
-function BrokerGarbage:GetCheapest(number)
-	if not number then number = 1 end
-	local cheapestItems, temp = {}, {}
-
-	-- get forced items
-	for _, itemTable in pairs(BrokerGarbage:JoinSimpleTables(BrokerGarbage.inventory, BrokerGarbage.sellItems)) do
-		local skip = false
-
-		for _, usedTable in pairs(cheapestItems) do
-			if usedTable == itemTable then
-				skip = true
-				break
-			end
-		end
-
-		if not skip and itemTable.force then
-			tinsert(temp, itemTable)
-		end
-	end
-	table.sort(temp, function(a, b)
-		-- put included items even prior to forced vendor price items
-		if (a.source == b.source) or (a.source ~= BrokerGarbage.tagInclude and b.source ~= BrokerGarbage.tagInclude) then
-			return a.value < b.value
-		else
-			return a.source == BrokerGarbage.tagInclude
-		end
-	end)
-
-	if #temp <= number then
-		cheapestItems = temp
-	else
-		for i = 1, number do
-			tinsert(cheapestItems, temp[i])
-		end
-	end
-
-	-- fill with non-forced
-	if #cheapestItems < number then
-		local minPrice, minTable
-
-		for i = #cheapestItems +1, number do
-			for _, itemTable in pairs(BrokerGarbage.inventory) do
-				local skip = false
-
-				for _, usedTable in pairs(cheapestItems) do
-					if usedTable == itemTable then
-						skip = true
+
+					if item.quality > BG_GlobalDB.dropQuality and
+						not (classification == BrokerGarbage.INCLUDE or classification == BrokerGarbage.VENDORLIST) then
+						-- include and vendor list items should always be displayed
+						insert = false
+
+					elseif value == 0 and BG_GlobalDB.hideZeroValue and classification == BrokerGarbage.VENDOR then
+						insert = false
+					end
+
+					-- insert data
+					if insert then
+						maxValue = cheapestItems[number] and cheapestItems[number].value or nil
+						if not maxValue then
+							tinsert(cheapestItems, {
+								itemID = itemID,
+								bag = container,
+								slot = slot,
+								count = count,
+								value = value,
+								source = classification,
+							})
+						elseif value < maxValue then
+							-- update last item
+							cheapestItems[number].itemID = itemID
+							cheapestItems[number].bag = container
+							cheapestItems[number].slot = slot
+							cheapestItems[number].count = count
+							cheapestItems[number].value = value
+							cheapestItems[number].source = classification
+						end
+						table.sort(cheapestItems, TableSort)
 					end
 				end
-
-				if not skip and (not minPrice or itemTable.value < minPrice) then
-					minPrice = itemTable.value
-					minTable = itemTable
-				end
 			end
-
-			if minTable then tinsert(cheapestItems, minTable) end
-			minPrice = nil
-			minTable = nil
 		end
 	end

+	BrokerGarbage.cheapestItem = cheapestItems[1]
 	return cheapestItems
 end

@@ -807,104 +753,70 @@ end
 -- ---------------------------------------------------------
 -- when at a merchant this will clear your bags of junk (gray quality) and items on your autoSellList
 function BrokerGarbage:AutoSell()
-	if BG_GlobalDB.autoSellToVendor or self == _G["BrokerGarbage_SellIcon"] then
-		if self == _G["BrokerGarbage_SellIcon"] then
-			BrokerGarbage:Debug("AutoSell was triggered by a click on Sell Icon.", BrokerGarbage:FormatMoney(sellValue), BrokerGarbage:FormatMoney(BrokerGarbage.toSellValue))
-		end
-		local i = 1
-		local skip
-		sellValue = 0
-		for _, itemTable in pairs(BrokerGarbage:JoinSimpleTables(BrokerGarbage.inventory, BrokerGarbage.sellItems)) do
-			local sellByString, sellByID, excludeByID, excludeByString
-			local temp, checkTable
-
-			-- check if item should be saved: exclude/whitelist
-			excludeByID = BG_GlobalDB.exclude[itemTable.itemID] or BG_LocalDB.exclude[itemTable.itemID]
-			for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.exclude, BG_LocalDB.exclude)) do
-				if type(setName) == "string" then
-					_, temp = BrokerGarbage.PT:ItemInSet(itemTable.itemID, setName)
-				end
-				if temp then
-					BrokerGarbage:Debug(itemTable.itemID, "is in set", temp, "on exclude list")
-					excludeByString = true
-					break
-				end
-			end
-			if excludeByID then
-				BrokerGarbage:Debug(itemTable.itemID, "is excluded via its itemID")
-			end
-
-			if excludeByString or excludeByID then
-				sellByID = false
-				checkTable = {}
-			elseif BG_GlobalDB.autoSellIncludeItems then
-				sellByID = BG_GlobalDB.include[itemTable.itemID] or BG_LocalDB.include[itemTable.itemID]
-				checkTable = BrokerGarbage:JoinTables(BG_LocalDB.include, BG_GlobalDB.include)
-			else
-				sellByID = BG_GlobalDB.autoSellList[itemTable.itemID] or BG_LocalDB.autoSellList[itemTable.itemID]
-				checkTable = BrokerGarbage:JoinTables(BG_LocalDB.autoSellList, BG_GlobalDB.autoSellList)
-			end
-
-			temp = nil
-			-- check if item should be sold
-			for setName,_ in pairs(checkTable) do
-				if type(setName) == "string" then
-					_, temp = BrokerGarbage.PT:ItemInSet(itemTable.itemID, setName)
-				end
-				if temp then
-					-- this only prints the first match
-					BrokerGarbage:Debug(itemTable.itemID, "is in set", temp, "on auto sell list")
-					sellByString = true
-					break
-				end
-			end
-			if sellByID then
-				BrokerGarbage:Debug(itemTable.itemID, "is to be sold via its itemID")
-			end
-
-			-- ==== Sell Gear ==== --
-			-- check if this item is equippable for us
-			local _, itemLink, quality, _, _, _, subClass, _, invType = GetItemInfo(itemTable.itemID)
-			local sellGear = quality
-				and not IsUsableSpell(BrokerGarbage.enchanting)	and BrokerGarbage:IsItemSoulbound(itemLink)
-				and BG_GlobalDB.sellNotWearable and quality <= BG_GlobalDB.sellNWQualityTreshold
-				and string.find(invType, "INVTYPE") and not string.find(invType, "BAG")
-				and not BrokerGarbage.usableByClass[BrokerGarbage.playerClass][subClass]
-				and not BrokerGarbage.usableByAll[invType]
-			if sellGear then
-				BrokerGarbage:Debug("Item should be sold (as we cannot wear it):" .. itemLink)
-			end
-
-			-- === Actuall Selling === ---
-			-- do the priorities right!
-			if itemTable.value ~= 0 and not excludeByID and (sellByID
-				or (not excludeByString and (sellByString or itemTable.quality == 0 or sellGear))) then
-
-				if i == 1 then
-					BrokerGarbage:Debug("Inventory scans locked")
-					locked = true
+	if not BrokerGarbage.isAtVendor then return end
+
+	if self == _G["BrokerGarbage_SellIcon"] then
+		BrokerGarbage:Debug("AutoSell was triggered by a click on Sell Icon.")
+	end
+	local sell, classification
+	local item, itemID, value, count, numSlots
+	sellValue = 0
+
+	for container = 0, 4 do
+		numSlots = GetContainerNumSlots(container)
+		if numSlots then
+			for slot = 1, numSlots do
+				_, count, _, _, _, _, itemLink = GetContainerItemInfo(container, slot)
+				if itemLink then
+					itemID 	= BrokerGarbage:GetItemID(itemLink)
+					item 	= BrokerGarbage:GetCached(itemID)
+					value 	= item.value
+
+					sell = false
+					-- various cases that have us sell this item
+					if item.classification == BrokerGarbage.UNUSABLE then
+						local quality = select(3, GetItemInfo(itemID))
+						if BG_GlobalDB.sellNotWearable and quality <= BG_GlobalDB.sellNWQualityTreshold then
+							sell = true
+						end
+
+					elseif item.classification == BrokerGarbage.INCLUDE and BG_GlobalDB.autoSellIncludeItems then
+						sell = true
+
+					elseif item.classification == BrokerGarbage.VENDORLIST then
+						sell = true
+					end
+
+					-- Actual Selling
+					if value ~= 0 and sell then
+						if not locked then
+							BrokerGarbage:Debug("Inventory scans locked")
+							locked = true
+						end
+
+						BrokerGarbage:Debug("Selling", itemID)
+						ClearCursor()
+						UseContainerItem(container, slot)
+
+						sellValue = sellValue + (count * value)
+						-- update statistics
+						BG_GlobalDB.moneyEarned = BG_GlobalDB.moneyEarned + (count * value)
+						BG_LocalDB.moneyEarned = BG_LocalDB.moneyEarned + (count * value)
+						BG_GlobalDB.itemsSold = BG_GlobalDB.itemsSold + count
+					end
 				end
-
-				BrokerGarbage:Debug("Selling", itemTable.itemID)
-				sellValue = sellValue + itemTable.value
-				BG_GlobalDB.moneyEarned = BG_GlobalDB.moneyEarned + itemTable.value
-				BG_LocalDB.moneyEarned = BG_LocalDB.moneyEarned + itemTable.value
-
-				ClearCursor()
-				UseContainerItem(itemTable.bag, itemTable.slot)
-				BG_GlobalDB.itemsSold = BG_GlobalDB.itemsSold + itemTable.count
-				i = i+1
 			end
 		end
-
-		if self == _G["BrokerGarbage_SellIcon"] then
-			if sellValue == 0 and BG_GlobalDB.reportNothingToSell then
-				BrokerGarbage:Print(BrokerGarbage.locale.reportNothingToSell)
-			elseif sellValue ~= 0 and not BG_GlobalDB.autoSellToVendor then
-				BrokerGarbage:Print(format(BrokerGarbage.locale.sell, BrokerGarbage:FormatMoney(sellValue)))
-			end
-			_G["BrokerGarbage_SellIcon"]:GetNormalTexture():SetDesaturated(true)
+	end
+
+	-- create output if needed
+	if self == _G["BrokerGarbage_SellIcon"] then
+		if sellValue == 0 and BG_GlobalDB.reportNothingToSell then
+			BrokerGarbage:Print(BrokerGarbage.locale.reportNothingToSell)
+		elseif sellValue ~= 0 and not BG_GlobalDB.autoSellToVendor then
+			BrokerGarbage:Print(format(BrokerGarbage.locale.sell, BrokerGarbage:FormatMoney(sellValue)))
 		end
+		_G["BrokerGarbage_SellIcon"]:GetNormalTexture():SetDesaturated(true)
 	end
 end

@@ -916,12 +828,10 @@ function BrokerGarbage:AutoRepair()

 		if cost > 0 and CanGuildBankRepair() and GetGuildBankWithdrawMoney() >= cost and not BG_LocalDB.neverRepairGuildBank then
 			-- guild repair if we're allowed to and the user wants it
-			-- RepairAllItems(1)
-			securecall(RepairAllItems, 1)
+			RepairAllItems(1)
 		elseif cost > 0 and money >= cost then
 			-- not enough allowance to guild bank repair, pay ourselves
-			--RepairAllItems(0)
-			securecall(RepairAllItems, 0)
+			RepairAllItems(0)
 		elseif cost > 0 then
 			-- oops. give us your moneys!
 			BrokerGarbage:Print(format(BrokerGarbage.locale.couldNotRepair, BrokerGarbage:FormatMoney(cost)))
diff --git a/helper.lua b/helper.lua
index e1a4136..4e8dd10 100644
--- a/helper.lua
+++ b/helper.lua
@@ -1,8 +1,7 @@
+-- to enable debug mode, run this (disable by setting it to false):
+--	/run BG_GlobalDB.debug = true
 _, BrokerGarbage = ...

-local debug = false		-- set this to 'true' to get your chatframe spammed :D
-
-
 -- Addon Basics
 -- ---------------------------------------------------------
 -- output functions
@@ -10,8 +9,9 @@ function BrokerGarbage:Print(text)
 	DEFAULT_CHAT_FRAME:AddMessage("|cffee6622Broker_Garbage|r "..text)
 end

+-- prints debug messages only when debug mode is active
 function BrokerGarbage:Debug(...)
-  if debug then
+  if BG_GlobalDB.debug then
 	BrokerGarbage:Print("! "..string.join(", ", tostringall(...)))
   end
 end
@@ -19,7 +19,7 @@ end
 -- warn the player by displaying a warning message
 function BrokerGarbage:Warning(text)
 	if BG_GlobalDB.showWarnings and time() - lastReminder >= 5 then
-		BrokerGarbage:Print("|cfff0000Warning:|r ", text)
+		BrokerGarbage:Print("|cfff0000Warning!|r ", text)
 		lastReminder = time()
 	end
 end
@@ -66,16 +66,13 @@ function BrokerGarbage:JoinSimpleTables(...)
 	return result
 end

+-- counts table entries. for numerically indexed tables, use #table
 function BrokerGarbage:Count(table)
   local i = 0
   for _, _ in pairs(table) do i = i + 1 end
   return i
 end

-function BrokerGarbage:ErrorReport()
-	-- TODO
-end
-
 -- Saved Variables Management / API
 -- ---------------------------------------------------------
 function BrokerGarbage:CheckSettings()
@@ -137,8 +134,10 @@ function BrokerGarbage:CreateDefaultLists(global)
 	-- class specific
 	if BrokerGarbage.playerClass == "HUNTER" then
 		BG_LocalDB.exclude["Misc.Reagent.Ammo"] = true
+
 	elseif BrokerGarbage.playerClass == "WARRIOR" or BrokerGarbage.playerClass == "ROGUE" or BrokerGarbage.playerClass == "DEATHKNIGHT" then
 		BG_LocalDB.autoSellList["Consumable.Water"] = true
+
 	elseif BrokerGarbage.playerClass == "SHAMAN" then
 		if not BG_LocalDB.include[17058] then BG_LocalDB.include[17058] = 20 end	-- fish oil
 		if not BG_LocalDB.include[17057] then BG_LocalDB.include[17057] = 20 end	-- scales
@@ -209,8 +208,13 @@ function BrokerGarbage:FormatString(text)
 	else
 		item = BrokerGarbage.cheapestItem
 	end
+
 	-- [junkvalue]
-	text = string.gsub(text, "%[junkvalue%]", BrokerGarbage:FormatMoney(BrokerGarbage.toSellValue))
+	local junkValue = 0
+	for i = 0, 4 do
+		junkValue = junkValue + BrokerGarbage.toSellValue[i]
+	end
+	text = string.gsub(text, "%[junkvalue%]", BrokerGarbage:FormatMoney(junkValue))

 	-- [itemname][itemcount][itemvalue]
 	text = string.gsub(text, "%[itemname%]", (select(2,GetItemInfo(item.itemID)) or ""))
@@ -314,7 +318,8 @@ function BrokerGarbage:CheckSkills()
 end

 local scanTooltip = CreateFrame('GameTooltip', 'BGItemScanTooltip', UIParent, 'GameTooltipTemplate')
-function BrokerGarbage:CanDisenchant(itemLink, myself)
+-- misc: either "true" to check only for the current character, or a table {container, slot} for reference
+function BrokerGarbage:CanDisenchant(itemLink, misc)
 	if (itemLink) then
 		local _, _, quality, level, _, _, _, count, bagSlot = GetItemInfo(itemLink)

@@ -349,12 +354,13 @@ function BrokerGarbage:CanDisenchant(itemLink, myself)
 				end
 				-- if skill is too low, still check if we can send it
 			end
-			if myself then return false end		-- we can't diss ourselves. hrm. maybe we can!
+			-- misc = "true" => we only care if we ourselves can DE. no twink mail etc.
+			if misc and type(misc) == "boolean" then return false end

 			-- so we can't DE, but can we send it to someone who may? i.e. is the item not soulbound?
 			if not BG_GlobalDB.hasEnchanter then return false end
-			if BrokerGarbage.checkItem then
-				return not BrokerGarbage:IsItemSoulbound(itemLink, BrokerGarbage.checkItem.bag, BrokerGarbage.checkItem.slot)
+			if misc and type(misc) == "table" then
+				return not BrokerGarbage:IsItemSoulbound(itemLink, misc.bag, misc.slot)
 			else
 				return not BrokerGarbage:IsItemSoulbound(itemLink)
 			end
@@ -390,6 +396,165 @@ function BrokerGarbage:IsItemSoulbound(itemLink, bag, slot)
 	return false
 end

+-- gets an item's classification and saves it to the item cache
+function BrokerGarbage:UpdateCache(itemID)
+	if not itemID then return nil end
+	local class, temp, limit
+
+	local _, itemLink, quality, _, _, _, subClass, stackSize, invType, _, value = GetItemInfo(itemID)
+
+	-- check if item is excluded by itemID
+	if BG_GlobalDB.exclude[itemID] or BG_LocalDB.exclude[itemID] then
+		BrokerGarbage:Debug("Item "..itemID.." is excluded via its itemID.")
+		class = BrokerGarbage.EXCLUDE
+	end
+
+	-- check if the item is classified by its itemID
+	if not class then
+		if BG_GlobalDB.include[itemID] or BG_LocalDB.include[itemID] then
+
+			if BG_LocalDB.include[itemID] and type(BG_LocalDB.include[itemID]) ~= "boolean" then
+				-- limited item, local rule
+				BrokerGarbage:Debug("Item "..itemID.." is locally limited via its itemID.")
+				class = BrokerGarbage.LIMITED
+				limit = BG_LocalDB.include[itemID]
+
+			elseif BG_GlobalDB.include[itemID] and type(BG_GlobalDB.include[itemID]) ~= "boolean" then
+				-- limited item, global rule
+				BrokerGarbage:Debug("Item "..itemID.." is globally limited via its itemID.")
+				class = BrokerGarbage.LIMITED
+				limit = BG_GlobalDB.include[itemID]
+
+			else
+				BrokerGarbage:Debug("Item "..itemID.." is included via its itemID.")
+				class = BrokerGarbage.INCLUDE
+			end
+
+		elseif BG_GlobalDB.autoSellList[itemID] or BG_LocalDB.autoSellList[itemID]
+			or BG_GlobalDB.forceVendorPrice[itemID] then
+
+			BrokerGarbage:Debug("Item "..itemID.." has a forced vendor price via its itemID.")
+			class = BrokerGarbage.VENDORLIST
+
+		elseif quality
+			and not IsUsableSpell(BrokerGarbage.enchanting)	and BrokerGarbage:IsItemSoulbound(itemLink)
+			and string.find(invType, "INVTYPE") and not string.find(invType, "BAG")
+			and not BrokerGarbage.usableByClass[BrokerGarbage.playerClass][subClass]
+			and not BrokerGarbage.usableByAll[invType] then
+
+			BrokerGarbage:Debug("Item "..itemID.." should be sold as we can't ever wear it.")
+			class = BrokerGarbage.UNUSABLE
+
+		-- check if the item is classified by its category
+		else
+			-- check if item is excluded by its category
+			for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.exclude, BG_LocalDB.exclude)) do
+				if type(setName) == "string" then
+					_, temp = BrokerGarbage.PT:ItemInSet(itemID, setName)
+				end
+				if temp then
+					BrokerGarbage:Debug("Item "..itemID.." is excluded via its category.")
+					class = BrokerGarbage.EXCLUDE
+					break
+				end
+			end
+
+			-- Include List
+			if not class then
+				for setName,_ in pairs(BrokerGarbage:JoinTables(BG_LocalDB.include, BG_GlobalDB.include)) do
+					if type(setName) == "string" then
+						_, temp = BrokerGarbage.PT:ItemInSet(itemID, setName)
+					end
+					if temp then
+						BrokerGarbage:Debug("Item "..itemID.." in included via its item category.")
+						class = BrokerGarbage.INCLUDE
+						break
+					end
+				end
+			end
+
+			-- Sell List
+			if not class then
+				for setName,_ in pairs(BrokerGarbage:JoinTables(BG_GlobalDB.autoSellList, BG_LocalDB.autoSellList)) do
+					if type(setName) == "string" then
+						_, temp = BrokerGarbage.PT:ItemInSet(itemID, setName)
+					end
+					if temp then
+						BrokerGarbage:Debug("Item "..itemID.." is on the sell list via its item category.")
+						class = BrokerGarbage.VENDORLIST
+						break
+					end
+				end
+			end
+
+			-- Force Vendor Price List
+			if not class then
+				for setName,_ in pairs(BG_GlobalDB.forceVendorPrice) do
+					if type(setName) == "string" then
+						_, temp = BrokerGarbage.PT:ItemInSet(itemID, setName)
+					end
+					if temp then
+						BrokerGarbage:Debug("Item "..itemID.." has a forced vendor price via its item category.")
+						class = BrokerGarbage.VENDOR
+						break
+					end
+				end
+			end
+		end
+	end
+
+	if not class then
+		value, class = BrokerGarbage:GetSingleItemValue(itemID)
+	end
+	if not value then
+		value = 0
+	end
+
+	-- save to items cache
+	if not BrokerGarbage.itemsCache[itemID] then
+		BrokerGarbage.itemsCache[itemID] = {
+			classification = class,
+			quality = quality,
+			value = value,
+			limit = limit,
+			stackSize = stackSize,
+			isClam = BrokerGarbage:Find(BrokerGarbage.clams, itemID),
+		}
+	else
+		BrokerGarbage.itemsCache[itemID].classification = class
+		BrokerGarbage.itemsCache[itemID].quality = quality
+		BrokerGarbage.itemsCache[itemID].value = value
+		BrokerGarbage.itemsCache[itemID].limit = limit
+		BrokerGarbage.itemsCache[itemID].stackSize = stackSize
+		BrokerGarbage.itemsCache[itemID].isClam = BrokerGarbage:Find(BrokerGarbage.clams, itemID)
+	end
+end
+
+-- fetch an item from the item cache, or insert if it doesn't exist yet
+function BrokerGarbage:GetCached(itemID)
+	if not BrokerGarbage.itemsCache[itemID] then
+		BrokerGarbage:UpdateCache(itemID)
+	end
+	return BrokerGarbage.itemsCache[itemID]
+end
+
+-- returns total bag slots and free bag slots of your whole inventory
+function BrokerGarbage:GetBagSlots()
+	local total, free = 0, 0
+	local num
+
+	for i = 0, 4 do
+		num = GetContainerNumSlots(i)
+		if num then
+			total = total + num
+			free = free + (GetContainerFreeSlots(i) and #GetContainerFreeSlots(i) or 0)
+		end
+	end
+
+	return total, free
+end
+
+-- formats money int values, depending on settings
 function BrokerGarbage:FormatMoney(amount)
 	if not amount then return "" end

diff --git a/options.lua b/options.lua
index dd73139..acb6c5b 100644
--- a/options.lua
+++ b/options.lua
@@ -899,7 +899,8 @@ local function ShowListOptions(frame)
 	-- function to set the drop treshold (limit) via the mousewheel
 	local function OnMouseWheel(self, dir)
 		if type(self.itemID) ~= "number" then return end
-		BrokerGarbage.debug = self
+		-- clear item from cache
+		BrokerGarbage.itemsCache[self.itemID] = nil
 		local list, text

 		if dir == 1 then
@@ -1124,9 +1125,11 @@ local function ShowListOptions(frame)
 		if itemID then
 			-- real items
 			itemID = itemID
+			BrokerGarbage.itemsCache[itemID] = nil
 		else
 			-- category strings
 			itemID = item
+			BrokerGarbage.itemsCache = {}
 		end

 		-- create "link" for output
@@ -1255,6 +1258,7 @@ local function ShowListOptions(frame)

 		-- empty action
 		if self == emptyExcludeList then
+			BrokerGarbage.itemsCache = {}
 			if IsShiftKeyDown() then
 				BG_GlobalDB.exclude = {}
 			else
@@ -1262,11 +1266,13 @@ local function ShowListOptions(frame)
 			end
 			BrokerGarbage:ListOptionsUpdate("exclude")
 		elseif self == emptyForcePriceList then
+			BrokerGarbage.itemsCache = {}
 			if IsShiftKeyDown() then
 				BG_GlobalDB.forceVendorPrice = {}
 				BrokerGarbage:ListOptionsUpdate("forceprice")
 			end
 		elseif self == emptyIncludeList then
+			BrokerGarbage.itemsCache = {}
 			if IsShiftKeyDown() then
 				BG_GlobalDB.include = {}
 			else
@@ -1274,6 +1280,7 @@ local function ShowListOptions(frame)
 			end
 			BrokerGarbage:ListOptionsUpdate("include")
 		elseif self == emptyAutoSellList then
+			BrokerGarbage.itemsCache = {}
 			if IsShiftKeyDown() then
 				BG_GlobalDB.autoSellList = {}
 			else
@@ -1285,6 +1292,11 @@ local function ShowListOptions(frame)
 		elseif self == minus then
 			for i, button in pairs(BrokerGarbage.listButtons.exclude) do
 				if button:GetChecked() then
+					if type(button.itemID) == "number" then
+						BrokerGarbage.itemsCache[button.itemID] = nil
+					else
+						BrokerGarbage.itemsCache = {}
+					end
 					BG_LocalDB.exclude[button.itemID] = nil
 					BG_GlobalDB.exclude[button.itemID] = nil
 				end
@@ -1294,6 +1306,11 @@ local function ShowListOptions(frame)
 		elseif self == minus2 then
 			for i, button in pairs(BrokerGarbage.listButtons.forceprice) do
 				if button:GetChecked() then
+					if type(button.itemID) == "number" then
+						BrokerGarbage.itemsCache[button.itemID] = nil
+					else
+						BrokerGarbage.itemsCache = {}
+					end
 					BG_GlobalDB.forceVendorPrice[button.itemID] = nil
 				end
 			end
@@ -1302,6 +1319,11 @@ local function ShowListOptions(frame)
 		elseif self == minus3 then
 			for i, button in pairs(BrokerGarbage.listButtons.include) do
 				if button:GetChecked() then
+					if type(button.itemID) == "number" then
+						BrokerGarbage.itemsCache[button.itemID] = nil
+					else
+						BrokerGarbage.itemsCache = {}
+					end
 					BG_LocalDB.include[button.itemID] = nil
 					BG_GlobalDB.include[button.itemID] = nil
 				end
@@ -1311,6 +1333,11 @@ local function ShowListOptions(frame)
 		elseif self == minus4 then
 			for i, button in pairs(BrokerGarbage.listButtons.autosell) do
 				if button:GetChecked() then
+					if type(button.itemID) == "number" then
+						BrokerGarbage.itemsCache[button.itemID] = nil
+					else
+						BrokerGarbage.itemsCache = {}
+					end
 					BG_LocalDB.autoSellList[button.itemID] = nil
 					BG_GlobalDB.autoSellList[button.itemID] = nil
 				end
@@ -1498,6 +1525,8 @@ function SlashCmdList.BROKERGARBAGE(msg, editbox)
 		itemID = tonumber(itemID)
 		count = tonumber(count)

+		BrokerGarbage.itemsCache[itemID] = nil
+
 		if string.find(command, "g") then
 			BG_GlobalDB.include[itemID] = count
 		else