Quantcast
-- $Revision: 213 $
-- Cauldron main user interface logic

CAULDRON_SKILLITEM_COLLAPSED_HEIGHT = 37;
CAULDRON_SKILLITEM_EXPANDED_HEIGHT = 100;
CAULDRON_SKILL_LIST_MAX = 50;

CAULDRON_TRADESKILL_NAME = CURRENT_TRADESKILL;

local L = LibStub("AceLocale-3.0"):GetLocale("Cauldron")

-- CauldronUI = LibStub("AceAddon-3.0"):NewAddon("CauldronUI", "AceEvent-3.0", "AceConsole-3.0", "LibDebugLog-1.0")

local SLOT_NONE = "none";

function Cauldron:Frame_Show()

	if Cauldron.vars.enabled and not(IsShiftKeyDown() and IsControlKeyDown()) then

		-- show main UI
		ShowUIPanel(CauldronFrame);
		SetPortraitToTexture(CauldronFramePortrait, GetTradeSkillTexture());
		CauldronInputBox:SetNumber(1);
		CauldronFrameTitleText:SetText(L["Cauldron"] --[[.." "..Cauldron.version--]]);

		-- show queue UI
		if Cauldron.vars.showQueue and not(IsTradeSkillLinked() or IsTradeSkillGuild()) then
			ShowUIPanel(CauldronQueueWindowFrame);
			SetPortraitToTexture(CauldronQueueWindowFramePortrait, GetTradeSkillTexture());
			CauldronQueueWindowFrameTitleText:SetText(L["Queue"]);
		end

		-- check if the filter structure is out of date
		--[[
		if not Cauldron.db.global.version or (tonumber(Cauldron.db.global.version) < tonumber(Cauldron.vars.filterVersion)) then
			Cauldron.db.global.version = tonumber(Cauldron.vars.filterVersion);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter = {
				-- sorting
				sortDefault = true,
				sortAlpha = false,
				sortDifficulty = false,
				sortBenefit = false,

				-- difficulty
				optimal = true,
				medium = true,
				easy = true,
				trivial = true,

				-- favorites
				favorites = false,
				favoritesAtTop = false,

				-- availability
				haveAllReagents = false,
				haveKeyReagents = false,
				haveAnyReagents = false,
			};
		end
		--]]

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

		Cauldron.needsRedraw = true;
		self:Frame_Update();

		self:RegisterEvent("TRADE_SKILL_UPDATE", "OnSkillUpdate");
		self:RegisterEvent("SKILL_LINES_CHANGED", "OnSkillUpdate");
		self:RegisterEvent("UNIT_PORTRAIT_UPDATE", "OnEvent");
		self:RegisterEvent("BAG_UPDATE", "OnBagUpdate");
	else
		-- show the Blizzard frame
		Cauldron.blizzTradeSkillShow();
	end

end

function Cauldron:Frame_Hide()

-- 	self:UnregisterEvent("Cauldron_Update");
 	HideUIPanel(CauldronQueueWindowFrame);
 	HideUIPanel(CauldronFrame);

 	--[[
 	if TradeSkillFrame then
 		TradeSkillFrame:SetAlpha(1.0);
 		TradeSkillFrame:SetFrameStrata(Cauldron.vars.origFrameStrata or "MEDIUM");
 		TradeSkillFrame:SetFrameLevel(Cauldron.vars.origFrameLevel or 5);
 	end
 	--]]

-- 	CloseTradeSkill();

	self:UnregisterEvent("TRADE_SKILL_UPDATE");
	self:UnregisterEvent("SKILL_LINES_CHANGED");
	self:UnregisterEvent("UNIT_PORTRAIT_UPDATE");
	self:UnregisterEvent("BAG_UPDATE");

end

function Cauldron:Frame_Toggle()

 	if CauldronQueueWindowFrame:IsVisible() then
 		Cauldron:Frame_Hide();
 	else
 		Cauldron:Frame_Show();
 	end

end

function CauldronFrame_Update()
	Cauldron.needsRedraw = true;
	Cauldron:Frame_Update();
end

function Cauldron:Frame_Update()

	local numTradeSkills = GetNumTradeSkills();
	local name, rank, maxRank = GetTradeSkillLine();

	if name == "UNKNOWN" then
		return;
	end

--	Cauldron:UpdateSkills();

	if CURRENT_TRADESKILL ~= name then
		StopTradeSkillRepeat();
		CURRENT_TRADESKILL = name;
	end

	-- display skill name, level/progress
	self:UpdateSkillInfo(name, rank, maxRank);

	-- update search text box
	self:UpdateSearchText();

	-- update filter information
	self:UpdateStatus();

	-- display list of matching skills
--	if CAULDRON_TRADESKILL_NAME ~= CURRENT_TRADESKILL then
--		CAULDRON_TRADESKILL_NAME = CURRENT_TRADESKILL;
		self:UpdateSkillList();
--	end

	-- display queue
	self:UpdateQueue();

	-- update buttons
	self:UpdateButtons();

	-- update page info
	self:UpdatePageInfo();

end

function Cauldron:UpdateSkillInfo(skillName, rank, maxRank)

	if IsTradeSkillGuild() then
		CauldronRankFrame:Hide();
		CauldronLinkFrame:Hide();
	else
		CauldronRankFrame:Show();
		CauldronLinkFrame:Show();
	end

	local skillCount = Cauldron:GetSkillCount(skillName);
	CauldronSkillNameText:SetText(skillName);
	local prof_title = "";
	if IsTradeSkillGuild() then
		prof_title = L["Guild"];
	else
		for i=1,#PROFESSION_RANKS do
			local value,title = PROFESSION_RANKS[i][1], PROFESSION_RANKS[i][2];
			if maxRank < value then break end
			prof_title = title;
		end
	end
	local linked, linkedName = IsTradeSkillLinked();
	if linked then
		linkedName = "["..linkedName.."] ";
	else
		linkedName = "";
	end
	CauldronRankInfoText:SetText(linkedName..prof_title..", "..skillCount.." "..L["skills"]);

	CauldronRankFrame:SetStatusBarColor(0.0, 0.0, 1.0, 0.5);
	CauldronRankFrameBackground:SetVertexColor(0.0, 0.0, 0.75, 0.5);
	CauldronRankFrame:SetMinMaxValues(0, maxRank);
	CauldronRankFrame:SetValue(rank);
	CauldronRankFrameText:SetText(rank.."/"..maxRank);

end

function Cauldron:UpdateSearchText()

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	if (not skillName or skillName == "UNKNOWN") or
	   (not self.vars.playername) or
	   (not self.db.realm.userdata[self.vars.playername]) or
	   (not self.db.realm.userdata[self.vars.playername].skills[skillName]) then
		return;
	end

	local searchText = self.db.realm.userdata[self.vars.playername].skills[skillName].window.search or "";
	if searchText == "" then
		searchText = SEARCH;
	end
	CauldronSearchBox:SetText(searchText);

end

function Cauldron:UpdateStatus()

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local filters = {};
	local filterTable = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter;

	if filterTable.haveAllReagents then
		table.insert(filters, L["Have all"]);
	elseif filterTable.haveKeyReagents then
		table.insert(filters, L["Have key"]);
	elseif filterTable.haveAnyReagents then
		table.insert(filters, L["Have any"]);
	end

	local difficulties = {};
	if not filterTable.optimal then
		table.insert(difficulties, "!"..L["Optimal"]);
	end
	if not filterTable.medium then
		table.insert(difficulties, "!"..L["Medium"]);
	end
	if not filterTable.easy then
		table.insert(difficulties, "!"..L["Easy"]);
	end
	if not filterTable.trivial then
		table.insert(difficulties, "!"..L["Trivial"]);
	end
	if #difficulties > 0 then
		table.insert(filters, L["Difficulty"]..": "..Cauldron:JoinStrings(difficulties, ","));
	end

	if filterTable.favorites then
		table.insert(filters, L["Favorites"]);
	end
	if filterTable.achievements then
		table.insert(filters, L["Achievements"]);
	end

	if #filters > 0 then
		local statusText = Cauldron:JoinStrings(filters, "; ");
		CauldronStatusText:SetText(L["Filters"]..": "..statusText);
		CauldronStatusFrame:Show();
	else
		CauldronStatusFrame:Hide();
	end
end

function Cauldron:UpdateFilterDropDowns()

	-- TODO

end

function Cauldron:UpdateSkillList()

	if Cauldron.updatingSkillList then
		return;
	end

	skillName = Cauldron:GetTradeSkillName(skillName);
	if not skillName then
		return;
	end

	local skillList = Cauldron:GetSkillList(self.vars.playername, skillName);
	if not skillList then
		return;
	end

	local height = 0;

	Cauldron.updatingSkillList = true;

	local startTime = GetTime();
	local offset = self.db.realm.userdata[self.vars.playername].skills[skillName].window.offset or 0;
	local lastFrameIndex = 0;

	-- iterate over the list of skills
--	for i, skillInfo in ipairs(skillList) do
	for i=1,CAULDRON_SKILL_LIST_MAX do

		local skillInfo = skillList[i + offset];
		if not skillInfo then
			break;
		end

		if not self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name] then
			self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name] = {
				favorite = false,
				expanded = false,
			};
		end

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

		-- check if we have a frame for this position
		if not skillFrame then
			-- create a new frame for the skill information
			if self.db.realm.userdata[self.vars.playername].options.compactView then
				-- TODO
			else
				-- TODO
			end
			skillFrame = CreateFrame("Button",
									 "CauldronSkillItem"..i,
									 CauldronSkillListScrollFrameScrollChild,
									 "CauldronSkillItemFrameTemplate");
		end

		-- set the height of frame
		skillFrame:SetHeight(CAULDRON_SKILLITEM_COLLAPSED_HEIGHT);

		skillFrame:SetID(i);
		skillFrame.skillIndex = skillInfo.index;

		-- set selection
		if self.db.realm.userdata[self.vars.playername].skills[skillName].window.selected == skillInfo.index then
			_G["CauldronSkillItem"..i.."Selection"]:Show();
		else
			_G["CauldronSkillItem"..i.."Selection"]:Hide();
		end

		-- populate the frame
		local frame = nil;

		-- set name and difficulty color
		frame = _G["CauldronSkillItem"..i.."SkillName"];
		if frame then
			local nameText = skillInfo.name;
			local skillNamePrefix = "";
			if ( ENABLE_COLORBLIND_MODE == "1" ) then
				skillNamePrefix = TradeSkillTypePrefix[skillType].." " or "";
			end
			frame:SetText(skillNamePrefix..nameText);
			if TradeSkillTypeColor then
				local color = TradeSkillTypeColor[skillInfo.difficulty];
				if color then
					frame:SetFontObject(color.font);
					frame.r = color.r;
					frame.g = color.g;
					frame.b = color.b;
				end
			end
		end

		-- set category
		frame = _G["CauldronSkillItem"..i.."SkillCategory"];
		if frame then
			frame:SetText(skillInfo.defaultCategory);
			if TradeSkillTypeColor then
				frame:SetFontObject(TradeSkillTypeColor.header.font);
				frame.r = TradeSkillTypeColor.header.r;
				frame.g = TradeSkillTypeColor.header.g;
				frame.b = TradeSkillTypeColor.header.b;
			end
		end

		-- set favorite check button
		frame = _G["CauldronSkillItem"..i.."FavoriteButton"];
		if frame then
			frame:SetChecked(self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].favorite);
			frame.skillInfo = skillInfo;

			-- set cooldown
			--[[
			frame = _G["CauldronSkillItem"..i.."SkillCooldown"];
			local cooldown = GetTradeSkillCooldown(skillInfo.index);
			if cooldown then
				if not frame:IsVisible() then
					frame:Show();
				end
				frame:SetText(SecondsToTime(cooldown));
			else
				if frame:IsVisible() then
					frame:Hide();
				end
			end
			--]]
		end

		-- set the icon
		frame = _G["CauldronSkillItem"..i.."SkillIcon"];
		if frame then
			frame:SetNormalTexture(skillInfo.icon);
			frame.itemLink = skillInfo.link;
			frame.skillIndex = skillInfo.index;
		end

		-- set the craft count
		frame = _G["CauldronSkillItem"..i.."SkillIconCount"];
		if frame then
			local minMade, maxMade = skillInfo.minMade, skillInfo.maxMade;
			if maxMade > 1 then
				if minMade == maxMade then
					frame:SetText(minMade);
				else
					frame:SetText(minMade.."-"..maxMade);
				end
				if frame:GetWidth() > 39 then
					frame:SetText("~"..floor((minMade + maxMade)/2));
				end
			else
				frame:SetText("");
			end
		end

		-- set the disclosure button texture
		frame = _G["CauldronSkillItem"..i.."DiscloseButton"];
		if frame then
			frame.skillInfo = skillInfo;

			local reagentsExpanded = self.db.realm.userdata[self.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
			if reagentsExpanded then
				frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
			else
				frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
			end

	--			_G["CauldronSkillItem"..i.."Reagents"]:Show();

				-- fill in the tools info
				--[[
				local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
				local toolsFrame = _G["CauldronSkillItem"..i.."ReagentsToolsInfo"];
				if spellFocus then
					toolsFrame:Show();
					toolsFrame:SetText(L["Requires"]..": "..spellFocus);
					toolsFrame:SetHeight(15);
				else
					toolsFrame:Hide();
					toolsFrame:SetText("");
					toolsFrame:SetHeight(0);
				end
				--]]

				-- fill in the reagents
				-- _G["CauldronSkillItem"..i.."Reagents"]:SetScale(0.86);

				-- learn reagents
				Cauldron:LearnSkillReagents(skillInfo);

				-- get reagents table
				local reagents = skillInfo.reagents;
				local reagentCount = #reagents;

				local smallReagentsFrame = _G["CauldronSkillItem"..i.."Reagents"];
				local reagentDetailsFrame = _G["CauldronSkillItem"..i.."ItemDetails"];

				if reagentsExpanded then

					reagentDetailsFrame:Show();
					smallReagentsFrame:Hide();

					local reqsLabelFrame = _G["CauldronSkillItem"..i.."ItemDetailsRequirementLabel"];
					local reqsFrame = _G["CauldronSkillItem"..i.."ItemDetailsRequirementText"];
					local spellFocus = BuildColoredListString(GetTradeSkillTools(skillInfo.index));
					if ( spellFocus ) then
						reqsLabelFrame:Show();
						reqsFrame:SetText(spellFocus);
					else
						reqsLabelFrame:Hide();
						reqsFrame:SetText("");
					end

					local cdFrame = _G["CauldronSkillItem"..i.."ItemDetailsSkillCooldown"];
					local cooldown = GetTradeSkillCooldown(skillInfo.index);
					if cooldown then
						cdFrame:SetText(COOLDOWN_REMAINING.." "..SecondsToTime(cooldown));
					else
						cdFrame:SetText("");
					end

					local descFrame = _G["CauldronSkillItem"..i.."ItemDetailsDescription"];
--					local reagentLabel = _G["CauldronSkillItem"..i.."ItemDetailsReagentLabel"];
					local desc = GetTradeSkillDescription(skillInfo.index);
					if desc then
						descFrame:SetText(desc);
--						reagentLabel:SetPoint("TOPLEFT", "CauldronSkillItem"..i.."ItemDetailsDescription", "BOTTOMLEFT", 0, -10);
					else
						descFrame:SetText(" ");
--						reagentLabel:SetPoint("TOPLEFT", "CauldronSkillItem"..i.."ItemDetailsDescription", "TOPLEFT", 0, 0);
					end
				else
					reagentDetailsFrame:Hide();
					smallReagentsFrame:Show();
				end

				for j=1,8 do
					local reagentFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j];
					local reagentDetailFrame = _G["CauldronSkillItem"..i.."ItemDetailsReagent"..j];

					if reagentFrame or reagentDetailFrame then
						if j > reagentCount then
							reagentFrame:Hide();
							reagentDetailFrame:Hide();
						else
							local reagentInfo = reagents[j];

							reagentFrame.skillIndex = skillInfo.index;
							reagentFrame.reagentIndex = reagentInfo.index;
							reagentFrame.link = reagentInfo.link;
							reagentDetailFrame.skillIndex = skillInfo.index;
							reagentDetailFrame.reagentIndex = reagentInfo.index;
							reagentDetailFrame.link = reagentInfo.link;

							local reagentNameFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Name"];
							local reagentDetailsNameFrame = _G["CauldronSkillItem"..i.."ItemDetailsReagent"..j.."Name"];
							local reagentIconFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."IconTexture"];
							local reagentDetailsIconFrame = _G["CauldronSkillItem"..i.."ItemDetailsReagent"..j.."IconTexture"];
							local reagentCountFrame = _G["CauldronSkillItem"..i.."ReagentsItemDetail"..j.."Count"];
							local reagentDetailsCountFrame = _G["CauldronSkillItem"..i.."ItemDetailsReagent"..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();
							reagentDetailFrame:Show();

							SetItemButtonTexture(reagentFrame, reagentInfo.icon);
							SetItemButtonTexture(reagentDetailFrame, reagentInfo.icon);
							if reagentNameFrame then
								reagentNameFrame:SetText(reagentInfo.name);
							end
							if reagentDetailsNameFrame then
								reagentDetailsNameFrame:SetText(reagentInfo.name);
							end

							local playerReagentCount = GetItemCount(reagentInfo.name);

							if playerReagentCount < reagentInfo.numRequired then
								-- Gray out items
								SetItemButtonTextureVertexColor(reagentFrame, 0.5, 0.5, 0.5);
								SetItemButtonTextureVertexColor(reagentDetailFrame, 0.5, 0.5, 0.5);
								if reagentNameFrame then
									reagentNameFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
								end
								if reagentDetailsNameFrame then
									reagentDetailsNameFrame:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
								end
							else
								SetItemButtonTextureVertexColor(reagentFrame, 1.0, 1.0, 1.0);
								SetItemButtonTextureVertexColor(reagentDetailFrame, 1.0, 1.0, 1.0);
								if reagentNameFrame then
									reagentNameFrame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
								end
								if reagentDetailsNameFrame then
									reagentDetailsNameFrame:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
								end
							end
							if playerReagentCount >= 100 then
								playerReagentCount = "*";
							end
							if reagentCountFrame then
								reagentCountFrame:SetText(playerReagentCount.."/"..reagentInfo.numRequired);
							end
							if reagentDetailsCountFrame then
								reagentDetailsCountFrame:SetText(playerReagentCount.."/"..reagentInfo.numRequired);
							end
						end
					end
				end

				-- only adjust height for expanded views
				if reagentsExpanded then
					local reagentRows = math.floor((reagentCount - 1) / 4);
					local reqHeight = _G["CauldronSkillItem"..i.."ItemDetailsRequirementText"]:GetHeight();
					local cooldownHeight = _G["CauldronSkillItem"..i.."ItemDetailsSkillCooldown"]:GetHeight();
					local descHeight = _G["CauldronSkillItem"..i.."ItemDetailsDescription"]:GetHeight();
					local detail1Frame = _G["CauldronSkillItem"..i.."ItemDetailsReagent1"];
					local detailHeight = detail1Frame:GetHeight();
					detail1Frame:SetPoint("TOPLEFT", _G["CauldronSkillItem"..i.."ItemDetailsDescription"], "BOTTOMLEFT", 0, -5);
					reagentDetailsFrame:SetHeight(40 + (reqHeight + cooldownHeight + descHeight) + (detailHeight * reagentRows));
					skillFrame:SetHeight(reagentDetailsFrame:GetHeight() + CAULDRON_SKILLITEM_COLLAPSED_HEIGHT + 2);
				else
					skillFrame:SetHeight(CAULDRON_SKILLITEM_COLLAPSED_HEIGHT);
				end
--[[
				_G["CauldronSkillItem"..i.."Reagents"]:SetHeight(toolsFrame:GetHeight() + (reagentRows * _G["CauldronSkillItem"..i.."ItemDetailsReagent1"]:GetHeight()));
				_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight() + _G["CauldronSkillItem"..i.."Reagents"]:GetHeight());
--]]
			--[[
			else
				_G["CauldronSkillItem"..i.."Reagents"]:Hide();

				frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
				_G["CauldronSkillItem"..i]:SetHeight(_G["CauldronSkillItem"..i.."SkillIcon"]:GetHeight());
			end
			--]]
		end

		-- craft count
		frame = _G["CauldronSkillItem"..i.."MiscInfoCount"];
		if frame then
			local potentialCount = Cauldron:GetPotentialCraftCount(skillInfo);
			local text = "";
			if (potentialCount > 0) and (potentialCount > skillInfo.available) then
				text = skillInfo.available.."/"..potentialCount;
			elseif skillInfo.available > 0 then
				text = skillInfo.available;
			end
			frame:SetText(text);
		end

		-- special skill-ups
		frame = _G["CauldronSkillItem"..i.."MiscInfoNumSkillUpsIcon"];
		-- Cauldron:info("skill ups icon frame: "..tostring(frame));
		if frame then
			if IsTradeSkillGuild() or (skillInfo.difficulty ~= "optimal") or (not skillInfo.numSkillUps or (skillInfo.numSkillUps < 1)) then
				frame:Hide();
				_G["CauldronSkillItem"..i.."MiscInfoNumSkillUps"]:Hide();
			else
				frame:Show();
				_G["CauldronSkillItem"..i.."MiscInfoNumSkillUps"]:Show();
				_G["CauldronSkillItem"..i.."MiscInfoNumSkillUps"]:SetText(skillInfo.numSkillUps);
			end
		end

		-- achievement indicator
		frame = _G["CauldronSkillItem"..i.."MiscInfoAchievement"];
		if frame then
			local achievements = Cauldron:GetAchievementsForSkill(skillInfo);
			local text = "";
			if achievements and #achievements > 0 then
				text = "A";
			end
			frame:SetText(text);
		end

		-- place the frame in the scroll view
		if i > 1 then
			-- anchor to the frame above
			skillFrame:SetPoint("TOPLEFT", _G["CauldronSkillItem"..(i-1)], "BOTTOMLEFT", 0, -2);
		else
			-- anchor to the parent
			skillFrame:SetPoint("TOPLEFT", 0, 0);
		end

		-- adjust the scroll child size
		height = height + skillFrame:GetHeight();
		CauldronSkillListScrollFrameScrollChild:SetHeight(height);

		-- show the frame
		skillFrame:Show();

		lastFrameIndex = i;
	end

	-- hide any remaining frames
--	local j = lastFrameIndex + 1;
	for j=lastFrameIndex+1,CAULDRON_SKILL_LIST_MAX do
		local frame = _G["CauldronSkillItem"..j];
		if not frame then
			break;
		end

		frame:Hide();
		frame:SetHeight(0);

--		j = j + 1;
	end

	local endTime = GetTime();
	if Cauldron.vars.displayTimers then
		Cauldron:info("draw skill list: "..tostring(endTime-startTime).."ms");
	end

	Cauldron.updatingSkillList = false;

end

function Cauldron:UpdateButtons()

	if IsTradeSkillLinked() or IsTradeSkillGuild() then
		CauldronQueueAllButton:Hide();
		CauldronQueueButton:Hide();
		CauldronDecrementButton:Hide();
		CauldronInputBox:Hide();
		CauldronIncrementButton:Hide();
		CauldronCreateAllButton:Hide();
		CauldronCreateButton:Hide();
		-- CauldronProcessButton:Disable();
		-- CauldronClearQueueButton:();
		CauldronShowQueueButton:Hide();
		CauldronShowGuildCraftersButton:Show();
		return;
	end

	CauldronQueueAllButton:Show();
	CauldronQueueButton:Show();
	CauldronDecrementButton:Show();
	CauldronInputBox:Show();
	CauldronIncrementButton:Show();
	CauldronCreateAllButton:Show();
	CauldronCreateButton:Show();
	CauldronShowGuildCraftersButton:Hide();

	local skillInfo = Cauldron:GetSelectedSkill();

	if skillInfo then
		CauldronCreateButton:SetText(skillInfo.verb or CREATE);
		if skillInfo.verb then
			CauldronCreateAllButton:Hide();
		end

		CauldronQueueAllButton:Enable();
		CauldronQueueButton:Enable();

		if skillInfo.available > 0 then
			CauldronCreateAllButton:Enable();
			CauldronCreateButton:Enable();
		else
			CauldronCreateAllButton:Disable();
			CauldronCreateButton:Disable();
		end
	else
		CauldronQueueAllButton:Disable();
		CauldronQueueButton:Disable();
		CauldronCreateAllButton:Disable();
		CauldronCreateButton:Disable();
	end

--[[
	if not IsTradeSkillLinked() then
		if #CauldronQueue:GetItems(self.db.realm.userdata[self.vars.playername].queue, CURRENT_TRADESKILL) > 0 then
			CauldronProcessButton:Enable();
			CauldronClearQueueButton:Enable();
		else
			CauldronProcessButton:Disable();
			CauldronClearQueueButton:Disable();
		end
	end
--]]

	if CauldronQueueWindowFrame:IsShown() then
		CauldronShowQueueButton:Hide();

		local queue = CauldronQueue:GetItems(Cauldron.db.realm.userdata[Cauldron.vars.playername].queue);
		if #queue > 0 then
			CauldronProcessButton:Enable();
			CauldronClearQueueButton:Enable();
		else
			CauldronProcessButton:Disable();
			CauldronClearQueueButton:Disable();
		end
	else
		CauldronShowQueueButton:Show();
	end

end

function Cauldron:UpdatePageInfo()

	local skillName = CURRENT_TRADESKILL;
	if skillName == "UNKNOWN" then
		return;
	end
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local offset = self.db.realm.userdata[self.vars.playername].skills[skillName].window.offset or 0;
	local firstIndex = 1 + offset;
	local numSkills = table.getn(Cauldron:GetSkillList(self.vars.playername, skillName));
--	local numSkills = self.db.realm.userdata[self.vars.playername].skills[skillName].skillCount or 0;
	local lastIndex = math.min(50 + offset, numSkills);

	local pageInfo = "";
	if numSkills > 0 then
		pageInfo = string.format(L["Showing %1$d - %2$d of %3$d items."], firstIndex, lastIndex, numSkills);
	else
		pageInfo = L["No items."];
	end
	CauldronPageInfoText:SetText(pageInfo);

	-- enable/disable navigation buttons
	-- TODO
end

function Cauldron:OnCauldronUpdate()

	--[[
--	self:Search();
 	local selectionIndex
 	if self.vars.selectionIndex == 0 then
 		selectionIndex = self:GetFirstTradeSkill();
 	else
 		selectionIndex = self.vars.selectionIndex;
 	end
 	--]]

end

function CauldronFrame_OnLoad()

--	ButtonFrameTemplate_HideButtonBar(CauldronFrame);
	ButtonFrameTemplate_HideAttic(CauldronFrame);
--	CauldronFrameInsetBg:Hide();

end

function CauldronFrame_OnEvent()
end

function CauldronFrame_OnShow()
end

function CauldronFrame_OnHide()
	CloseTradeSkill();
end

function CauldronSearch_OnTextChanged()
	Cauldron:TradeSkillFilter_OnTextChanged(CauldronSearchBox);
end

function CauldronFrame_Update()
end

function CauldronFrame_Show()
	Cauldron:Frame_Show();
end

function CauldronFrameIncrement_OnClick()
	if ( CauldronInputBox:GetNumber() < 100 ) then
		CauldronInputBox:SetNumber(CauldronInputBox:GetNumber() + 1);
	end
end

function CauldronFrameDecrement_OnClick()
	if ( CauldronInputBox:GetNumber() > 0 ) then
		CauldronInputBox:SetNumber(CauldronInputBox:GetNumber() - 1);
	end
end

function CauldronFilterDropDown_OnLoad(self)
	UIDropDownMenu_Initialize(self, CauldronFilterDropDown_Initialize, "MENU");
	CauldronFilterDropDownText:SetJustifyH("CENTER");
	CauldronFilterDropDownButton:Show();
end

function CauldronFilterDropDown_Initialize(self, level)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local info = UIDropDownMenu_CreateInfo();

	if level == 1 then

		if not IsTradeSkillLinked() and not IsTradeSkillGuild() then
			-- favorites
			local favorites = UIDropDownMenu_CreateInfo();
			favorites.text = L["Favorites"];
			favorites.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites or false;
			favorites.isNotRadio = true;
			favorites.keepShownOnClick = true;
			-- tooltipTitle = L["Favorites"],
			-- tooltipText = L["Display only favorite skills"],
			favorites.func = function()
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites;
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			-- arg1 = "favorite",
			-- arg2 = "",
			UIDropDownMenu_AddButton(favorites, level);

			-- achievements
			local achievements = UIDropDownMenu_CreateInfo();
			achievements.text = L["Achievements"];
			achievements.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.achievements or false;
			achievements.isNotRadio = true;
			achievements.keepShownOnClick = true;
			-- tooltipTitle = L["Achievements"],
			-- tooltipText = L["Display only skills for achievements"],
			achievements.func = function()
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.achievements = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.achievements;
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			-- arg1 = "achievement",
			-- arg2 = "",
			UIDropDownMenu_AddButton(achievements, level);
		end

	--[==[
		info.text = CRAFT_IS_MAKEABLE
		info.func = 	function()
							TradeSkillFrame.filterTbl.hasMaterials  = not TradeSkillFrame.filterTbl.hasMaterials;
							TradeSkillOnlyShowMakeable(TradeSkillFrame.filterTbl.hasMaterials);
							TradeSkillUpdateFilterBar();
						end
		info.keepShownOnClick = true;
		info.checked = 	TradeSkillFrame.filterTbl.hasMaterials
		info.isNotRadio = true;
		UIDropDownMenu_AddButton(info, level)

		if ( not IsTradeSkillGuild() ) then
			info.text = TRADESKILL_FILTER_HAS_SKILL_UP;
			info.func = 	function()
								TradeSkillFrame.filterTbl.hasSkillUp  = not TradeSkillFrame.filterTbl.hasSkillUp;
								TradeSkillOnlyShowSkillUps(TradeSkillFrame.filterTbl.hasSkillUp);
								TradeSkillUpdateFilterBar();
							end
			info.keepShownOnClick = true;
			info.checked = 	TradeSkillFrame.filterTbl.hasSkillUp;
			info.isNotRadio = true;
			UIDropDownMenu_AddButton(info, level);
		end
	--]==]

		info.checked = 	nil;
		info.isNotRadio = nil;

		info.text = TRADESKILL_FILTER_SLOTS
		info.func =  nil;
		info.notCheckable = true;
		info.keepShownOnClick = false;
		info.hasArrow = true;
		info.value = 1;
		UIDropDownMenu_AddButton(info, level)

		info.text = TRADESKILL_FILTER_SUBCLASS
		info.func =  nil;
		info.notCheckable = true;
		info.keepShownOnClick = false;
		info.hasArrow = true;
		info.value = 2;
		UIDropDownMenu_AddButton(info, level)

		-- spacer
		UIDropDownMenu_AddButton({
			text = "",
			notClickable = true,
			isNotRadio = nil,
			notCheckable = true,
		}, level);

		-- skill difficulty

		local difficultyTitle = UIDropDownMenu_CreateInfo();
		difficultyTitle.text = L["Difficulty"];
		difficultyTitle.isTitle = true;
		difficultyTitle.isNotRadio = nil;
		difficultyTitle.notCheckable = true;
		difficultyTitle.tooltipTitle = "";
		difficultyTitle.tooltipText = "";
		UIDropDownMenu_AddButton(difficultyTitle, level);

		local difficultyOptimal = UIDropDownMenu_CreateInfo();
		difficultyOptimal.text = L["Optimal"];
--		textR = 1.0,
--		textG = 1.0,
--		textB = 1.0,
		difficultyOptimal.isNotRadio = true;
		difficultyOptimal.notCheckable = false;
		difficultyOptimal.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.optimal;
		difficultyOptimal.keepShownOnClick = true;
		difficultyOptimal.tooltipTitle = L["Optimal"];
		difficultyOptimal.tooltipText = L["Set whether items of this difficulty level should be shown"];
		difficultyOptimal.func = function(arg1, arg2)
			Cauldron:FilterDropDown_ToggleDifficulty(arg1);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		difficultyOptimal.arg1 = "optimal";
		difficultyOptimal.arg2 = "";
		UIDropDownMenu_AddButton(difficultyOptimal, level);

		local difficultyMedium = UIDropDownMenu_CreateInfo();
		difficultyMedium.text = L["Medium"];
--		textR = 1.0,
--		textG = 1.0,
--		textB = 1.0,
		difficultyMedium.isNotRadio = true;
		difficultyMedium.notCheckable = false;
		difficultyMedium.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.medium;
		difficultyMedium.keepShownOnClick = true;
		difficultyMedium.tooltipTitle = L["Medium"];
		difficultyMedium.tooltipText = L["Set whether items of this difficulty level should be shown"];
		difficultyMedium.func = function(arg1, arg2)
			Cauldron:FilterDropDown_ToggleDifficulty(arg1);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		difficultyMedium.arg1 = "medium";
		difficultyMedium.arg2 = "";
		UIDropDownMenu_AddButton(difficultyMedium, level);

		local difficultyEasy = UIDropDownMenu_CreateInfo();
		difficultyEasy.text = L["Easy"];
--		textR = 1.0,
--		textG = 1.0,
--		textB = 1.0,
		difficultyEasy.isNotRadio = true;
		difficultyEasy.notCheckable = false;
		difficultyEasy.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.easy;
		difficultyEasy.keepShownOnClick = true;
		difficultyEasy.tooltipTitle = L["Easy"];
		difficultyEasy.tooltipText = L["Set whether items of this difficulty level should be shown"];
		difficultyEasy.func = function(arg1, arg2)
			Cauldron:FilterDropDown_ToggleDifficulty(arg1);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		difficultyEasy.arg1 = "easy";
		difficultyEasy.arg2 = "";
		UIDropDownMenu_AddButton(difficultyEasy, level);

		local difficultyTrivial = UIDropDownMenu_CreateInfo();
		difficultyTrivial.text = L["Trivial"];
--		textR = 1.0,
--		textG = 1.0,
--		textB = 1.0,
		difficultyTrivial.isNotRadio = true;
		difficultyTrivial.notCheckable = false;
		difficultyTrivial.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.trivial;
		difficultyTrivial.keepShownOnClick = true;
		difficultyTrivial.tooltipTitle = L["Trivial"];
		difficultyTrivial.tooltipText = L["Set whether items of this difficulty level should be shown"];
		difficultyTrivial.func = function(arg1, arg2)
			Cauldron:FilterDropDown_ToggleDifficulty(arg1);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		difficultyTrivial.arg1 = "trivial";
		difficultyTrivial.arg2 = "";
		UIDropDownMenu_AddButton(difficultyTrivial, level);

		-- spacer
		UIDropDownMenu_AddButton({
			text = "",
			notClickable = true,
			isNotRadio = nil,
			notCheckable = true,
		}, level);

		-- reagents availability

		local reagentsTitle = UIDropDownMenu_CreateInfo();
		reagentsTitle.text = L["Reagents"];
		reagentsTitle.isTitle = true;
		reagentsTitle.isNotRadio = nil;
		reagentsTitle.notCheckable = true;
		reagentsTitle.tooltipTitle = "";
		reagentsTitle.tooltipText = "";
		UIDropDownMenu_AddButton(reagentsTitle, level);

		-- force check "normal" if the list is linked
		if IsTradeSkillLinked() then
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;
		end

		local normal = UIDropDownMenu_CreateInfo();
		normal.text = L["Normal"];
		normal.checked = Cauldron:ReagentsFilterNormalCheck();
		normal.tooltipTitle = L["Reagents"];
		normal.tooltipText = L["Display the normal list of skills"];
		normal.func = function(arg1, arg2)
			Cauldron:FilterDropDown_SetReagentFilter(arg1);
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		normal.arg1 = "normal";
		normal.arg2 = "";
		UIDropDownMenu_AddButton(normal, level);

		if not IsTradeSkillLinked() then

			local haveAllReagents = UIDropDownMenu_CreateInfo();
			haveAllReagents.text = L["Have all"];
			haveAllReagents.isNotRadio = nil;
			haveAllReagents.notCheckable = false;
			haveAllReagents.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents;
			haveAllReagents.tooltipTitle = L["Reagents"];
			haveAllReagents.tooltipText = L["Set whether skills for which you have all the required reagents are shown in the list"];
			haveAllReagents.func = function(arg1, arg2)
				Cauldron:FilterDropDown_SetReagentFilter(arg1);
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			haveAllReagents.arg1 = "all";
			haveAllReagents.arg2 = "";
			UIDropDownMenu_AddButton(haveAllReagents, level);

			local haveKeyReagents = UIDropDownMenu_CreateInfo();
			haveKeyReagents.text = L["Have key"];
			haveKeyReagents.isNotRadio = nil;
			haveKeyReagents.notCheckable = false;
			haveKeyReagents.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents;
			haveKeyReagents.tooltipTitle = L["Reagents"];
			haveKeyReagents.tooltipText = L["Set whether skills for which you have all key reagents (non-vendor available) are shown in the list"];
			haveKeyReagents.func = function(arg1, arg2)
				Cauldron:FilterDropDown_SetReagentFilter(arg1);
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			haveKeyReagents.arg1 = "key";
			haveKeyReagents.arg2 = "";
			UIDropDownMenu_AddButton(haveKeyReagents, level);

			local haveAnyReagents = UIDropDownMenu_CreateInfo();
			haveAnyReagents.text = L["Have any"];
			haveAnyReagents.isNotRadio = nil;
			haveAnyReagents.notCheckable = false;
			haveAnyReagents.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents;
			haveAnyReagents.tooltipTitle = L["Reagents"];
			haveAnyReagents.tooltipText = L["Set whether skills for which you have any reagents are shown in the list"];
			haveAnyReagents.func = function(arg1, arg2)
				Cauldron:FilterDropDown_SetReagentFilter(arg1);
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			haveAnyReagents.arg1 = "any";
			haveAnyReagents.arg2 = "";
			UIDropDownMenu_AddButton(haveAnyReagents, level);

		end

		-- spacer
		UIDropDownMenu_AddButton({
			text = "",
			notClickable = true,
			isNotRadio = nil,
			notCheckable = true,
		}, level);

		-- reset item
		local resetFilters = UIDropDownMenu_CreateInfo();
		resetFilters.text = L["Reset filters"];
		resetFilters.checked = false;
		resetFilters.isNotRadio = nil;
		resetFilters.notCheckable = true;
		resetFilters.tooltipTitle = L["Reset filters"];
		resetFilters.tooltipText = L["Reset all filters on the skills list"];
		resetFilters.func = function(arg1, arg2)
			Cauldron:FilterDropDown_Reset();
			Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
			Cauldron:UpdateSkillList();
			Cauldron:UpdateStatus();
			Cauldron:UpdatePageInfo();
		end;
		UIDropDownMenu_AddButton(resetFilters, level);

	elseif level == 2 then
		if UIDROPDOWNMENU_MENU_VALUE == 1 then
			local slots = { GetTradeSkillSubClassFilteredSlots(0) };
			local subslots = {};
			for i,slot in pairs(slots) do
				local slotInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slot];
				if not slotInfo then
					slotInfo = {
						checked = true,
					};
				end

				info.text = slot;
				info.func =  function()
					Cauldron:FilterDropDown_SetSlot(slots[i]);
					-- TradeSkillSetFilter(0, i, "", slots[i]);
					Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
					Cauldron:UpdateSkillList();
					Cauldron:UpdateStatus();
					Cauldron:UpdatePageInfo();
				end;
				info.notCheckable = false;
				info.checked = slotInfo.checked;
				info.hasArrow = false;
				info.isNotRadio = true;
				info.keepShownOnClick = true;
				UIDropDownMenu_AddButton(info, level);
			end
		elseif UIDROPDOWNMENU_MENU_VALUE == 2 then
			-- "all" sub-class
			info.text = L["All"];
			info.func = function()
				Cauldron:FilterDropDown_SetSubclass("all", "");
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			info.notCheckable = true;
			info.hasArrow = false;
			info.isNotRadio = true;
			info.keepShownOnClick = false;
			info.value = -1;
			UIDropDownMenu_AddButton(info, level);

			-- "none" sub-class
			info.text = L["None"];
			info.func = function()
				Cauldron:FilterDropDown_SetSubclass("none", "");
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			info.notCheckable = true;
			info.hasArrow = false;
			info.isNotRadio = true;
			info.keepShownOnClick = false;
			info.value = -2;
			UIDropDownMenu_AddButton(info, level);

			-- iterate over sub-classes
			local subClasses = { GetTradeSkillSubClasses() };
			local subslots = {};

			for i,subClass in pairs(subClasses) do
				info.text = subClass;
				info.func =  function()
					Cauldron:FilterDropDown_SetSubclass(subClasses[i], "");
					-- TradeSkillSetFilter(i, 0, subClasses[i], "");
					Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
					Cauldron:UpdateSkillList();
					Cauldron:UpdateStatus();
					Cauldron:UpdatePageInfo();
				end
				subslots  = { GetTradeSkillSubClassFilteredSlots(i) };
				if #subslots > 1 then
					info.notCheckable = true;
					info.hasArrow = true;
				else
					local catInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClass];
					if not catInfo then
						catInfo = {
							shown = true,
							expanded = true,
						};
					end

					info.notCheckable = false;
					info.checked = catInfo.shown;
					info.hasArrow = false;
					info.isNotRadio = true;
					info.keepShownOnClick = true;
				end
--				info.hasArrow = #subslots > 1;
				info.value = i;
				UIDropDownMenu_AddButton(info, level);
			end
		end
	elseif level == 3 then
		local subClasses = { GetTradeSkillSubClasses() };
		local subslots  = { GetTradeSkillSubClassFilteredSlots(UIDROPDOWNMENU_MENU_VALUE) };
		for i,slot in pairs(subslots) do
			info.text = slot;
			info.func =  function()
				Cauldron:FilterDropDown_SetSubclass(subClasses[UIDROPDOWNMENU_MENU_VALUE], subslots[i]);
				--[[
				TradeSkillSetFilter(UIDROPDOWNMENU_MENU_VALUE, i, subClasses[UIDROPDOWNMENU_MENU_VALUE], subslots[i]);
				--]]
				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.offset = 0;
				Cauldron:UpdateSkillList();
				Cauldron:UpdateStatus();
				Cauldron:UpdatePageInfo();
			end;
			local catInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClasses[UIDROPDOWNMENU_MENU_VALUE]..";"..subslots[i]];
			if not catInfo then
				catInfo = {
					shown = true,
					expanded = true,
				};
			end

			info.notCheckable = false;
			info.checked = catInfo.shown;
			info.isNotRadio = true;
			info.keepShownOnClick = true;
			info.value = {UIDROPDOWNMENU_MENU_VALUE, i};
			UIDropDownMenu_AddButton(info, level);
		end
	end

end

function CauldronSortDropDown_OnLoad(self)
	CauldronSortButton:SetText(L["Sort"]);
	UIDropDownMenu_Initialize(self, CauldronSortDropDown_Initialize, "MENU");
	CauldronSortDropDownText:SetJustifyH("CENTER");
	CauldronSortDropDownButton:Show();
end

function CauldronSortDropDown_Initialize(self, level)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local info = UIDropDownMenu_CreateInfo();

	if level == 1 then

		-- title
		--[[
		local sortTitle = UIDropDownMenu_CreateInfo();
		sortTitle.text = L["Sort"];
		sortTitle.isTitle = true;
		sortTitle.isNotRadio = nil;
		sortTitle.notCheckable = true;
		sortTitle.tooltipTitle = "";
		sortTitle.tooltipText = "";
		UIDropDownMenu_AddButton(sortTitle, level);
		--]]

		-- default
		local sortDefault = UIDropDownMenu_CreateInfo();
		sortDefault.text = L["Default"];
		sortDefault.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDefault;
		sortDefault.isNotRadio = nil;
		sortDefault.keepShownOnClick = false;
		sortDefault.func = function()
			Cauldron:FilterDropDown_SetSort("default");
			Cauldron:UpdateSkillList();
		end;
		UIDropDownMenu_AddButton(sortDefault, level);

	--[[
	local sortDefault = {
		text = L["Default"],
		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDefault,
		tooltipTitle = L["Default"],
		tooltipText = L["Set the sorting method to use on the skills list"],
		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
		arg1 = "default",
		arg2 = "",
	};
	--]]

		-- alpha
		local sortAlpha = UIDropDownMenu_CreateInfo();
		sortAlpha.text = L["Alphabetically"];
		sortAlpha.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortAlpha;
		sortAlpha.isNotRadio = nil;
		sortAlpha.keepShownOnClick = false;
		sortAlpha.func = function()
			Cauldron:FilterDropDown_SetSort("alpha");
			Cauldron:UpdateSkillList();
		end;
		UIDropDownMenu_AddButton(sortAlpha, level);

	--[[
	local sortAlpha = {
		text = L["Alphabetically"],
		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortAlpha,
		tooltipTitle = L["Alphabetically"],
		tooltipText = L["Set the sorting method to use on the skills list"],
		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
		arg1 = "alpha",
		arg2 = "",
	};
	--]]

		-- difficulty
		local sortDifficulty = UIDropDownMenu_CreateInfo();
		sortDifficulty.text = L["By difficulty"];
		sortDifficulty.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDifficulty;
		sortDifficulty.isNotRadio = nil;
		sortDifficulty.keepShownOnClick = false;
		sortDifficulty.func = function()
			Cauldron:FilterDropDown_SetSort("difficulty");
			Cauldron:UpdateSkillList();
		end;
		UIDropDownMenu_AddButton(sortDifficulty, level);

	--[[
	local sortDifficulty = {
		text = L["By difficulty"],
		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDifficulty,
		tooltipTitle = L["By difficulty"],
		tooltipText = L["Set the sorting method to use on the skills list"],
		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
		arg1 = "difficulty",
		arg2 = "",
	};
	--]]

		-- item level
		local sortItemLevel = UIDropDownMenu_CreateInfo();
		sortItemLevel.text = L["By item level"];
		sortItemLevel.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortItemLevel;
		sortItemLevel.isNotRadio = nil;
		sortItemLevel.keepShownOnClick = false;
		sortItemLevel.func = function()
			Cauldron:FilterDropDown_SetSort("itemlevel");
			Cauldron:UpdateSkillList();
		end;
		UIDropDownMenu_AddButton(sortItemLevel, level);

	--[[
	local sortItemLevel = {
		text = L["By item level"],
		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortItemLevel,
		tooltipTitle = L["By item level"],
		tooltipText = L["Set the sorting method to use on the skills list"],
		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
		arg1 = "itemlevel",
		arg2 = "",
	};
	--]]

		-- required level
		local sortReqLevel = UIDropDownMenu_CreateInfo();
		sortReqLevel.text = L["By required level"];
		sortReqLevel.checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortRequiredLevel;
		sortReqLevel.isNotRadio = nil;
		sortReqLevel.keepShownOnClick = false;
		sortReqLevel.func = function()
			Cauldron:FilterDropDown_SetSort("reqlevel");
			Cauldron:UpdateSkillList();
		end;
		UIDropDownMenu_AddButton(sortReqLevel, level);

	--[[
	local sortReqLevel = {
		text = L["By required level"],
		checked = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortRequiredLevel,
		tooltipTitle = L["By required level"],
		tooltipText = L["Set the sorting method to use on the skills list"],
		func = function(arg1, arg2) Cauldron:FilterDropDown_SetSort(arg1) end,
		arg1 = "reqlevel",
		arg2 = "",
	};
	--]]

		-- favorites
		-- TODO

		-- benefit
		-- TODO

	end

end

function Cauldron:FilterDropDown_Reset()

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	--[[
	-- sorting
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDefault = true;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortAlpha = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortDifficulty = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.sortBenefit = false;
	--]]

	-- difficulty
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.optimal = true;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.medium = true;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.easy = true;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.trivial = true;

	-- favorites/achievements
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favorites = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.favoritesAtTop = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.achievements = false;

	-- availability
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents = false;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents = false;

end

function Cauldron:FilterDropDown_SetSort(sort)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

--	local sort = info.arg1;
	local filter = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter;

	if sort == "default" then
		filter.sortDefault = true;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = false;
	elseif sort == "alpha" then
		filter.sortDefault = false;
		filter.sortAlpha = true;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = false;
	elseif sort == "difficulty" then
		filter.sortDefault = false;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = true;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = false;
	elseif sort == "itemlevel" then
		filter.sortDefault = false;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = true;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = false;
	elseif sort == "reqlevel" then
		filter.sortDefault = false;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = true;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = false;
	elseif sort == "benefit" then
		filter.sortDefault = false;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = false;
	   	filter.sortBenefit = true;
	elseif sort == "favorite" then
		filter.sortDefault = false;
		filter.sortAlpha = false;
	   	filter.sortDifficulty = false;
	   	filter.sortItemLevel = false;
	   	filter.sortRequiredLevel = false;
	   	filter.sortFavorites = true;
	   	filter.sortBenefit = false;
	end

end

function Cauldron:FilterDropDown_SetSlot(slot)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

--	Cauldron:info("set slot: "..tostring(slot));

	local slotInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slot];
	if not slotInfo then
		-- don't have slot info; create it
		slotInfo = {
			checked = true,
		};

		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.slots[slot] = slotInfo;
	end

	slotInfo.checked = not slotInfo.checked;

end

function Cauldron:FilterDropDown_SetSubclass(subclass, subslot)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

--	Cauldron:info("set subclass: "..tostring(subclass)..", subslot: "..tostring(subslot));

	-- handle "special" sub-classes
	if subclass == "all" or subclass == "none" then
		local checkit = (subclass == "all");
		local subClasses = { GetTradeSkillSubClasses() };
		local subslots = {};

		for i,subClass in pairs(subClasses) do
			subslots  = { GetTradeSkillSubClassFilteredSlots(i) };
			if #subslots > 1 then
				for j,slot in pairs(subslots) do
					local catInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClass..";"..subslots[j]];
					if not catInfo then
						catInfo = {
							shown = checkit,
							expanded = true,
						};
					else
						catInfo.shown = checkit;
					end

					Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClass..";"..subslots[j]] = catInfo;
				end
			else
				local catInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClass];
				if not catInfo then
					catInfo = {
						shown = checkit,
						expanded = true,
					};
				else
					catInfo.shown = checkit;
				end

				Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[subClass] = catInfo;
			end
		end

		return;
	end

	local catName = subclass;
	if subslot ~= "" then
		catName = subclass..";"..subslot;
	end
--	Cauldron:info("catName: "..catName);

	local catInfo = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[catName];
	if not catInfo then
		-- don't have category info; create it
		catInfo = {
			shown = true,
			expanded = true,
		};

		Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.categories[catName] = catInfo;
	end

	catInfo.shown = not catInfo.shown;

end

function CauldronLinkDropDown_LinkPost(self, chan)
	local link = GetTradeSkillListLink();
	if link then
		ChatFrame_OpenChat(chan.." "..link, DEFAULT_CHAT_FRAME);
	end
end


function CauldronLinkDropDown_OnLoad(self)
	UIDropDownMenu_Initialize(self, CauldronLinkDropDown_Init, "MENU");
end

function CauldronLinkDropDown_Init(self, level)

	local info = UIDropDownMenu_CreateInfo();
	info.notCheckable = true;
	info.text = TRADESKILL_POST;
	info.isTitle = 1;
	UIDropDownMenu_AddButton(info);
	info.isTitle = nil;

	info = UIDropDownMenu_CreateInfo();
	info.notCheckable = true;
	info.func = CauldronLinkDropDown_LinkPost;

	info.text = GUILD;
	info.arg1 = SLASH_GUILD1;
	info.disabled = not IsInGuild();
	UIDropDownMenu_AddButton(info);

	info.text = PARTY;
	info.arg1 = SLASH_PARTY1;
	info.disabled = GetNumPartyMembers() == 0;
	UIDropDownMenu_AddButton(info);

	info.text = RAID;
	info.disabled = GetNumRaidMembers() == 0;
	info.arg1 = SLASH_RAID1;
	UIDropDownMenu_AddButton(info);
	-- info.text = SAY;
	-- info.arg1 = SLASH_SAY1;
	-- UIDropDownMenu_AddButton(info);

	info.disabled = false
	local name;
	local channels = {GetChannelList()};
	local channelCount = #channels/2;
	for i=1, MAX_CHANNEL_BUTTONS, 1 do
		if ( i <= channelCount) then
			info.text = channels[i*2];
			info.arg1 = "/"..channels[(i-1)*2 + 1];
			UIDropDownMenu_AddButton(info);
		end
	end
end

function Cauldron:ReagentsFilterNormalCheck()

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local checked = true;

	if Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAllReagents or
	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveKeyReagents or
	   Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter.haveAnyReagents then
	   	checked = false;
	end

	return checked;
end

function Cauldron:FilterDropDown_SetReagentFilter(info)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local reagents = info.arg1;
	local filter = Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter;

	if reagents == "normal" then
		filter.haveAllReagents = false;
	   	filter.haveKeyReagents = false;
	   	filter.haveAnyReagents = false;
	elseif reagents == "all" then
		filter.haveAllReagents = true;
	   	filter.haveKeyReagents = false;
	   	filter.haveAnyReagents = false;
	elseif reagents == "key" then
		filter.haveAllReagents = false;
	   	filter.haveKeyReagents = true;
	   	filter.haveAnyReagents = false;
	elseif reagents == "any" then
		filter.haveAllReagents = false;
	   	filter.haveKeyReagents = false;
	   	filter.haveAnyReagents = true;
	end

	-- update the UI
	Cauldron:UpdateSkillList();

end

function Cauldron:FilterDropDown_ToggleDifficulty(info)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.filter[info.arg1] = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[CURRENT_TRADESKILL].window.filter[info.arg1];

end


function Cauldron:CollapseItemButton_OnClick(button)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local skillInfo = button.skillInfo;

	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded = not Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.skills[skillInfo.name].expanded;
	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = skillInfo.index;

	-- update the UI
	Cauldron:UpdateSkillList();

end

function Cauldron:SkillItem_OnEnter(frame)

	local id = frame:GetID();

	local name = _G["CauldronSkillItem"..id.."SkillName"];
	if name then
--		name:
	end

	-- TODO

end

function Cauldron:SkillItem_OnLeave(frame)

-- TODO

end

function Cauldron:SkillItem_OnClick(frame, button, down)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	-- select this frame
	if frame.skillIndex then
    	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.selected = frame.skillIndex;
    	CauldronFrame.selectedSkill = frame.skillIndex;
    	CauldronFrame.numAvailable = 1;
    end

	-- update the UI
	Cauldron:UpdateSkillList();
	Cauldron:UpdateButtons();

end

function Cauldron:TradeSkillFilter_OnTextChanged(frame)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	if (not skillName or skillName == "UNKNOWN") or
	   (not self.vars.playername) or
	   (not self.db.realm.userdata[self.vars.playername]) or
	   (not self.db.realm.userdata[self.vars.playername].skills[skillName]) then
		return;
	end

	local text = frame:GetText();
	if text == SEARCH then
		text = "";
	end

	Cauldron.db.realm.userdata[Cauldron.vars.playername].skills[skillName].window.search = text;

	-- update the UI
	Cauldron:UpdateSkillList();

end

function Cauldron:AmountDecrement_OnClick()

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

end

function Cauldron:AmountIncrement_OnClick()

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

end

function Cauldron:FavoriteItemButton_OnClick(button)

	local skillName = CURRENT_TRADESKILL;
	if IsTradeSkillLinked() then
		skillName = "Linked-"..skillName;
	end
	if IsTradeSkillGuild() then
		skillName = "Guild-"..skillName;
	end

	local skillInfo = button.skillInfo;

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

end

function Cauldron:AppendToTooltip(tooltip, skillIndex)
	if not tooltip then
		return;
	end
	if not skillIndex then
		return;
	end


end

function Cauldron:ShowGuildCrafters()
	if CauldronGuildFrame:IsShown() then
		CauldronGuildFrame:Hide();
	else
		CauldronGuildFrame:Show();
	end
end

function CauldronGuildFrame_OnShow()
	CauldronGuildCraftersFrameScrollBar:SetValue(0);
	CauldronGuilCraftersFrame_Update();
end

function CauldronGuilCraftersFrame_Update()
	local skillLineID, recipeID, numMembers = GetGuildRecipeInfoPostQuery();
	local offset = FauxScrollFrame_GetOffset(CauldronGuildCraftersFrame);
	local index, button, name, online;

	for i = 1, TRADE_SKILL_GUILD_CRAFTERS_DISPLAYED, 1 do
		index = i + offset;
		button = _G["CauldronGuildCrafter"..i];
		if ( index > numMembers ) then
			button:Hide();
		else
			name, online = GetGuildRecipeMember(index);
			button:SetText(name);
			if ( online ) then
				button:Enable();
			else
				button:Disable();
			end
			button:Show();
			button.name = name;
		end
	end
	FauxScrollFrame_Update(CauldronGuildCraftersFrame, numMembers, TRADE_SKILL_GUILD_CRAFTERS_DISPLAYED, TRADE_SKILL_HEIGHT);
end