Quantcast
--[[
************************************************************************
Core.lua
Core functions for Ackis Recipe List
************************************************************************
File date: @file-date-iso@
File hash: @file-abbreviated-hash@
Project hash: @project-abbreviated-hash@
Project version: @project-version@
************************************************************************
Please see http://www.wowace.com/addons/arl/ for more information.
************************************************************************
This source code is released under All Rights Reserved.
************************************************************************
--- Ackis Recipe List provides functionality to scan your professions.
-- It will determine which recipes you are missing.
-- @class file
-- @name Core.lua
-- @release 2.0
************************************************************************
]]

-------------------------------------------------------------------------------
-- Localized Lua globals.
-------------------------------------------------------------------------------
local _G = getfenv(0)

-- Functions
local pairs, ipairs = _G.pairs, _G.ipairs
local select = _G.select
local tonumber, tostring = _G.tonumber, _G.tostring
local type = _G.type

-- Libraries
local bit = _G.bit
local string = _G.string
local table = _G.table

-------------------------------------------------------------------------------
-- AddOn namespace.
-------------------------------------------------------------------------------
local FOLDER_NAME, private = ...

local LibStub	= _G.LibStub
local addon	= LibStub("AceAddon-3.0"):NewAddon(private.addon_name, "AceConsole-3.0", "AceEvent-3.0")
_G.AckisRecipeList = addon

--@alpha@
_G.ARL = addon
--@end-alpha@

local L		= LibStub("AceLocale-3.0"):GetLocale(private.addon_name)
local BFAC 	= LibStub("LibBabble-Faction-3.0"):GetLookupTable()

local debugger	= _G.tekDebug and _G.tekDebug:GetFrame(private.addon_name)

private.build_num = select(2, _G.GetBuildInfo())

private.custom_list	= {}
private.mob_list	= {}
private.quest_list	= {}
private.recipe_list	= {}
private.reputation_list	= {}
private.trainer_list	= {}
private.seasonal_list	= {}
private.vendor_list	= {}
private.location_list	= {}
private.acquire_list	= {}

------------------------------------------------------------------------------
-- Constants.
------------------------------------------------------------------------------
local PROFESSION_INIT_FUNCS = {}

------------------------------------------------------------------------------
-- Database tables
------------------------------------------------------------------------------
local AllSpecialtiesTable = {}
local SpecialtyTable

-- Filter flags and acquire types - defined in Constants.lua
local F 	= private.filter_flags
local A		= private.acquire_types

-- Global Frame Variables
addon.optionsFrame = {}

-------------------------------------------------------------------------------
-- Check to see if we have mandatory libraries loaded. If not, notify the user
-- which are missing and return.
-------------------------------------------------------------------------------
local MissingLibraries
do
	local REQUIRED_LIBS = {
		"AceLocale-3.0",
		"LibBabble-Boss-3.0",
		"LibBabble-Faction-3.0",
		"LibBabble-Zone-3.0",
	}
	function MissingLibraries()
		local missing = false

		for idx, lib in ipairs(REQUIRED_LIBS) do
			if not LibStub:GetLibrary(lib, true) then
				missing = true
				addon:Print(L["MISSING_LIBRARY"]:format(lib))
			end
		end
		return missing
	end
end -- do

if MissingLibraries() then
	--@debug@
	addon:Print("You are using a development version of ARL.  As per WowAce standards, externals are not set up.  You will have to install all necessary libraries in order for the addon to function correctly.")
	--@end-debug@
	_G.AckisRecipeList = nil
	return
end

-------------------------------------------------------------------------------
-- Define the static popups we're going to call when people haven't scanned or
-- when current filters are blocking all recipes from being displayed.
-------------------------------------------------------------------------------
_G.StaticPopupDialogs["ARL_NOTSCANNED"] = {
	text = L["NOTSCANNED"],
	button1 = _G.OKAY,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

_G.StaticPopupDialogs["ARL_ALLFILTERED"] = {
	text = L["ALL_FILTERED"],
	button1 = _G.OKAY,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

_G.StaticPopupDialogs["ARL_ALLKNOWN"] = {
	text = L["ARL_ALLKNOWN"],
	button1 = _G.OKAY,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

_G.StaticPopupDialogs["ARL_ALLEXCLUDED"] = {
	text = L["ARL_ALLEXCLUDED"],
	button1 = _G.OKAY,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

_G.StaticPopupDialogs["ARL_SEARCHFILTERED"] = {
	text = L["ARL_SEARCHFILTERED"],
	button1 = _G.OKAY,
	timeout = 0,
	exclusive = 1,
	whileDead = 1,
	hideOnEscape = 1
}

-------------------------------------------------------------------------------
-- Close all possible pop-up windows
-------------------------------------------------------------------------------
function addon:ClosePopups()
	_G.StaticPopup_Hide("ARL_NOTSCANNED")
	_G.StaticPopup_Hide("ARL_ALLFILTERED")
	_G.StaticPopup_Hide("ARL_ALLKNOWN")
	_G.StaticPopup_Hide("ARL_ALLEXCLUDED")
	_G.StaticPopup_Hide("ARL_SEARCHFILTERED")
end

-------------------------------------------------------------------------------
-- Debugger.
-------------------------------------------------------------------------------
function addon:Debug(...)
	if debugger then
		debugger:AddMessage(string.format(...))
	else
		--@debug@
		self:Printf(...)
		--@end-debug@
	end
end

do
	local output = {}

	function addon:DumpMembers(match)
		table.wipe(output)
		table.insert(output, "Addon Object members.\n")

		local count = 0

		for key, value in pairs(self) do
			local val_type = type(value)

			if not match or val_type == match then
				table.insert(output, ("%s (%s)"):format(key, val_type))
				count = count + 1
			end
		end
		table.insert(output, ("\n%d found\n"):format(count))
		self:DisplayTextDump(nil, nil, table.concat(output, "\n"))
	end
end	-- do

-------------------------------------------------------------------------------
-- Initialization functions
-------------------------------------------------------------------------------
function addon:OnInitialize()
	-- Set default options, which are to include everything in the scan
	local defaults = {
		global = {
			-- Saving alts tradeskills (needs to be global so all profiles can access it)
			tradeskill = {},
		},
		profile = {
			-------------------------------------------------------------------------------
			-- Frame options
			-------------------------------------------------------------------------------
			frameopts = {
				offsetx = 0,
				offsety = 0,
				anchorTo = "",
				anchorFrom = "",
				uiscale = 1,
				small_list_font = true,
			},

			-------------------------------------------------------------------------------
			-- Tooltip Options
			-------------------------------------------------------------------------------
			tooltip = {
				scale = 1,
				acquire_fontsize = 11,
			},
			-------------------------------------------------------------------------------
			-- Sorting Options
			-------------------------------------------------------------------------------
			sorting = "Ascending",
			current_tab = 3,		-- Name tab
			skill_view = false,		-- Sort the recipes by skill level instead of name?

			-------------------------------------------------------------------------------
			-- Display Options
			-------------------------------------------------------------------------------
			includefiltered = false,
			includeexcluded = false,
			closeguionskillclose = false,
			ignoreexclusionlist = false,
			scanbuttonlocation = "TR",
			spelltooltiplocation = "Right",
			acquiretooltiplocation = "Right",
			recipes_in_tooltips = true,
			max_recipes_in_tooltips = 10,
			hide_tooltip_hint = false,
			hidepopup = false,
			minimap = true,
			worldmap = true,
			autoscanmap = false,
			scantrainers = false,
			scanvendors = false,
			autoloaddb = false,
			maptrainer = false,
			mapvendor = true,
			mapmob = true,
			mapquest = true,

			-------------------------------------------------------------------------------
			-- Text Dump Options
			-------------------------------------------------------------------------------
			textdumpformat = "BBCode",

			-------------------------------------------------------------------------------
			-- Recipe Exclusion
			-------------------------------------------------------------------------------
			exclusionlist = {},

			-------------------------------------------------------------------------------
			-- Filter Options
			-------------------------------------------------------------------------------
			filters = {
				-------------------------------------------------------------------------------
				-- General Filters
				-------------------------------------------------------------------------------
				general = {
					faction = true,
					specialty = false,
					skill = true,
					known = false,
					unknown = true,
					retired = false,
				},
				-------------------------------------------------------------------------------
				-- Obtain Filters
				-------------------------------------------------------------------------------
				obtain = {
					trainer = true,
					vendor = true,
					instance = true,
					raid = true,
					seasonal = true,
					quest = true,
					pvp = true,
					discovery = true,
					worlddrop = true,
					mobdrop = true,
					achievement = true,
					expansion0 = true,
					expansion1 = true,
					expansion2 = true,
					expansion3 = true,
				},
				-------------------------------------------------------------------------------
				-- Item Filters (Armor/Weapon)
				-------------------------------------------------------------------------------
				item = {
					armor = {
						cloth = true,
						leather = true,
						mail = true,
						plate = true,
						trinket = true,
						cloak = true,
						ring = true,
						necklace = true,
						shield = true,
					},
					weapon = {
						onehand = true,
						twohand = true,
						axe = true,
						sword = true,
						mace = true,
						polearm = true,
						dagger = true,
						fist = true,
						staff = true,
						wand = true,
						thrown = true,
						bow = true,
						crossbow = true,
						gun = true,
					},
				},
				-------------------------------------------------------------------------------
				-- Quality Filters
				-------------------------------------------------------------------------------
				quality = {
					common = true,
					uncommon = true,
					rare = true,
					epic = true,
				},
				-------------------------------------------------------------------------------
				-- Binding Filters
				-------------------------------------------------------------------------------
				binding = {
					itemboe = true,
					itembop = true,
					recipebop = true,
					recipeboe = true,
				},
				-------------------------------------------------------------------------------
				-- Player Role Filters
				-------------------------------------------------------------------------------
				player = {
					melee = true,
					tank = true,
					healer = true,
					caster = true,
				},
				-------------------------------------------------------------------------------
				-- Reputation Filters
				-------------------------------------------------------------------------------
				rep = {
					aldor = true,
					scryer = true,
					argentdawn = true,
					ashtonguedeathsworn = true,
					cenarioncircle = true,
					cenarionexpedition = true,
					consortium = true,
					hellfire = true,
					keepersoftime = true,
					nagrand = true,
					lowercity = true,
					scaleofthesands = true,
					shatar = true,
					shatteredsun = true,
					sporeggar = true,
					thoriumbrotherhood = true,
					timbermaw = true,
					violeteye = true,
					zandalar = true,
					argentcrusade = true,
					frenzyheart = true,
					ebonblade = true,
					kirintor = true,
					sonsofhodir = true,
					kaluak = true,
					oracles = true,
					wyrmrest = true,
					wrathcommon1 = true,
					wrathcommon2 = true,
					wrathcommon3 = true,
					wrathcommon4 = true,
					wrathcommon5 = true,
					ashenverdict = true,
					catacommon1 = true,
					catacommon2 = true,
					guardiansofhyjal = true,
					ramkahen = true,
					earthenring = true,
					therazane = true,
				},
				-------------------------------------------------------------------------------
				-- Class Filters
				-------------------------------------------------------------------------------
				classes = {
					deathknight = true,
					druid = true,
					hunter = true,
					mage = true,
					paladin = true,
					priest = true,
					rogue = true,
					shaman = true,
					warlock = true,
					warrior = true,
				},
			}
		}
	}
	self.db = LibStub("AceDB-3.0"):New("ARLDB2", defaults)

	if not self.db then
		self:Print("Error: Database not loaded correctly.  Please exit out of WoW and delete the ARL database file (AckisRecipeList.lua) found in: \\World of Warcraft\\WTF\\Account\\<Account Name>>\\SavedVariables\\")
		return
	end
	local version = _G.GetAddOnMetadata("AckisRecipeList", "Version")
	local debug_version = false
	local alpha_version = false

	--@debug@
	debug_version = true
	--@end-debug@

	--@alpha@
	alpha_version = true
	--@end-alpha@

	version = debug_version and "Devel" or (alpha_version and version .. "-Alpha") or version

	self.version = version

	self:SetupOptions()

	-- Register slash commands
	self:RegisterChatCommand("arl", "ChatCommand")
	self:RegisterChatCommand("ackisrecipelist", "ChatCommand")

	-------------------------------------------------------------------------------
	-- Create the scan button
	-------------------------------------------------------------------------------
	local scan_button = _G.CreateFrame("Button", nil, _G.UIParent, "UIPanelButtonTemplate")
	scan_button:SetHeight(20)

	scan_button:RegisterForClicks("LeftButtonUp")
	scan_button:SetScript("OnClick",
			      function(self, button, down)
				      local cur_profession = _G.GetTradeSkillLine()
				      local MainPanel = addon.Frame
				      local prev_profession

				      if MainPanel then
					      prev_profession = MainPanel.prof_name or private.ordered_professions[MainPanel.profession]
				      end

				      local shift_key = _G.IsShiftKeyDown()
				      local alt_key = _G.IsAltKeyDown()
				      local ctrl_key = _G.IsControlKeyDown()

				      if shift_key and not alt_key and not ctrl_key then
					      addon:Scan(true)
				      elseif alt_key and not shift_key and not ctrl_key then
					      addon:ClearWaypoints()
				      elseif ctrl_key and not shift_key and not alt_key then
					      local current_prof = _G.GetTradeSkillLine()
					      addon:DumpProfession(current_prof)
				      elseif not shift_key and not alt_key and not ctrl_key then
					      if MainPanel and MainPanel:IsVisible() and prev_profession == cur_profession then
						      MainPanel:Hide()
					      else
						      addon:Scan(false)
						      addon:AddWaypoint()
					      end
				      end
			      end)

	scan_button:SetScript("OnEnter",
			      function(self)
				      local tooltip = _G.GameTooltip

				      _G.GameTooltip_SetDefaultAnchor(tooltip, self)
				      tooltip:SetText(L["SCAN_RECIPES_DESC"])
				      tooltip:Show()
			      end)
	scan_button:SetScript("OnLeave", function() _G.GameTooltip:Hide() end)
	scan_button:SetText(L["Scan"])

	self.scan_button = scan_button

	-------------------------------------------------------------------------------
	-- Populate the profession initialization functions.
	-------------------------------------------------------------------------------
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51304)] = addon.InitAlchemy
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51300)] = addon.InitBlacksmithing
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51296)] = addon.InitCooking
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51313)] = addon.InitEnchanting
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51306)] = addon.InitEngineering
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45542)] = addon.InitFirstAid
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51302)] = addon.InitLeatherworking
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(32606)] = addon.InitSmelting
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51309)] = addon.InitTailoring
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51311)] = addon.InitJewelcrafting
	PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45363)] = addon.InitInscription
	PROFESSION_INIT_FUNCS[private.runeforging_name] = addon.InitRuneforging

	-------------------------------------------------------------------------------
	-- Hook GameTooltip so we can show information on mobs that drop/sell/train
	-------------------------------------------------------------------------------
        _G.GameTooltip:HookScript("OnTooltipSetUnit",
		       function(self)
			       if not addon.db.profile.recipes_in_tooltips then
				       return
			       end
			       local name, unit = self:GetUnit()

			       if not unit then
				       return
			       end
			       local guid = _G.UnitGUID(unit)

			       if not guid then
				       return
			       end
			       local id_num = tonumber(guid:sub(-12,-9), 16)
			       local unit = private.mob_list[id_num] or private.vendor_list[id_num] or private.trainer_list[id_num]

			       if not unit or not unit.item_list then
				       return
			       end
			       local player = private.Player
			       local recipe_list = private.recipe_list
			       local shifted = _G.IsShiftKeyDown()
			       local count = 0

			       for spell_id in pairs(unit.item_list) do
				       local recipe = recipe_list[spell_id]
				       local recipe_prof = _G.GetSpellInfo(recipe.profession)

				       if player.scanned_professions[recipe_prof] then
					       local skill_level = player.professions[recipe_prof]
					       local has_level = skill_level and (type(skill_level) == "boolean" and true or skill_level >= recipe.skill_level)

					       if ((not recipe:HasState("KNOWN") and has_level) or shifted) and player:HasRecipeFaction(recipe) then
						       local _, _, _, hex = _G.GetItemQualityColor(recipe.quality)

						       self:AddLine(("%s: |c%s%s|r (%d)"):format(recipe.profession, hex, recipe.name, recipe.skill_level))
						       count = count + 1
					       end
				       end

				       if count >= addon.db.profile.max_recipes_in_tooltips then
					       break
				       end
			       end
		       end)
end

---Function run when the addon is enabled.  Registers events and pre-loads certain variables.
function addon:OnEnable()
	self:RegisterEvent("TRADE_SKILL_SHOW")	-- Make addon respond to the tradeskill windows being shown
	self:RegisterEvent("TRADE_SKILL_CLOSE")	-- Addon responds to tradeskill windows being closed.
	self:RegisterEvent("TRADE_SKILL_UPDATE")

	if addon.db.profile.scantrainers then
		self:RegisterEvent("TRAINER_SHOW")
	end

	if addon.db.profile.scanvendors then
		self:RegisterEvent("MERCHANT_SHOW")
	end

	-------------------------------------------------------------------------------
	-- Set the parent and scripts for addon.scan_button.
	-------------------------------------------------------------------------------
	local scan_button = self.scan_button

	if _G.Skillet and _G.Skillet:IsActive() then
		scan_button:SetParent(_G.SkilletFrame)
		_G.Skillet:AddButtonToTradeskillWindow(scan_button)
		scan_button:SetWidth(80)
	elseif _G.MRTAPI then
		_G.MRTAPI:RegisterHandler("TradeSkillWindowOnShow",
						function()
							scan_button:SetParent(_G.MRTSkillFrame)
							scan_button:ClearAllPoints()
							scan_button:SetPoint("RIGHT", _G.MRTSkillFrameCloseButton, "LEFT", 4, 0)
							scan_button:SetWidth(scan_button:GetTextWidth() + 10)
							scan_button:Show()
						end)
  	elseif _G.ATSWFrame then
		scan_button:SetParent(_G.ATSWFrame)
		scan_button:ClearAllPoints()

		if _G.TradeJunkieMain and _G.TJ_OpenButtonATSW then
			scan_button:SetPoint("RIGHT", _G.TJ_OpenButtonATSW, "LEFT", 0, 0)
		else
			scan_button:SetPoint("RIGHT", _G.ATSWOptionsButton, "LEFT", 0, 0)
		end
		scan_button:SetHeight(_G.ATSWOptionsButton:GetHeight())
		scan_button:SetWidth(_G.ATSWOptionsButton:GetWidth())
	elseif _G.CauldronFrame then
		scan_button:SetParent(_G.CauldronFrame)
		scan_button:ClearAllPoints()
		scan_button:SetPoint("TOP", _G.CauldronFrame, "TOPRIGHT", -58, -52)
		scan_button:SetWidth(90)
	elseif _G.BPM_ShowTrainerFrame then
		scan_button:SetParent(_G.BPM_ShowTrainerFrame)
		scan_button:ClearAllPoints()
		scan_button:SetPoint("RIGHT", _G.BPM_ShowTrainerFrame, "LEFT", 4, 0)
		scan_button:SetWidth(scan_button:GetTextWidth() + 10)
		scan_button:Show()
	end

	local buttonparent = scan_button:GetParent()
	local framelevel = buttonparent:GetFrameLevel()
	local framestrata = buttonparent:GetFrameStrata()

	-- Set the frame level of the button to be 1 deeper than its parent
	scan_button:SetFrameLevel(framelevel + 1)
	scan_button:SetFrameStrata(framestrata)
	scan_button:Enable()

	-- Add an option so that ARL will work with Manufac
	if _G.Manufac then
		_G.Manufac.options.args.ARLScan = {
			type = 'execute',
			name = L["Scan"],
			desc = L["SCAN_RECIPES_DESC"],
			func = function() addon:Scan(false) end,
			order = 550,
		}
	end
	private.Player:Initialize()

	-------------------------------------------------------------------------------
	-- Initialize the SpecialtyTable and AllSpecialtiesTable.
	-------------------------------------------------------------------------------
	do
		--[[
		local AlchemySpec = {
			[_G.GetSpellInfo(28674)] = 28674,
			[_G.GetSpellInfo(28678)] = 28678,
			[_G.GetSpellInfo(28676)] = 28676,
		}
		]]--

		--[[
		local BlacksmithSpec = {
			[_G.GetSpellInfo(9788)] = 9788,		-- Armorsmith
			[_G.GetSpellInfo(17041)] = 17041,	-- Master Axesmith
			[_G.GetSpellInfo(17040)] = 17040,	-- Master Hammersmith
			[_G.GetSpellInfo(17039)] = 17039,	-- Master Swordsmith
			[_G.GetSpellInfo(9787)] = 9787,		-- Weaponsmith
		}
		]]--

		local EngineeringSpec = {
			[_G.GetSpellInfo(20219)] = 20219, -- Gnomish
			[_G.GetSpellInfo(20222)] = 20222, -- Goblin
		}

		--[[
		local LeatherworkSpec = {
			[_G.GetSpellInfo(10657)] = 10657, -- Dragonscale
			[_G.GetSpellInfo(10659)] = 10659, -- Elemental
			[_G.GetSpellInfo(10661)] = 10661, -- Tribal
		}
		]]--

		--[[
		local TailorSpec = {
			[_G.GetSpellInfo(26797)] = 26797, -- Spellfire
			[_G.GetSpellInfo(26801)] = 26801, -- Shadoweave
			[_G.GetSpellInfo(26798)] = 26798, -- Primal Mooncloth
		}
		]]--

		SpecialtyTable = {
			--[_G.GetSpellInfo(51304)] = AlchemySpec,
			--[_G.GetSpellInfo(51300)] = BlacksmithSpec,
			[_G.GetSpellInfo(51306)] = EngineeringSpec,
			--[_G.GetSpellInfo(51302)] = LeatherworkSpec,
			--[_G.GetSpellInfo(51309)] = TailorSpec,
		}

		-- Populate the Specialty table with all Specialties, adding alchemy even though no recipes have alchemy filters
		--for i in pairs(AlchemySpec) do AllSpecialtiesTable[i] = true end
		--for i in pairs(BlacksmithSpec) do AllSpecialtiesTable[i] = true end
		for i in pairs(EngineeringSpec) do AllSpecialtiesTable[i] = true end
		--for i in pairs(LeatherworkSpec) do AllSpecialtiesTable[i] = true end
		--for i in pairs(TailorSpec) do AllSpecialtiesTable[i] = true end
	end	-- do
end

---Run when the addon is disabled. Ace3 takes care of unregistering events, etc.
function addon:OnDisable()
	if addon.Frame then
		addon.Frame:Hide()
	end

	-- Remove the option from Manufac
	if _G.Manufac then
		_G.Manufac.options.args.ARLScan = nil
	end
end

-------------------------------------------------------------------------------
-- Event handling functions
-------------------------------------------------------------------------------

---Event used for datamining when a trainer is shown.
function addon:TRAINER_SHOW()
	self:ScanTrainerData(true)
end

---Event used for datamining when a vendor is shown.
function addon:MERCHANT_SHOW()
	self:ScanVendor()
end

do
	local GetTradeSkillListLink = _G.GetTradeSkillListLink
	local UnitName = _G.UnitName
	local GetRealmName = _G.GetRealmName

	function addon:TRADE_SKILL_SHOW()
		local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild()
		local tradelink = GetTradeSkillListLink()

		local pname = UnitName("player")
		local prealm = GetRealmName()
		local tradename = _G.GetTradeSkillLine()

		-- Actual alt information saved here. -Torhal
		addon.db.global.tradeskill = addon.db.global.tradeskill or {}
		addon.db.global.tradeskill[prealm] = addon.db.global.tradeskill[prealm] or {}
		addon.db.global.tradeskill[prealm][pname] = addon.db.global.tradeskill[prealm][pname] or {}

		-- If this is our own skill, save it. Otherwise, make sure it's gone.
		addon.db.global.tradeskill[prealm][pname][tradename] = (not is_linked) and tradelink or nil

		local scan_button = self.scan_button
		local scan_parent = scan_button:GetParent()

		if not scan_parent or scan_parent == _G.UIParent then
			scan_button:SetParent(_G.TradeSkillFrame)
			scan_parent = scan_button:GetParent()
		end

		if scan_parent == _G.TradeSkillFrame then
			scan_button:ClearAllPoints()

			local loc = addon.db.profile.scanbuttonlocation

			if loc == "TR" then
				scan_button:SetPoint("RIGHT", _G.TradeSkillFrameCloseButton, "LEFT",4,0)
			elseif loc == "TL" then
				scan_button:SetPoint("LEFT", _G.TradeSkillFramePortrait, "RIGHT",2,12)
			elseif loc == "BR" then
				scan_button:SetPoint("TOP", _G.TradeSkillCancelButton, "BOTTOM",0,-5)
			elseif loc == "BL" then
				scan_button:SetPoint("TOP", _G.TradeSkillCreateAllButton, "BOTTOM",0,-5)
			end
			scan_button:SetWidth(scan_button:GetTextWidth() + 10)
		end
		scan_button:Show()
	end
end

function addon:TRADE_SKILL_CLOSE()
	if self.Frame and addon.db.profile.closeguionskillclose then
		self.Frame:Hide()
	end

	if not _G.Skillet then
		addon.scan_button:Hide()
	end
end

do
	local last_update = 0
	local updater = _G.CreateFrame("Frame", nil, _G.UIParent)

	updater:Hide()
	updater:SetScript("OnUpdate",
			  function(self, elapsed)
				  last_update = last_update + elapsed

				  if last_update >= 0.5 then
					  local profession = _G.GetTradeSkillLine()

					  if profession ~= "UNKNOWN" then
						  addon:Scan(false, true)
					  end
					  self:Hide()
				  end
			  end)

	function addon:TRADE_SKILL_UPDATE(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
		if not self.Frame or not self.Frame:IsVisible() then
			return
		end

		if not updater:IsVisible() then
			last_update = 0
			updater:Show()
		end
	end
end

-------------------------------------------------------------------------------
-- ARL Logic Functions
-------------------------------------------------------------------------------
function addon:InitializeProfession(profession)
	if not profession then
		--@alpha@
		addon:Print("nil profession passed to InitializeProfession()")
		--@end-alpha@
		return
	end

	if profession == private.professions["Smelting"] then
		profession = private.mining_name
	end
	local func = PROFESSION_INIT_FUNCS[profession]

	if func then
		func(addon)
		PROFESSION_INIT_FUNCS[profession] = nil
	end
end

do
	local fa = _G.GetSpellInfo(45542)

	-- Code snippet stolen from GearGuage by Torhal and butchered by Ackis
	local function StrSplit(input)
		if not input then return nil, nil end
		local arg1, arg2, var1

		arg1, var1 = input:match("^([^%s]+)%s*(.*)$")
		arg1 = (arg1 and arg1:lower() or input:lower())

		if var1 then
			-- Small hack to get code to work with first aid.
			if var1:lower() == fa:lower() then
				arg2 = var1
			else
				local var2
				arg2, var2 = var1:match("^([^%s]+)%s*(.*)$")
				arg2 = (arg2 and arg2:lower() or var1:lower())
			end
		end
		return arg1, arg2
	end

	-- Determines what to do when the slash command is called.
	function addon:ChatCommand(input)

		local arg1, arg2 = StrSplit(input)

		-- Open About panel if there's no parameters or if we do /arl about
		if not arg1 or (arg1 and arg1:trim() == "") or arg1 == L["Sorting"]:lower() or arg1 == L["Sort"]:lower() or arg1 == _G.DISPLAY:lower() then
			_G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame)
		elseif arg1 == L["About"]:lower() then
			if self.optionsFrame["About"] then
				_G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["About"])
			else
				_G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame)
			end
		elseif arg1 == L["Profile"]:lower() then
			_G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Profiles"])
		elseif arg1 == L["Documentation"]:lower() then
			_G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Documentation"])
		elseif arg1 == L["Scan"]:lower() then
			if not arg2 then
				self:Print(L["COMMAND_LINE_SCAN"])
			else
				_G.CastSpellByName(arg2)

				if self.Frame and self.Frame:IsVisible() then
					self.Frame:Hide()
				else
					self:Scan(false, false)
				end
			end
		elseif arg1 == "scanprof" then
			self:ScanProfession("all")
		elseif arg1 == "tradelinks" then
			self:GenerateLinks()
		else
			-- What happens when we get here?
			LibStub("AceConfigCmd-3.0"):HandleCommand("arl", "Ackis Recipe List", arg1)
		end
	end
end

--- Public API function to initialize all of the lookup lists - self-nils once run.
-- @name AckisRecipeList:InitializeLookups()
-- @usage if AckisRecipeList.InitializeLookups then AckisRecipeList:InitializeLookups() end
function addon:InitializeLookups()
	self:InitCustom(private.custom_list)
	self:InitMob(private.mob_list)
	self:InitQuest(private.quest_list)
	self:InitReputation(private.reputation_list)
	self:InitTrainer(private.trainer_list)
	self:InitSeasons(private.seasonal_list)
	self:InitVendor(private.vendor_list)

	self.InitializeLookups = nil
end

-------------------------------------------------------------------------------
-- Recipe Scanning Functions
-------------------------------------------------------------------------------
do
	local current_recipe_count, previous_recipe_count = 0, 0

	-- List of tradeskill headers, used in addon:Scan()
	local header_list = {}

	-- Toggles a recipe's stats based on whether it's linked or actually known.
	local function SetRecipeAsKnownOrLinked(recipe, is_linked)
		if is_linked then
			recipe:AddState("LINKED")
		else
			recipe:AddState("KNOWN")
			recipe:RemoveState("LINKED")
		end
	end

	--- Causes a scan of the tradeskill to be conducted. Function called when the scan button is clicked.   Parses recipes and displays output
	-- @name AckisRecipeList:Scan
	-- @usage AckisRecipeList:Scan(true)
	-- @param textdump Boolean indicating if we want the output to be a text dump, or if we want to use the ARL GUI
	-- @return A frame with either the text dump, or the ARL frame
	function addon:Scan(textdump, is_refresh)
		local current_prof, prof_level = _G.GetTradeSkillLine()

		if current_prof == private.runeforging_name then
			prof_level = _G.UnitLevel("player")
		end

		-- Bail if we haven't opened a tradeskill frame.
		if current_prof == "UNKNOWN" then
			self:Print(L["OpenTradeSkillWindow"])
			return
		end
		local player = private.Player
		player:SetProfessions()

		-- Set the current profession level, and update the cached data.
		private.current_profession_scanlevel = prof_level

		-- Make sure we're only updating a profession the character actually knows - this could be a scan from a tradeskill link.
		local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild()

		if not is_linked then
			player.scanned_professions[current_prof] = true
		end

		-- Get the current profession Specialty
		local specialty = SpecialtyTable[current_prof]

		-- Get the indexes of the spells in the spell book which may contain a speciality
		local ProfessionSpecialIndex = {}

		ProfessionSpecialIndex[1] = PrimaryProfession1SpellButtonTop:GetID() + PrimaryProfession1SpellButtonTop:GetParent().spellOffset
		ProfessionSpecialIndex[2] = PrimaryProfession1SpellButtonBottom:GetID() + PrimaryProfession1SpellButtonBottom:GetParent().spellOffset
		ProfessionSpecialIndex[3] = PrimaryProfession2SpellButtonTop:GetID() + PrimaryProfession2SpellButtonTop:GetParent().spellOffset
		ProfessionSpecialIndex[4] = PrimaryProfession2SpellButtonBottom:GetID() + PrimaryProfession2SpellButtonBottom:GetParent().spellOffset

		for i,j in pairs(ProfessionSpecialIndex) do

			local spellName = GetSpellBookItemName(j, "profession")
			if not spellName then
				player["Specialty"] = nil
				break
			elseif specialty and specialty[spellName] then
				player["Specialty"] = specialty[spellName]
			end

		end

		if self.InitializeLookups then
			self:InitializeLookups()
		end
		addon:InitializeProfession(current_prof)

		-------------------------------------------------------------------------------
		-- Scan all recipes and mark the ones we know
		-------------------------------------------------------------------------------
		table.wipe(header_list)

		-- Save the current state of the TradeSkillFrame so it can be restored after we muck with it.
		local have_materials = _G.TradeSkillFrame.filterTbl.hasMaterials
		local have_skillup = _G.TradeSkillFrame.filterTbl.hasSkillUp

		if _G.MRTAPI then
			_G.MRTAPI:PushFilterSelection()
		else
			if not _G.Skillet and have_materials then
				_G.TradeSkillFrame.filterTbl.hasMaterials = false
				_G.TradeSkillOnlyShowMakeable(false)
			end
			if not _G.Skillet and have_skillup then
				_G.TradeSkillFrame.filterTbl.hasSkillUp = false
				_G.TradeSkillOnlyShowSkillUps(false)
			end
			_G.SetTradeSkillInvSlotFilter(0, 1, 1)
			_G.TradeSkillUpdateFilterBar()
			_G.TradeSkillFrame_Update()

			-- Expand all headers so we can see all the recipes there are
			for i = _G.GetNumTradeSkills(), 1, -1 do
				local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i)

				if tradeType == "header" and not isExpanded then
					header_list[name] = true
					_G.ExpandTradeSkillSubClass(i)
				end
			end
		end
		local recipe_list = private.recipe_list
		local recipes_found = 0
		local SF = private.recipe_state_flags
		local spell_overwrite_map = private.spell_overwrite_map

		for i = 1, _G.GetNumTradeSkills() do
			local tradeName, tradeType = _G.GetTradeSkillInfo(i)

			if tradeType ~= "header" then
				local spell_link = _G.GetTradeSkillRecipeLink(i)
				local spell_string = spell_link:match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)")
				local spell_id = tonumber(spell_string)
				local recipe = recipe_list[spell_id]

				if recipe then
					-- Mark the first rank of the spell as known if we know rank 2 for certain recipes.
					-- This is only done for recipes which when you learn the higher rank, you lose the
					-- ability to learn the lower rank.

					-- If we have it in the mapping, set the lower rank spell to known
					if spell_overwrite_map[spell_id] then
						local overwrite_recipe = recipe_list[spell_overwrite_map[spell_id]]

						if overwrite_recipe then
							SetRecipeAsKnownOrLinked(overwrite_recipe, is_linked)
						else
							self:Debug(tradeName .. " " .. spell_overwrite_map[spell_id] .. L["MissingFromDB"])
						end
					end
					SetRecipeAsKnownOrLinked(recipe, is_linked)
					recipes_found = recipes_found + 1
				else
					self:Debug(tradeName .. " " .. spell_string .. L["MissingFromDB"])
				end
			end
		end

		-- Restore the state of the things we changed.
		if _G.MRTAPI then
			_G.MRTAPI:PopFilterSelection()
		else
			for i = _G.GetNumTradeSkills(), 1, -1 do
				local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i)

				if header_list[name] then
					_G.CollapseTradeSkillSubClass(i)
				end
			end
			_G.TradeSkillFrame.filterTbl.hasMaterials = have_materials
			_G.TradeSkillOnlyShowMakeable(have_materials)
			_G.TradeSkillFrame.filterTbl.hasSkillUp = have_skillup
			_G.TradeSkillOnlyShowSkillUps(have_skillup)

			_G.TradeSkillUpdateFilterBar()
			_G.TradeSkillFrame_Update()
		end
		previous_recipe_count = current_recipe_count
		current_recipe_count = recipes_found

		if is_refresh and previous_recipe_count == recipes_found then
			return
		end
		player:UpdateReputations()

		-------------------------------------------------------------------------------
		-- Everything is ready - display the GUI or dump the list to text.
		-------------------------------------------------------------------------------
		if textdump then
			self:DisplayTextDump(recipe_list, current_prof)
		else
			if private.InitializeFrame then
				private.InitializeFrame()
			end
			self.Frame:Display(current_prof, is_linked)
		end
	end
end

-------------------------------------------------------------------------------
-- Text dumping functions
-------------------------------------------------------------------------------

--------------------------------------------------------------------------------
--- Creates a new frame with the contents of a text dump so you can copy and paste
-- Code borrowed from Antiarc (Chatter) with permission
-- @name AckisRecipeList:DisplayTextDump
-- @param RecipeDB The database (array) which you wish read data from.
-- @param profession Which profession are you displaying data for
-- @param text The text to be dumped
--------------------------------------------------------------------------------
do
	local copy_frame = _G.CreateFrame("Frame", "ARLCopyFrame", _G.UIParent)
	copy_frame:SetBackdrop({
				       bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]],
				       edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]],
				       tile = true,
				       tileSize = 16,
				       edgeSize = 16,
				       insets = {
					       left = 3,
					       right = 3,
					       top = 5,
					       bottom = 3
				       }
			       })
	copy_frame:SetBackdropColor(0, 0, 0, 1)
	copy_frame:SetWidth(750)
	copy_frame:SetHeight(400)
	copy_frame:SetPoint("CENTER", _G.UIParent, "CENTER")
	copy_frame:SetFrameStrata("DIALOG")

	table.insert(_G.UISpecialFrames, "ARLCopyFrame")

	local scrollArea = _G.CreateFrame("ScrollFrame", "ARLCopyScroll", copy_frame, "UIPanelScrollFrameTemplate")
	scrollArea:SetPoint("TOPLEFT", copy_frame, "TOPLEFT", 8, -30)
	scrollArea:SetPoint("BOTTOMRIGHT", copy_frame, "BOTTOMRIGHT", -30, 8)

	local edit_box = _G.CreateFrame("EditBox", nil, copy_frame)
	edit_box:SetMultiLine(true)
	edit_box:SetMaxLetters(0)
	edit_box:EnableMouse(true)
	edit_box:SetAutoFocus(true)
	edit_box:SetFontObject("ChatFontNormal")
	edit_box:SetWidth(650)
	edit_box:SetHeight(270)
	edit_box:SetScript("OnEscapePressed",
			   function()
				   copy_frame:Hide()
			   end)
	edit_box:HighlightText(0)

	scrollArea:SetScrollChild(edit_box)

	local close = _G.CreateFrame("Button", nil, copy_frame, "UIPanelCloseButton")
	close:SetPoint("TOPRIGHT", copy_frame, "TOPRIGHT")

	copy_frame:Hide()

	function addon:DisplayTextDump(RecipeDB, profession, text)
		local text = (not RecipeDB and not profession) and text or self:GetTextDump(profession)

		if text ~= "" then
			edit_box:SetText(text)
			edit_box:HighlightText(0)
			edit_box:SetCursorPosition(1)
			copy_frame:Show()
		end
	end
end	-- do

do
	-------------------------------------------------------------------------------
	-- Dumps recipe output in the format requested by the user
	-------------------------------------------------------------------------------
	local text_table = {}
	local acquire_list = {}
	local ACQUIRE_NAMES = private.acquire_names

	local GetFilterNames
	do
		local LC = _G.LOCALIZED_CLASS_NAMES_MALE
		local FILTER_NAMES

		function GetFilterNames()
			if not FILTER_NAMES then
				local is_alliance = (private.Player.faction == "Alliance")

				FILTER_NAMES = {
					[1]	= BFAC["Alliance"],
					[2]	= BFAC["Horde"],
					[3]	= L["Trainer"],
					[4]	= L["Vendor"],
					[5]	= _G.INSTANCE,
					[6]	= _G.RAID,
					[7]	= _G.EVENTS_LABEL,
					[8]	= L["Quest"],
					[9]	= _G.PVP,
					[10]	= L["World Drop"],
					[11]	= L["Mob Drop"],
					[12]	= L["Discovery"],
					[13]	= L["Retired"],
					[21]	= LC["DEATHKNIGHT"],
					[22]	= LC["DRUID"],
					[23]	= LC["HUNTER"],
					[24]	= LC["MAGE"],
					[25]	= LC["PALADIN"],
					[26]	= LC["PRIEST"],
					[27]	= LC["SHAMAN"],
					[28]	= LC["ROGUE"],
					[29]	= LC["WARLOCK"],
					[30]	= LC["WARRIOR"],
					[36]	= L["BOEFilter"],
					[37]	= L["BOPFilter"],
					[38]	= L["BOAFilter"],
					[40]	= L["RecipeBOEFilter"],
					[41]	= L["RecipeBOPFilter"],
					[42]	= L["RecipeBOAFilter"],
					[51]	= _G.MELEE,
					[52]	= _G.TANK,
					[53]	= _G.HEALER,
					[54]	= _G.DAMAGER,
					[56]	= L["Cloth"],
					[57]	= L["Leather"],
					[58]	= L["Mail"],
					[59]	= L["Plate"],
					[60]	= L["Cloak"],
					[61]	= L["Trinket"],
					[62]	= L["Ring"],
					[63]	= L["Necklace"],
					[64]	= L["Shield"],
					[66]	= L["One Hand"],
					[67]	= L["Two Hand"],
					[68]	= L["Axe"],
					[69]	= L["Sword"],
					[70]	= L["Mace"],
					[71]	= L["Polearm"],
					[72]	= L["Dagger"],
					[73]	= L["Staff"],
					[74]	= L["Wand"],
					[75]	= L["Thrown"],
					[76]	= L["Bow"],
					[77]	= L["Crossbow"],
					[79]	= L["Fist"],
					[80]	= L["Gun"],
					[96]	= BFAC["Argent Dawn"],
					[97]	= BFAC["Cenarion Circle"],
					[98]	= BFAC["Thorium Brotherhood"],
					[99]	= BFAC["Timbermaw Hold"],
					[100]	= BFAC["Zandalar Tribe"],
					[101]	= BFAC["The Aldor"],
					[102]	= BFAC["Ashtongue Deathsworn"],
					[103]	= BFAC["Cenarion Expedition"],
					[104]	= (is_alliance and BFAC["Honor Hold"] or BFAC["Thrallmar"]),
					[105]	= BFAC["The Consortium"],
					[106]	= BFAC["Keepers of Time"],
					[107]	= BFAC["Lower City"],
					[108]	= (is_alliance and BFAC["Kurenai"] or BFAC["The Mag'har"]),
					[109]	= BFAC["The Scale of the Sands"],
					[110]	= BFAC["The Scryers"],
					[111]	= BFAC["The Sha'tar"],
					[112]	= BFAC["Shattered Sun Offensive"],
					[113]	= BFAC["Sporeggar"],
					[114]	= BFAC["The Violet Eye"],
					[115]	= BFAC["Argent Crusade"],
					[116]	= BFAC["Frenzyheart Tribe"],
					[117]	= BFAC["Knights of the Ebon Blade"],
					[118]	= BFAC["Kirin Tor"],
					[119]	= BFAC["The Sons of Hodir"],
					[120]	= BFAC["The Kalu'ak"],
					[121]	= BFAC["The Oracles"],
					[122]	= BFAC["The Wyrmrest Accord"],
					[123]	= (is_alliance and BFAC["The Silver Covenant"] or BFAC["The Sunreavers"]),
					[124]	= (is_alliance and BFAC["Explorers' League"] or BFAC["The Hand of Vengeance"]),
					[125]	= (is_alliance and BFAC["Valiance Expedition"] or BFAC["Warsong Offensive"]),
					[126]	= (is_alliance and BFAC["The Frostborn"] or BFAC["The Taunka"]),
					[127]	= (is_alliance and BFAC["Alliance Vanguard"] or BFAC["Horde Expedition"]),
					[128]	= BFAC["The Ashen Verdict"],
					[129]	= (is_alliance and BFAC["Wildhammer Clan"] or BFAC["Dragonmaw Clan"]),
					[130]	= (is_alliance and BFAC["Baradin's Wardens"] or BFAC["Hellscream's Reach"]),
					[131]	= BFAC["Guardians of Hyjal"],
					[132]	= BFAC["Ramkahen"],
					[133]	= BFAC["The Earthen Ring"],
					[134]	= BFAC["Therazane"],
				}
			end
			return FILTER_NAMES
		end
	end	-- do

	---Dumps the recipe database in a format that is readable to humans (or machines)
	function addon:GetTextDump(profession)
		local output = addon.db.profile.textdumpformat
		table.wipe(text_table)

		if not output or output == "Comma" then
			table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of Comma Separated Values.\n  "):format(private.player_name, profession))
			table.insert(text_table, "Spell ID,Recipe Name,Skill Level,ARL Filter Flags,Acquire Methods,Known\n")
		elseif output == "BBCode" then
			table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of BBCode.\n"):format(private.player_name, profession))
		elseif output == "XML" then
			table.insert(text_table, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>")
		end

		local recipe_list = private.recipe_list
		local SF = private.recipe_state_flags

		for recipe_id in pairs(recipe_list) do
			local recipe = recipe_list[recipe_id]
			local recipe_prof = _G.GetSpellInfo(recipe.profession)
			local is_known = recipe:HasState("KNOWN")

			if recipe_prof == profession then
				-- CSV
				if not output or output == "Comma" then
					-- Add Spell ID, Name and Skill Level to the list
					table.insert(text_table, recipe_id)
					table.insert(text_table, ",")
					table.insert(text_table, recipe.name)
					table.insert(text_table, ",")
					table.insert(text_table, recipe.skill_level)
					table.insert(text_table, ",\"")
				-- BBCode
				elseif output == "BBCode" then
					-- Make the entry red
					if not is_known then
						table.insert(text_table, "[color=red]")
					end
					table.insert(text_table, "\n[b]" .. recipe_id .. "[/b] - " .. recipe.name .. " (" .. recipe.skill_level .. ")\n")

					-- Close Color tag
					if not is_known then
						table.insert(text_table, "[/color]\nRecipe Flags:\n[list]")
					elseif is_known then
						table.insert(text_table, "\nRecipe Flags:\n[list]")
					end
				--XML
				elseif output == "XML" then
					table.insert(text_table, "<recipe>")
					table.insert(text_table, "  <id>..recipe_id..</id>")
					table.insert(text_table, "  <name>"..recipe.name.."</name>")
					table.insert(text_table, "  <skilllevel>..recipe.skill_level..</skilllevel>")
					table.insert(text_table, "  <known>"..tostring(is_known).."</known>")
					table.insert(text_table, "  <flags>")
				--Name
				elseif output == "Name" then
					table.insert(text_table, recipe.name)
				end

				-- Add in all the filter flags
				local filter_names = GetFilterNames()
				local prev = false

				-- Find out which flags are set
				for table_index, bits in ipairs(private.bit_flags) do
					for flag_name, flag in pairs(bits) do
						local bitfield = recipe.flags[private.flag_members[table_index]]

						if bitfield and bit.band(bitfield, flag) == flag then
							if not output or output == "Comma" then
								if prev then
									table.insert(text_table, ",")
								end
								table.insert(text_table, filter_names[private.filter_flags[flag_name]])
								prev = true
								-- BBCode
							elseif output == "BBCode" then
								table.insert(text_table, "[*]"..filter_names[private.filter_flags[flag_name]])
							elseif output == "XML" then
								table.insert(text_table, "    <flag>"..filter_names[private.filter_flags[flag_name]].."</flag>")
							end
						end
					end
				end

				if not output or output == "Comma" then
					table.insert(text_table, "\",\"")
				elseif output == "BBCode" then
					table.insert(text_table, "[/list]\nAcquire Methods:\n[list]")
				elseif output == "XML" then
					table.insert(text_table, "  </flags>")
					table.insert(text_table, "  <acquire>")
				end

				-- Find out which unique acquire methods we have
				local acquire_data = recipe["acquire_data"]
				table.wipe(acquire_list)

				for acquire_type in pairs(acquire_data) do
					acquire_list[ACQUIRE_NAMES[acquire_type]] = true
				end

				-- Add all the acquire methods in
				prev = false

				for i in pairs(acquire_list) do
					if not output or output == "Comma" then
						if prev then
							table.insert(text_table, ",")
						end
						table.insert(text_table, i)
						prev = true
					elseif output == "BBCode" then
						table.insert(text_table, "[*] " .. i)
					elseif output == "XML" then
						table.insert(text_table, "<acquiremethod>"..i.."</acquiremethod>")
					end
				end

				if not output or output == "Comma" then
					table.insert(text_table, "\","..tostring(is_known).."\n")
					--if is_known then
					--	table.insert(text_table, "\",true\n")
					--else
					--	table.insert(text_table, "\",false\n")
					--end
				elseif output == "BBCode" then
					table.insert(text_table, "\n[/list]")
				elseif output == "XML" then
					table.insert(text_table, "  </acquire>")
					table.insert(text_table, "</recipe>")
				end
			end
		end	-- for
		return table.concat(text_table, "")
	end
end