Quantcast

Added checking for incomplete reagents when rendering the skill list or queuing skills.

pschifferer [12-19-09 - 17:10]
Added checking for incomplete reagents when rendering the skill list or queuing skills.
Removed a slew of unused logging statements.
Filename
CauldronMain.lua
CauldronMainUI.lua
CauldronQueue.lua
CauldronTradeskill.lua
CauldronUtil.lua
diff --git a/CauldronMain.lua b/CauldronMain.lua
index fdb505d..7eda771 100644
--- a/CauldronMain.lua
+++ b/CauldronMain.lua
@@ -153,9 +153,6 @@ function Cauldron:OnInitialize()
 end

 function Cauldron:InitPlayer()
---@alpha@
-	self:debug("InitPlayer enter");
---@end-alpha@

 	-- check if the database needs to be updated
 	if self.db.global.version then
@@ -196,16 +193,10 @@ function Cauldron:InitPlayer()

 	-- store the current revision in the database
 	self.db.global.version = Cauldron.version;
-
---@alpha@
-	self:debug("InitPlayer exit");
---@end-alpha@
+
 end

 function Cauldron:OnEnable()
---@alpha@
-	self:debug("OnEnable enter");
---@end-alpha@

 	-- set init flag, for some callbacks
 	self.initializing = true;
@@ -256,26 +247,16 @@ function Cauldron:OnEnable()
 	-- clear init flag
 	self.initializing = false;

---@alpha@
-	self:debug("OnEnable exit");
---@end-alpha@
 end

 function Cauldron:OnDisable()
---@alpha@
-	self:debug("OnDisable enter");
---@end-alpha@
-
---@alpha@
-	self:debug("OnDisable exit");
---@end-alpha@
+
+	-- TODO
+
 end

 function Cauldron:OnAddonLoaded(event, addon)
---@alpha@
-	self:debug("OnAddonLoaded enter");
---@end-alpha@
-
+
 	--[[
 	-- show the shopping list?
 	if self.db.profile.showShoppingList then
@@ -287,15 +268,9 @@ function Cauldron:OnAddonLoaded(event, addon)
 	end
 	--]]

---@alpha@
-	self:debug("OnAddonLoaded exit");
---@end-alpha@
 end

 function Cauldron:OnEvent(event, ...)
---@alpha@
-	self:debug("OnEvent enter");
---@end-alpha@

 	if event == "UNIT_PORTRAIT_UPDATE" then
 		local arg1 = ...;
@@ -304,9 +279,6 @@ function Cauldron:OnEvent(event, ...)
 		end
 	end

---@alpha@
-	self:debug("OnEvent exit");
---@end-alpha@
 end

 function Cauldron:OnTradeShow()
@@ -337,21 +309,12 @@ function Cauldron:OnTradeUpdate()
 end

 function Cauldron:OnTradeClose()
---@alpha@
-	self:debug("OnTradeClose enter");
---@end-alpha@

 	self:Frame_Hide();

---@alpha@
-	self:debug("OnTradeClose exit");
---@end-alpha@
 end

 function Cauldron:OnSkillUpdate()
---@alpha@
-	self:debug("OnSkillUpdate enter");
---@end-alpha@

 	if CURRENT_TRADESKILL ~= "" then
 		if not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL] then
@@ -371,15 +334,9 @@ function Cauldron:OnSkillUpdate()

 	self:Frame_Update();

---@alpha@
-	self:debug("OnSkillUpdate exit");
---@end-alpha@
 end

 function Cauldron:OnTradeSkillRecast()
---@alpha@
-	self:debug("OnTradeSkillRecast enter");
---@end-alpha@

 	-- keep the processing flag set
 	self.processing = true;
@@ -390,16 +347,10 @@ function Cauldron:OnTradeSkillRecast()

 	self:Frame_Update();

---@alpha@
-	self:debug("OnTradeSkillRecast exit");
---@end-alpha@
 end

 function Cauldron:OnBagUpdate(event, bagid)
-	--@alpha@
-	self:debug("OnBagUpdate enter");
-	--@end-alpha@
-
+
     -- make sure we're not reacting to initial bag update events when the DB isn't initialized yet
     if (self.initializing) or (not self.db) or (not self.vars) then
         return;
@@ -412,14 +363,8 @@ function Cauldron:OnBagUpdate(event, bagid)
 	self:debug("items="..tostring(items));
 	local recalc = false;
 	for item, itemCount in pairs(items) do
-		--@alpha@
-		self:debug("OnBagUpdate: item="..tostring(item).."; itemCount="..tostring(itemCount));
-		--@end-alpha@
 		if itemCount > 0 then
 			-- adjust shopping list
-			--@alpha@
-			self:debug("OnBagUpdate: adjust shopping list");
-			--@end-alpha@
 			local amtRemoved = CauldronShopping:RemoveFromList(self.db.realm.shopping, self.vars.playername, item, itemCount);
 			if amtRemoved > 0 then
 				local str = string.format("%s: %s: %d", L["Shopping list"], item, amtRemoved);
@@ -492,39 +437,21 @@ function Cauldron:OnBagUpdate(event, bagid)
 	-- update the bags
 	Cauldron:ScanBags();

-	--@alpha@
-	self:debug("OnBagUpdate exit");
-	--@end-alpha@
 end

 function Cauldron:OnCraftShow()
---@alpha@
-	self:debug("OnCraftShow enter");
---@end-alpha@

 --	TODO

---@alpha@
-	self:debug("OnCraftShow exit");
---@end-alpha@
 end

 function Cauldron:OnCraftClose()
---@alpha@
-	self:debug("OnCraftClose enter");
---@end-alpha@

 --	TODO

---@alpha@
-	self:debug("OnCraftClose exit");
---@end-alpha@
 end

 function Cauldron:OnMerchantShow()
---@alpha@
-	self:debug("OnMerchantShow enter");
---@end-alpha@

 	-- check if there's anything in the shopping list
 	if CauldronShopping:ContainsItems(Cauldron.db.realm.shopping) then
@@ -535,112 +462,64 @@ function Cauldron:OnMerchantShow()
 		end
 	end

---@alpha@
-	self:debug("OnMerchantShow exit");
---@end-alpha@
 end

 function Cauldron:OnMerchantClose()
---@alpha@
-	self:debug("OnMerchantClose enter");
---@end-alpha@

 	if not CauldronShopping:ContainsItems(Cauldron.db.realm.shopping) then
 		Cauldron:HideShoppingList();
 	end

---@alpha@
-	self:debug("OnMerchantClose exit");
---@end-alpha@
 end

 function Cauldron:OnBankOpened()
---@alpha@
-	self:debug("OnBankOpened enter");
---@end-alpha@

 	-- check if there's anything in the shopping list
 	if CauldronShopping:ContainsItems(Cauldron.db.realm.shopping) then
 		Cauldron:ShowShoppingList();
 	end

---@alpha@
-	self:debug("OnBankOpened exit");
---@end-alpha@
 end

 function Cauldron:OnBankClosed()
---@alpha@
-	self:debug("OnBankClosed enter");
---@end-alpha@

 	if not CauldronShopping:ContainsItems(Cauldron.db.realm.shopping) then
 		Cauldron:HideShoppingList();
 	end

---@alpha@
-	self:debug("OnBankClosed exit");
---@end-alpha@
 end

 function Cauldron:OnQuestLogChanged()
---@alpha@
-	self:debug("OnQuestLogChanged enter");
---@end-alpha@

 	-- TODO

---@alpha@
-	self:debug("OnQuestLogChanged exit");
---@end-alpha@
 end

 function Cauldron:OnAchievementEarned()
---@alpha@
-	self:debug("OnAchievementEarned enter");
---@end-alpha@

 	-- update the achievement skill map
 	Cauldron:CreateAchievementSkillMap();
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("OnAchievementEarned exit");
---@end-alpha@
 end

 function Cauldron:OnSpellcastStart(event, unit, spell, rank)
-	--@alpha@
-	self:debug("OnSpellcastStart enter");
-	--@end-alpha@

 -- self:info("spell start - unit: "..tostring(unit).."; spell: "..tostring(spell).."; rank: "..tostring(rank));

 	self.processing = true;

-	--@alpha@
-	self:debug("OnSpellcastStart exit");
-	--@end-alpha@
 end

 function Cauldron:OnSpellcastStop(event, unit, spell, rank)
-	--@alpha@
-	self:debug("OnSpellcastStop enter");
-	--@end-alpha@

 -- self:info("spell stop - unit: "..tostring(unit).."; spell: "..tostring(spell).."; rank: "..tostring(rank));

 	self.processing = false;

-	--@alpha@
-	self:debug("OnSpellcastStop exit");
-	--@end-alpha@
 end

 function Cauldron:OnSpellcastSucceed(event, unit, spell, rank)
-	--@alpha@
-	self:debug("OnSpellcastSucceed enter");
-	--@end-alpha@

 -- self:info("spell succeed - unit: "..tostring(unit).."; spell: "..tostring(spell).."; rank: "..tostring(rank));

@@ -652,70 +531,37 @@ function Cauldron:OnSpellcastSucceed(event, unit, spell, rank)
 	local queue = self.db.realm.userdata[self.vars.playername].queue;

 	-- adjust queue, but only if window is open
-	--@alpha@
-	self:debug("adjust queue? spell="..spell);
-	--@end-alpha@
 	if CauldronFrame:IsShown() then
-		--@alpha@
-		self:debug("window is open; self.makingItemSpell="..tostring(self.makingItemSpell));
-		--@end-alpha@
 		if self.makingItemSpell == spell then
 			self.processing = false;

-			--@alpha@
-			self:debug("OnBagUpdate: adjust queue for item: "..self.makingItem.."; itemCount="..self.makingItemCount);
-			--@end-alpha@
 			CauldronQueue:AdjustItemCount(queue, self.makingItem, -1);
 		end
 	end

-	--@alpha@
-	self:debug("OnSpellcastSucceed exit");
-	--@end-alpha@
 end

 function Cauldron:OnSpellcastInterrupt(event, unit, spell, rank)
-	--@alpha@
-	self:debug("OnSpellcastInterrupt enter");
-	--@end-alpha@

 -- self:info("spell interrupt - unit: "..tostring(unit).."; spell: "..tostring(spell).."; rank: "..tostring(rank));

 	self.processing = false;

-	--@alpha@
-	self:debug("OnSpellcastInterrupt exit");
-	--@end-alpha@
 end

 function Cauldron:OnError()
---@alpha@
-	self:debug("OnError enter");
---@end-alpha@

 --	TODO

---@alpha@
-	self:debug("OnError exit");
---@end-alpha@
 end

 function Cauldron:TradeSkillFrame_SetSelection(id)
---@alpha@
-	self:debug("TradeSkillFrame_SetSelection enter");
---@end-alpha@

 	-- TODO

---@alpha@
-	self:debug("TradeSkillFrame_SetSelection exit");
---@end-alpha@
 end

 function Cauldron:GetSelectedSkill()
---@alpha@
-	self:debug("GetSelectedSkill enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -734,18 +580,11 @@ function Cauldron:GetSelectedSkill()
 			return info;
 		end
 	end
-
---@alpha@
-	self:debug("GetSelectedSkill exit");
---@end-alpha@

 	return nil;
 end

 function Cauldron:QueueAllTradeSkillItem()
---@alpha@
-	self:debug("QueueAllTradeSkillItem enter");
---@end-alpha@

 	local skillInfo = Cauldron:GetSelectedSkill();

@@ -777,15 +616,9 @@ function Cauldron:QueueAllTradeSkillItem()
 		end
 	end

---@alpha@
-	self:debug("QueueAllTradeSkillItem exit");
---@end-alpha@
 end

 function Cauldron:QueueTradeSkillItem()
---@alpha@
-	self:debug("QueueTradeSkillItem enter");
---@end-alpha@

 	local skillInfo = Cauldron:GetSelectedSkill();

@@ -802,17 +635,11 @@ function Cauldron:QueueTradeSkillItem()
 		Cauldron:UpdateShoppingListFromQueue();
 	end

---@alpha@
-	self:debug("QueueTradeSkillItem exit");
---@end-alpha@
 end

 function Cauldron:CreateAllTradeSkillItem()
---@alpha@
-	self:debug("CreateAllTradeSkillItem enter");
---@end-alpha@

-	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
+	if (not PartialPlayTime()) and (not NoPlayTime()) then
 		CauldronAmountInputBox:ClearFocus();

 		local skillInfo = Cauldron:GetSelectedSkill();
@@ -822,15 +649,9 @@ function Cauldron:CreateAllTradeSkillItem()
 		DoTradeSkill(skillInfo.index, skillInfo.available);
 	end

---@alpha@
-	self:debug("CreateAllTradeSkillItem exit");
---@end-alpha@
 end

 function Cauldron:CreateTradeSkillItem()
---@alpha@
-	self:debug("CreateTradeSkillItem enter");
---@end-alpha@

 	if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
 		CauldronAmountInputBox:ClearFocus();
@@ -841,13 +662,9 @@ function Cauldron:CreateTradeSkillItem()
 		DoTradeSkill(skillInfo.index, amount);
 	end

---@alpha@
-	self:debug("CreateTradeSkillItem exit");
---@end-alpha@
 end

 function Cauldron:ProcessQueue()
-	self:debug("ProcessQueue enter");

 	if IsTradeSkillLinked() then
 		self:error("Can't process queue for linked tradeskill!");
@@ -870,12 +687,12 @@ function Cauldron:ProcessQueue()

 		-- see if first item can be made
 		queueInfo = queue[1];
-		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
+--		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
 		skillInfo = Cauldron:GetSkillInfo(queueInfo.tradeskill, queueInfo.name);
-		self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));
+--		self:debug("ProcessQueue: skillInfo="..tostring(skillInfo));

 		if skillInfo.available > 0 then
-			self:debug("First item in main queue can be made "..skillInfo.available.." times");
+--			self:debug("First item in main queue can be made "..skillInfo.available.." times");
 			self:SubmitItemToProcess(queueInfo, skillInfo, math.min(skillInfo.available, queueInfo.amount));
 			return;
 --[[		else
@@ -930,11 +747,9 @@ function Cauldron:ProcessQueue()

 	self:SubmitItemToProcess(queueInfo, skillInfo);

-	self:debug("ProcessQueue exit");
 end

 function Cauldron:SubmitItemToProcess(queueInfo, skillInfo, amount)
-	self:debug("SubmitItemToProcess enter");

 	if queueInfo and skillInfo then
 		self:debug("ProcessQueue: queueInfo="..queueInfo.name);
@@ -956,11 +771,9 @@ function Cauldron:SubmitItemToProcess(queueInfo, skillInfo, amount)
 		end
 	end

-	self:debug("SubmitItemToProcess exit");
 end

 function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
-	self:debug("ProcessItem enter");

 	if not skillInfo then
 		self:error("ProcessItem: Missing skill info!");
@@ -980,7 +793,7 @@ function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
 --		self:debug("makingItemId: "..tostring(self.makingItemId));
 		self.itemCurrentCount = GetItemCount(skillInfo.itemLink);

-		self.makingItemSpell = Cauldron:GetNameFromLink(queueInfo.link);
+		self.makingItemSpell = queueInfo.spell or Cauldron:GetNameFromLink(queueInfo.link);
 		self.makingItemCount = amount;
 		self.queueInfo = queueInfo;

@@ -994,7 +807,6 @@ function Cauldron:ProcessItem(skillInfo, queueInfo, amount)
 		-- TODO: notify player?
 	end

-	self:debug("ProcessItem exit");
 end

 function Cauldron:RemoveQueueItem(name)
@@ -1018,9 +830,6 @@ function Cauldron:IncreaseItemCount(name)
 end

 function Cauldron:GetQueue(player)
---@alpha@
-	self:debug("GetQueue enter");
---@end-alpha@

 	if not player then
 		player = self.vars.playername;
@@ -1032,10 +841,6 @@ function Cauldron:GetQueue(player)
 		self.db.realm.userdata[player].queue = queue;
 	end

---@alpha@
-	self:debug("GetQueue enter");
---@end-alpha@
-
 	return queue;
 end

@@ -1084,9 +889,6 @@ end
 ----------------------------------------------------------------

 function Cauldron:HookTooltips()
---@alpha@
-	self:debug("HookTooltips enter");
---@end-alpha@

 	self:SecureHook(GameTooltip, "SetBagItem");
 	self:SecureHook(GameTooltip, "SetInventoryItem");
@@ -1099,9 +901,6 @@ function Cauldron:HookTooltips()
 	self:SecureHook(GameTooltip, "SetGuildBankItem");
 	self:SecureHook("SetItemRef");

---@alpha@
-	self:debug("HookTooltips exit");
---@end-alpha@
 end

 function Cauldron:AddToTooltip(tooltip, id)
diff --git a/CauldronMainUI.lua b/CauldronMainUI.lua
index c3f898b..015d9b0 100644
--- a/CauldronMainUI.lua
+++ b/CauldronMainUI.lua
@@ -8,24 +8,14 @@ local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")
 local SLOT_NONE = "none";

 function Cauldron:Frame_Show()
-	--@alpha@
- 	self:debug("Frame_Show enter");
-	--@end-alpha@

 	if Cauldron.vars.enabled and not(IsShiftKeyDown() and IsControlKeyDown()) then
-		--@alpha@
-	 	self:debug("Frame_Show: close dropdown menus");
-		--@end-alpha@
  		CloseDropDownMenus();

 		if TradeSkillFrame then
 			-- place our frame over the original frame
 --			CauldronFrame:SetPoint("TOPLEFT", TradeSkillFrame:GetLeft(), TradeSkillFrame:GetTop());

-			--@alpha@
-			self:debug("Frame_Show: hide the original tradeskill frame");
-			--@end-alpha@
-
 			-- hide the original tradeskill frame
 			if not Cauldron.vars.origFrameStrata then
 				Cauldron.vars.origFrameStrata = TradeSkillFrame:GetFrameStrata();
@@ -62,29 +52,17 @@ function Cauldron:Frame_Show()
 		CauldronProcessButton:SetText(L["Process"]);
 		CauldronClearQueueButton:SetText(L["Clear Queue"]);

-		--@alpha@
-	 	self:debug("Frame_Show: show our frame");
-		--@end-alpha@
  		ShowUIPanel(CauldronFrame);
 -- 		tinsert(UISpecialFrames, CauldronFrame:GetName());

 	 	self:RegisterMessage("Cauldron_Update", "OnCauldronUpdate");

-		--@alpha@
- 		self:debug("Frame_Show: call Frame_Update()");
-		--@end-alpha@
 		self:Frame_Update();
 	end

-	--@alpha@
- 	self:debug("Frame_Show exit");
-	--@end-alpha@
 end

 function Cauldron:Frame_Hide()
-	--@alpha@
- 	self:debug("Frame_Hide enter");
-	--@end-alpha@

  	self:UnregisterEvent("Cauldron_Update")
  	HideUIPanel(CauldronFrame);
@@ -95,37 +73,19 @@ function Cauldron:Frame_Hide()
  		TradeSkillFrame:SetFrameLevel(Cauldron.vars.origFrameLevel or 5);
  	end

-	--@alpha@
- 	self:debug("Frame_Hide exit");
-	--@end-alpha@
 end

 function Cauldron:Frame_Toggle()
-	--@alpha@
- 	self:debug("Frame_Toggle enter");
-	--@end-alpha@

  	if CauldronFrame:IsVisible() then
-		--@alpha@
-		self:debug("Frame_Toggle: call Frame_Hide()");
-		--@end-alpha@
  		Cauldron:Frame_Hide();
  	else
-		--@alpha@
-		self:debug("Frame_Toggle: call Frame_Show()");
-		--@end-alpha@
  		Cauldron:Frame_Show();
  	end

-	--@alpha@
- 	self:debug("Frame_Toggle exit");
-	--@end-alpha@
 end

 function Cauldron:Frame_Update()
-	--@alpha@
- 	self:debug("Frame_Update enter");
-	--@end-alpha@

 	local numTradeSkills = GetNumTradeSkills();
 	local name, rank, maxRank = GetTradeSkillLine();
@@ -137,13 +97,10 @@ function Cauldron:Frame_Update()
 	Cauldron:UpdateSkills();

 	if CURRENT_TRADESKILL ~= name then
-		--@alpha@
-		self:debug("Frame_Update: current skill changed");
-		--@end-alpha@

 		StopTradeSkillRepeat();

-		if ( CURRENT_TRADESKILL ~= "" ) then
+		if CURRENT_TRADESKILL ~= "" then
 			-- To fix problem with switching between two tradeskills
 --			UIDropDownMenu_Initialize(TradeSkillInvSlotDropDown, TradeSkillInvSlotDropDown_Initialize);
 --			UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, 1);
@@ -155,44 +112,23 @@ function Cauldron:Frame_Update()
 	end

 	-- display skill name, level/progress
-	--@alpha@
-	self:debug("Frame_Update: display skill level/progress");
-	--@end-alpha@
 	self:UpdateSkillInfo(name, rank, maxRank);

 	-- update search text box
-	--@alpha@
-	self:debug("Frame_Update: display search text");
-	--@end-alpha@
 	self:UpdateSearchText();

 	-- TODO: update dropdowns
-	--@alpha@
-	self:debug("Frame_Update: update dropdowns");
-	--@end-alpha@
 	self:UpdateFilterDropDowns();

 	-- display list of matching skills
-	--@alpha@
-	self:debug("Frame_Update: display list of skills");
-	--@end-alpha@
 	self:UpdateSkillList();

 	-- display queue
-	--@alpha@
-	self:debug("Frame_Update: display queue");
-	--@end-alpha@
 	self:UpdateQueue();

 	-- update buttons
-	--@alpha@
-	self:debug("Frame_Update: update buttons");
-	--@end-alpha@
 	self:UpdateButtons();

-	--@alpha@
- 	self:debug("Frame_Update exit");
-	--@end-alpha@
 end

 function Cauldron:UpdateSkillInfo(skillName, rank, maxRank)
@@ -215,15 +151,9 @@ function Cauldron:UpdateSkillInfo(skillName, rank, maxRank)
 	CauldronRankFrame:SetValue(rank);
 	CauldronRankFrameSkillRank:SetText(rank.."/"..maxRank);

---@alpha@
-	self:debug("UpdateSkillInfo exit");
---@end-alpha@
 end

 function Cauldron:UpdateSearchText()
---@alpha@
-	self:debug("UpdateSearchText enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -243,25 +173,17 @@ function Cauldron:UpdateSearchText()
 	end
 	CauldronFiltersSearchEditBox:SetText(searchText);

---@alpha@
-	self:debug("UpdateSearchText exit");
---@end-alpha@
 end

 function Cauldron:UpdateFilterDropDowns()
---@alpha@
-	self:debug("UpdateFilterDropDowns enter");
---@end-alpha@

---@alpha@
-	self:debug("UpdateFilterDropDowns exit");
---@end-alpha@
+	-- TODO
+
 end

 function Cauldron:UpdateSkillList()
-	--@alpha@
-	self:debug("UpdateSkillList enter");
-	--@end-alpha@
+
+	Cauldron:info("Updating skill list: "..debugstack());

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -272,17 +194,11 @@ function Cauldron:UpdateSkillList()
 	if not skillList then
 		return;
 	end
-	--@alpha@
-	self:debug("UpdateSkillList: skillList="..#skillList);
-	--@end-alpha@

 	local height = 0;

 	-- iterate over the list of skills
 	for i, skillInfo in ipairs(skillList) do
-		--@alpha@
-		self:debug("UpdateSkillList: i="..i);
-		--@end-alpha@

 		local skillFrame = _G["CauldronSkillItem"..i];

@@ -416,13 +332,7 @@ function Cauldron:UpdateSkillList()
 		-- set the disclosure button texture
 		frame = _G["CauldronSkillItem"..i.."DiscloseButton"];
 		frame.skillInfo = skillInfo;
---@alpha@
-		self:debug("UpdateSkillList: skillInfo.name="..skillInfo.name);
---@end-alpha@
 		local reagentsExpanded = self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
---@alpha@
-		self:debug("UpdateSkillList: reagentsExpanded="..tostring(reagentsExpanded));
---@end-alpha@
 		if reagentsExpanded then
 			frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");

@@ -432,18 +342,10 @@ function Cauldron:UpdateSkillList()
 			local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
 			local toolsFrame = _G["CauldronSkillItem"..i.."ReagentsToolsInfo"];
 			if spellFocus then
---@alpha@
-				self:debug("UpdateSkillList: skill has a spell focus");
---@end-alpha@
-
 				toolsFrame:Show();
 				toolsFrame:SetText(L["Requires"]..": "..spellFocus);
 				toolsFrame:SetHeight(15);
 			else
---@alpha@
-				self:debug("UpdateSkillList: skill doesn't have a spell focus");
---@end-alpha@
-
 				toolsFrame:Hide();
 				toolsFrame:SetText("");
 				toolsFrame:SetHeight(0);
@@ -470,6 +372,12 @@ function Cauldron:UpdateSkillList()

 					local reagentNameFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Name"];
 					local reagentCountFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Count"];
+
+					-- PARANOIA: check if the reagent name, icon, or link are missing
+					if not reagentInfo.name or not reagentInfo.icon or not reagentInfo.link then
+						Cauldron:error("Reagent info missing; marking recipe for rescan: "..skillInfo.name);
+						Cauldron:MarkRecipeForRescan(self.db.realm.userdata[self.vars.playername].skills[skillName], skillInfo.name);
+					end

 					reagentFrame:Show();
 					SetItemButtonTexture(reagentFrame, reagentInfo.icon);
@@ -478,7 +386,7 @@ function Cauldron:UpdateSkillList()
 					local playerReagentCount = GetItemCount(reagentInfo.name);

 					if playerReagentCount < reagentInfo.numRequired then
-						-- Grayout items
+						-- Gray out items
 						SetItemButtonTextureVertexColor(reagentFrame, 0.5, 0.5, 0.5);
 						reagentNameFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
 					else
@@ -505,29 +413,17 @@ function Cauldron:UpdateSkillList()
 		-- place the frame in the scroll view
 		if i > 1 then
 			-- anchor to the frame above
---@alpha@
-			self:debug("UpdateSkillList: anchor frame to top left of frame above");
---@end-alpha@
 			skillFrame:SetPoint("TOPLEFT", _G["CauldronSkillItem"..(i-1)], "BOTTOMLEFT", 0, -2);
 		else
 			-- anchor to the parent
---@alpha@
-			self:debug("UpdateSkillList: anchor frame to parent");
---@end-alpha@
 			skillFrame:SetPoint("TOPLEFT", 0, 0);
 		end

 		-- adjust the scroll child size
 		height = height + skillFrame:GetHeight();
---@alpha@
-		self:debug("UpdateSkillList: height="..height);
---@end-alpha@
 		CauldronSkillListFrameScrollFrameScrollChild:SetHeight(height);

 		-- show the frame
---@alpha@
-		self:debug("UpdateSkillList: show the frame");
---@end-alpha@
 		skillFrame:Show();
 	end

@@ -545,15 +441,9 @@ function Cauldron:UpdateSkillList()
 		j = j + 1;
 	end

---@alpha@
-	self:debug("UpdateSkillList exit");
---@end-alpha@
 end

 function Cauldron:UpdateButtons()
---@alpha@
-	self:debug("UpdateButtons enter");
---@end-alpha@

 	if IsTradeSkillLinked() then
 		CauldronQueueAllButton:Hide();
@@ -615,15 +505,9 @@ function Cauldron:UpdateButtons()
 		end
 	end

---@alpha@
-	self:debug("UpdateButtons exit");
---@end-alpha@
 end

 function Cauldron:UpdateQueue()
-	--@alpha@
-	self:debug("UpdateQueue enter");
-	--@end-alpha@

 	if (not CauldronFrame) or (not CauldronFrame:IsShown()) then
 		return;
@@ -638,10 +522,6 @@ function Cauldron:UpdateQueue()
 	end

 	if #itemQueue == 0 then
-		--@alpha@
-		self:debug("UpdateQueue: display empty queue");
-		--@end-alpha@
-
 		-- queue is empty, display the empty message
 		CauldronQueueFrameQueueEmpty:Show();
 		CauldronQueueFrameScrollFrame:Hide();
@@ -655,10 +535,6 @@ function Cauldron:UpdateQueue()
 		return;
 	end

-	--@alpha@
-	self:debug("UpdateQueue: display queue");
-	--@end-alpha@
-
 	-- queue has items, show them
 	CauldronQueueFrameQueueEmpty:Hide();
 	CauldronQueueFrameScrollFrame:Show();
@@ -669,16 +545,9 @@ function Cauldron:UpdateQueue()

 	CauldronQueueFrameScrollFrameQueueSectionsMainItemsHeaderText:SetText(L["In order to make:"]);
 	-- adjust the scroll child size
-	--@alpha@
-	self:debug("set main section height for "..#itemQueue.." items: "..(#itemQueue * itemFrameHeight));
-	--@end-alpha@
 	CauldronQueueFrameScrollFrameQueueSectionsMainItems:SetHeight(#itemQueue * itemFrameHeight);

 	for i, queueInfo in ipairs(itemQueue) do
-		--@alpha@
-		self:debug("queueInfo: name="..queueInfo.name);
-		--@end-alpha@
-
 		local queueItemFrame = _G["CauldronQueueItem"..i];
 		self:debug("queueItemFrame: "..tostring(queueItemFrame));

@@ -729,9 +598,6 @@ function Cauldron:UpdateQueue()

 		-- set name and difficulty color
 		frame = _G["CauldronQueueItem"..i.."ItemName"];
-		--@alpha@
-		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
-		--@end-alpha@
 		local nameText = queueInfo.name;
 		if skillInfo and (skillInfo.available > 0) then
 			nameText = nameText.." ["..skillInfo.available.."]";
@@ -753,9 +619,6 @@ function Cauldron:UpdateQueue()

 		-- set quantity info
 		frame = _G["CauldronQueueItem"..i.."Info"];
-		--@alpha@
-		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
-		--@end-alpha@
 		local infoText = queueInfo.tradeskill;
 		-- TODO: alts/bank/etc.
 		frame:SetText(infoText);
@@ -764,31 +627,19 @@ function Cauldron:UpdateQueue()

 		-- set the icon
 		frame = _G["CauldronQueueItem"..i.."Icon"];
---@alpha@
-		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
---@end-alpha@
 		frame:SetNormalTexture(queueInfo.icon);
 		frame.link = queueInfo.link;

 		-- set the amount
 		frame = _G["CauldronQueueItem"..i.."IconCount"];
---@alpha@
-		self:debug("frame: "..tostring(frame).." ("..frame:GetName()..")");
---@end-alpha@
 		frame:SetText(queueInfo.amount);

 		-- place the frame in the scroll view
 		if i > 1 then
 			-- anchor to the frame above
---@alpha@
-			self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 		else
 			-- anchor to the parent
---@alpha@
-			self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsMainItems, "TOPLEFT", 0, 0);
 		end

@@ -796,9 +647,6 @@ function Cauldron:UpdateQueue()
 --		self:debug("UpdateQueue: height="..height);

 		-- show the frame
---@alpha@
-		self:debug("UpdateQueue: show the frame");
---@end-alpha@
 		queueItemFrame:Show();
 	end

@@ -831,9 +679,6 @@ function Cauldron:UpdateQueue()

 	-- display intermediate queue, maybe
 	if #intQueue == 0 then
---@alpha@
-		self:debug("UpdateQueue: intermediate queue is empty, hide header and item frames");
---@end-alpha@
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeader:SetHeight(1);
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItemsHeaderText:SetText("");
 		CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(1);
@@ -845,11 +690,7 @@ function Cauldron:UpdateQueue()

 		local intHeight = 0;

-		for i, queueInfo in ipairs(intQueue) do
---@alpha@
-			self:debug("intQueue: name="..queueInfo.name);
---@end-alpha@
-
+		for i, queueInfo in ipairs(intQueue) do
 			local queueItemFrame = _G["CauldronQueueIntItem"..i];

 			-- check if we have a frame for this position
@@ -949,15 +790,9 @@ function Cauldron:UpdateQueue()
 			-- place the frame in the scroll view
 			if i > 1 then
 				-- anchor to the frame above
---@alpha@
-				self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
 				queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueIntItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 			else
 				-- anchor to the parent
---@alpha@
-				self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
 				queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems, "TOPLEFT", 0, 0);
 			end

@@ -967,9 +802,6 @@ function Cauldron:UpdateQueue()
 --			CauldronQueueFrameScrollFrameQueueSectionsSecondaryItems:SetHeight(intHeight);

 			-- show the frame
---@alpha@
-			self:debug("UpdateQueue: show the frame");
---@end-alpha@
 			queueItemFrame:Show();
 		end
 	end
@@ -1002,10 +834,6 @@ function Cauldron:UpdateQueue()
 	local reagentHeight = 0;

 	for i, queueInfo in ipairs(reagentList) do
---@alpha@
-		self:debug("reagentList: "..queueInfo.name);
---@end-alpha@
-
 		local queueItemFrame = _G["CauldronQueueReagentItem"..i];

 		-- check if we have a frame for this position
@@ -1098,15 +926,9 @@ function Cauldron:UpdateQueue()
 		-- place the frame in the scroll view
 		if i > 1 then
 			-- anchor to the frame above
---@alpha@
-			self:debug("UpdateQueue: anchor frame to top left of frame above");
---@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", _G["CauldronQueueReagentItem"..(i-1)], "BOTTOMLEFT", 0, 0);
 		else
 			-- anchor to the parent
---@alpha@
-			self:debug("UpdateQueue: anchor frame to parent");
---@end-alpha@
 			queueItemFrame:SetPoint("TOPLEFT", CauldronQueueFrameScrollFrameQueueSectionsReagents, "TOPLEFT", 0, 0);
 		end

@@ -1116,9 +938,6 @@ function Cauldron:UpdateQueue()
 --		CauldronQueueFrameScrollFrameQueueSectionsReagents:SetHeight(reagentHeight);

 		-- show the frame
---@alpha@
-		self:debug("UpdateQueue: show the frame");
---@end-alpha@
 		queueItemFrame:Show();
 	end

@@ -1152,27 +971,15 @@ function Cauldron:UpdateQueue()
 	CauldronQueueFrameScrollFrameQueueSections:SetHeight(h);
 	CauldronQueueFrameScrollFrame:UpdateScrollChildRect();

---@alpha@
-	self:debug("UpdateQueue exit");
---@end-alpha@
 end

 function Cauldron:SaveFramePosition()
---@alpha@
- 	self:debug("SaveFramePosition enter");
---@end-alpha@

 -- TODO

---@alpha@
- 	self:debug("SaveFramePosition exit");
---@end-alpha@
 end

 function Cauldron:OnCauldronUpdate()
---@alpha@
-	self:debug("OnCauldronUpdate enter");
---@end-alpha@

 	--[[
 --	self:Search();
@@ -1184,15 +991,9 @@ function Cauldron:OnCauldronUpdate()
  	end
  	--]]

---@alpha@
-	self:debug("OnCauldronUpdate exit");
---@end-alpha@
 end

 function Cauldron:FilterDropDown_OnLoad(dropdown)
---@alpha@
-	self:debug("FilterDropDown_OnLoad enter");
---@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1203,15 +1004,9 @@ function Cauldron:FilterDropDown_OnLoad(dropdown)
 	UIDropDownMenu_Initialize(dropdown, Cauldron.FilterDropDown_Initialize);
 	UIDropDownMenu_SetText(CauldronFiltersFilterDropDown, L["Filters"]);

---@alpha@
-	self:debug("FilterDropDown_OnLoad exit");
---@end-alpha@
 end

 function Cauldron:InvSlotDropDown_OnLoad(dropdown)
---@alpha@
-	self:debug("InvSlotDropDown_OnLoad enter");
---@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1222,15 +1017,9 @@ function Cauldron:InvSlotDropDown_OnLoad(dropdown)
 	UIDropDownMenu_Initialize(dropdown, Cauldron.InvSlotDropDown_Initialize);
 	UIDropDownMenu_SetText(CauldronFiltersInvSlotDropDown, L["Slots"]);

---@alpha@
-	self:debug("InvSlotDropDown_OnLoad exit");
---@end-alpha@
 end

 function Cauldron:CategoryDropDown_OnLoad(dropdown)
---@alpha@
-	self:debug("CategoryDropDown_OnLoad enter");
---@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1241,15 +1030,9 @@ function Cauldron:CategoryDropDown_OnLoad(dropdown)
 	UIDropDownMenu_Initialize(dropdown, Cauldron.CategoryDropDown_Initialize);
 	UIDropDownMenu_SetText(CauldronFiltersCategoryDropDown, L["Categories"]);

---@alpha@
-	self:debug("CategoryDropDown_OnLoad exit");
---@end-alpha@
 end

 function Cauldron:FilterDropDown_Initialize(level)
---@alpha@
-	Cauldron:debug("FilterDropDown_Initialize enter");
---@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1576,9 +1359,6 @@ function Cauldron:FilterDropDown_Initialize(level)

 	end

---@alpha@
-	Cauldron:debug("FilterDropDown_Initialize exit");
---@end-alpha@
 end

 function Cauldron:FilterDropDown_Reset()
@@ -1615,9 +1395,6 @@ function Cauldron:FilterDropDown_Reset()
 end

 function Cauldron:FilterDropDown_SetSort(info)
---@alpha@
-	self:debug("FilterDropDown_SetSort enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -1687,15 +1464,9 @@ function Cauldron:FilterDropDown_SetSort(info)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("FilterDropDown_SetSort exit");
---@end-alpha@
 end

 function Cauldron:ReagentsFilterNormalCheck()
---@alpha@
-	self:debug("ReagentsFilterNormalCheck enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -1709,18 +1480,11 @@ function Cauldron:ReagentsFilterNormalCheck()
 	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents then
 	   	checked = false;
 	end
-
---@alpha@
-	self:debug("ReagentsFilterNormalCheck exit");
---@end-alpha@
-
+
 	return checked;
 end

 function Cauldron:FilterDropDown_SetReagentFilter(info)
---@alpha@
-	self:debug("FilterDropDown_SetReagentFilter enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -1750,15 +1514,9 @@ function Cauldron:FilterDropDown_SetReagentFilter(info)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("FilterDropDown_SetReagentFilter exit");
---@end-alpha@
 end

 function Cauldron:FilterDropDown_ToggleDifficulty(info)
---@alpha@
-	self:debug("FilterDropDown_ToggleDifficulty enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -1770,9 +1528,6 @@ function Cauldron:FilterDropDown_ToggleDifficulty(info)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("FilterDropDown_ToggleDifficulty exit");
---@end-alpha@
 end

 function Cauldron:InvSlotDropDown_Initialize(level)
@@ -1894,9 +1649,6 @@ function Cauldron:InvSlotDropDown_SetSlot(info)
 end

 function Cauldron:CategoryDropDown_Initialize(level)
---@alpha@
-	Cauldron:debug("CategoryDropDown_Initialize enter");
---@end-alpha@

 --[[
 	if CURRENT_TRADESKILL == "" or CURRENT_TRADESKILL == "UNKNOWN" then
@@ -1953,9 +1705,6 @@ function Cauldron:CategoryDropDown_Initialize(level)
 		UIDropDownMenu_AddButton(category);
 	end

---@alpha@
-	Cauldron:debug("CategoryDropDown_Initialize exit");
---@end-alpha@
 end

 --[[
@@ -1983,9 +1732,6 @@ end
 --]]

 function Cauldron:CategoryDropDown_SetCategory(info)
---@alpha@
-	self:debug("CategoryDropDown_SetCategory enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -2014,15 +1760,9 @@ function Cauldron:CategoryDropDown_SetCategory(info)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("CategoryDropDown_SetCategory exit");
---@end-alpha@
 end

 function Cauldron:CollapseAllButton_OnClick(button)
---@alpha@
-	self:debug("CollapseAllButton_OnClick enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -2061,15 +1801,9 @@ function Cauldron:CollapseAllButton_OnClick(button)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("CollapseAllButton_OnClick exit");
---@end-alpha@
 end

 function Cauldron:CollapseItemButton_OnClick(button)
---@alpha@
-	self:debug("CollapseItemButton_OnClick enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -2084,20 +1818,11 @@ function Cauldron:CollapseItemButton_OnClick(button)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("CollapseItemButton_OnClick exit");
---@end-alpha@
 end

 function Cauldron:SkillItem_OnEnter(frame)
---@alpha@
-	self:debug("SkillItem_OnEnter enter");
---@end-alpha@

 	local id = frame:GetID();
---@alpha@
-	self:debug("SkillItem_OnEnter: id="..id);
---@end-alpha@

 	local name = _G["CauldronSkillItem"..id.."SkillName"];
 	if name then
@@ -2106,35 +1831,20 @@ function Cauldron:SkillItem_OnEnter(frame)

 	-- TODO

---@alpha@
-	self:debug("SkillItem_OnEnter exit");
---@end-alpha@
 end

 function Cauldron:SkillItem_OnLeave(frame)
---@alpha@
-	self:debug("SkillItem_OnLeave enter");
---@end-alpha@
-

+-- TODO

---@alpha@
-	self:debug("SkillItem_OnLeave exit");
---@end-alpha@
 end

 function Cauldron:SkillItem_OnClick(frame, button, down)
---@alpha@
-	self:debug("SkillItem_OnClick enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
 		skillName = "Linked-"..skillName;
 	end
---@alpha@
-	self:debug("SkillItem_OnClick: skillName="..skillName);
---@end-alpha@

 	-- select this frame
 	if frame.skillIndex then
@@ -2145,15 +1855,9 @@ function Cauldron:SkillItem_OnClick(frame, button, down)
 	Cauldron:UpdateSkillList();
 	Cauldron:UpdateButtons();

---@alpha@
-	self:debug("SkillItem_OnClick exit");
---@end-alpha@
 end

 function Cauldron:TradeSkillFilter_OnTextChanged(frame)
---@alpha@
-	self:debug("TradeSkillFilter_OnTextChanged enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -2177,43 +1881,25 @@ function Cauldron:TradeSkillFilter_OnTextChanged(frame)
 	-- update the UI
 	Cauldron:UpdateSkillList();

---@alpha@
-	self:debug("TradeSkillFilter_OnTextChanged exit");
---@end-alpha@
 end

 function Cauldron:AmountDecrement_OnClick()
---@alpha@
-	self:debug("AmountDecrement_OnClick enter");
---@end-alpha@

 	local num = CauldronAmountInputBox:GetNumber();
 	num = math.max(1, num - 1);
 	CauldronAmountInputBox:SetNumber(num);

---@alpha@
-	self:debug("AmountDecrement_OnClick exit");
---@end-alpha@
 end

 function Cauldron:AmountIncrement_OnClick()
---@alpha@
-	self:debug("AmountIncrement_OnClick enter");
---@end-alpha@

 	local num = CauldronAmountInputBox:GetNumber();
 	num = math.min(999, num + 1);
 	CauldronAmountInputBox:SetNumber(num);

---@alpha@
-	self:debug("AmountIncrement_OnClick exit");
---@end-alpha@
 end

 function Cauldron:FavoriteItemButton_OnClick(button)
---@alpha@
-	self:debug("FavoriteItemButton_OnClick enter");
---@end-alpha@

 	local skillName = CURRENT_TRADESKILL;
 	if IsTradeSkillLinked() then
@@ -2224,9 +1910,6 @@ function Cauldron:FavoriteItemButton_OnClick(button)

 	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite = button:GetChecked();

---@alpha@
-	self:debug("FavoriteItemButton_OnClick exit");
---@end-alpha@
 end

 function Cauldron:ConfirmDialog(title, message, okayBtn, okayBtnCB, cancelBtn, cancelBtnCB)
diff --git a/CauldronQueue.lua b/CauldronQueue.lua
index e426d2b..e0f66c5 100644
--- a/CauldronQueue.lua
+++ b/CauldronQueue.lua
@@ -39,7 +39,7 @@ function CauldronQueue:NewQueue()
 	return queue;
 end

-function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link)
+function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link, spell)

 	local queueItem = {
 		["name"] = name or "",
@@ -48,6 +48,7 @@ function CauldronQueue:NewItem(name, icon, amount, priority, tradeskill, link)
 		["link"] = link,
 		["amount"] = amount or 1,
 		["priority"] = priority or 0,
+		["spell"] = spell,
 	};

 	return queueItem;
@@ -162,7 +163,7 @@ function CauldronQueue:AddItem(queue, skillInfo, amount, suppressCalc)
 		item.amount = item.amount + amount;
 	else
 		-- it's not there, so create a new instance
-		queue.main[skillInfo.name] = CauldronQueue:NewItem(skillInfo.name, skillInfo.icon, amount, nil, skillInfo.tradeskill, skillInfo.itemLink);
+		queue.main[skillInfo.name] = CauldronQueue:NewItem(skillInfo.name, skillInfo.icon, amount, nil, skillInfo.tradeskill, skillInfo.itemLink, Cauldron:GetNameFromLink(skillInfo.recipeLink));
 	end

 	if not suppressCalc then
@@ -251,7 +252,13 @@ function CauldronQueue:CalculateRequiredItems(queue, skillInfo, amount, priority
 	end

 	for i, reagent in ipairs(reagents) do
-		CauldronQueue:AddReagent(queue, reagent, reagent.numRequired, skillInfo.tradeskill, reagent.link);
+		local v = CauldronQueue:AddReagent(queue, reagent, reagent.numRequired, skillInfo.tradeskill, reagent.link);
+
+		if not v then
+			Cauldron:error("Failed to add reagent to queue; marking recipe for rescan: "..skillInfo.name);
+			Cauldron:MarkRecipeForRescan(Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[tradeskill], skillInfo.name);
+		end
+
 	end

 end
@@ -261,7 +268,7 @@ function CauldronQueue:AddIntermediate(queue, reagent, amount, priority)
 	-- sanity checks
 	if not queue then
 		Cauldron:error("AddIntermediate: No queue found!");
-		return;
+		return false;
 	end

 	amount = math.max(0, tonumber(amount) or 0);
@@ -280,18 +287,21 @@ function CauldronQueue:AddIntermediate(queue, reagent, amount, priority)
 		if reagent.name then
 			local skillInfo = Cauldron:GetSkillInfoForItem(reagent.name);
 			if skillInfo then
-				local newItem = CauldronQueue:NewItem(reagent.name, reagent.icon, amount, nil, skillInfo.tradeskill, reagent.link);
+				local newItem = CauldronQueue:NewItem(reagent.name, reagent.icon, amount, nil, skillInfo.tradeskill, reagent.link, Cauldron:GetNameFromLink(skillInfo.recipeLink));
 				newItem.priority = priority or 0;
 				queue.intermediate[reagent.name] = newItem;
 			else
 				Cauldron:error("AddIntermediate: no skill info found for reagent: "..reagent.name);
+				return false;
 			end
 		else
 			-- this shouldn't occur unless there's something wrong with the reagent info, but if it does, the user can report this error
 			Cauldron:error("AddIntermediate: reagent.name is nil!  Please report this.  (skillIndex: "..reagent.skillIndex..", index: "..reagent.index..")");
+			return false;
 		end
 	end

+	return true;
 end

 function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill)
@@ -299,7 +309,7 @@ function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill)
 	-- sanity checks
 	if not queue then
 		Cauldron:error("AddReagent: No queue found!");
-		return;
+		return false;
 	end

 	amount = math.max(1, tonumber(amount) or 1);
@@ -320,9 +330,11 @@ function CauldronQueue:AddReagent(queue, reagent, amount, tradeskill)
 		else
 			-- this shouldn't occur unless there's something wrong with the reagent info, but if it does, the user can report this error
 			Cauldron:error("AddReagent: reagent.name is nil!");
+			return false;
 		end
 	end

+	return true;
 end

 function CauldronQueue:AdjustItemCount(queue, name, delta)
diff --git a/CauldronTradeskill.lua b/CauldronTradeskill.lua
index 9c64ecd..4a9b072 100644
--- a/CauldronTradeskill.lua
+++ b/CauldronTradeskill.lua
@@ -117,7 +117,7 @@ function Cauldron:UpdateSkills()
 					Cauldron:Print(msg);

 					-- remove it from the list (we're optimistic!)
-					skillDB.rescan.failedRecipes[name] = false;
+					skillDB.rescan.failedRecipes[name] = nil;
 				end

 				-- add the recipe info and other miscellaneous info
@@ -171,9 +171,9 @@ function Cauldron:UpdateSkills()
 				-- populate the slot list
 				Cauldron:debug("slot: "..tostring(slot));
 				if slot and (slot ~= "") then
-						skillDB.window.slots[slot] = {
-							checked = true,
-						};
+					skillDB.window.slots[slot] = {
+						checked = true,
+					};
 				else
 					-- special slot representing items that don't have a slot
 					skillDB.window.slots.none = {
@@ -194,15 +194,8 @@ function Cauldron:UpdateSkills()

 						-- store the info if it's not already from rescanning
 						if not rescan then
-							-- store rescan info
-							if not skillDB.rescan then
-								skillDB.rescan = {
-									failedRecipes = {},
-								};
-							end
-
-							-- record the failed recipe
-							skillDB.rescan.failedRecipes[name] = true;
+							Cauldron:error("Failed to retrieve reagent info; marking recipe for rescan: "..name);
+							Cauldron:MarkRecipeForRescan(skillDB, name);
 						end

 						--[[
@@ -480,6 +473,9 @@ function Cauldron:GetSkillList(playername, skillName)
 			if (not r1) or (not r2) then
 				return true;
 			end
+			if not r1.name or not r2.name then
+				return true;
+			end

 			--@alpha@
 			self:debug("GetSkillList: sorting: r1.name="..r1.name.."; r2.name="..r2.name);
@@ -539,8 +535,8 @@ function Cauldron:GetSkillList(playername, skillName)
 				self:debug("GetSkillList: sorting by favorites");
 				--@end-alpha@

-				local r1f = self.db.realm.userdata[playername].skills[skillName].window.skills[r1.name].favorite and 100 or 1;
-				local r2f = self.db.realm.userdata[playername].skills[skillName].window.skills[r2.name].favorite and 100 or 1;
+				local r1f = (self.db.realm.userdata[playername].skills[skillName].window.skills[r1.name].favorite and 100) or 1;
+				local r2f = (self.db.realm.userdata[playername].skills[skillName].window.skills[r2.name].favorite and 100) or 1;

 				return r2f < r1f;
 			elseif self.db.realm.userdata[playername].skills[skillName].window.filter.sortBenefit then
diff --git a/CauldronUtil.lua b/CauldronUtil.lua
index 3812264..6330d90 100644
--- a/CauldronUtil.lua
+++ b/CauldronUtil.lua
@@ -300,3 +300,15 @@ end
 function Cauldron:GetAutoBuy()
 	return Cauldron.db.realm.userdata[Cauldron.vars.playername].options.autoBuy;
 end
+
+function Cauldron:MarkRecipeForRescan(skillDB, name)
+	-- store rescan info
+	if not skillDB.rescan then
+		skillDB.rescan = {
+			failedRecipes = {},
+		};
+	end
+
+	-- record the failed recipe
+	skillDB.rescan.failedRecipes[name] = true;
+end