--[[
Atlasloot Enhanced
Author Daviesh / Reworked by Deim of PrimalWoW / Reworked again for Ascension
Loot browser associating loot with instance bosses

Functions:
AtlasLoot:OnEnable()
AtlasLoot:SlashCommand(msg)
AtlasLoot:OptionsToggle()
AtlasLoot:OnInitialize()
AtlasLoot:ShowItemsFrame()
AtlasLoot:NavButton_OnClick()
AtlasLoot:IsLootTableAvailable(dataID)
AtlasLoot:LoadAllModules()
AtlasLoot:SetFavorites(number)
AtlasLoot:AddTooltip(frameb, tooltiptext)
]]

AtlasLoot = LibStub("AceAddon-3.0"):NewAddon("AtlasLoot", "AceEvent-3.0", "AceTimer-3.0")

local AL = LibStub("AceLocale-3.0"):GetLocale("AtlasLoot")
local BabbleInventory = AtlasLoot_GetLocaleLibBabble("LibBabble-Inventory-3.0")

--Establish version number and compatible version of Atlas
local VERSION_MAJOR = "5";
local VERSION_MINOR = "11";
local VERSION_BOSSES = "04";

AtlasLoot.Version = "AtlasLoot Ascension Edition"
AtlasLoot.DebugMessages = false
AtlasLoot.WishListVersion = 1

--Make the Dewdrop menu in the standalone loot browser accessible here
AtlasLoot.Dewdrop = AceLibrary("Dewdrop-2.0")

AtlasLoot.filterEnable = false
AtlasLoot.CurrentType = "Default"
AtlasLoot.type = {}
AtlasLoot.backEnabled = false
AtlasLoot.Difficultys = {}

-- Colours stored for code readability
local GREY = "|cff999999"
local RED = "|cffff0000"
local WHITE = "|cffFFFFFF"
local GREEN = "|cff1eff00"
local LIMEGREEN = "|cFF32CD32"
local BLUE = "|cff0070dd"
local ORANGE = "|cffFF8400"
local YELLOW = "|cffFFd200"
local itemHighlightBlue = "Interface\\AddOns\\AtlasLoot\\Images\\knownBlue"
local itemHighlightGreen = "Interface\\AddOns\\AtlasLoot\\Images\\knownGreen"

--Search panel open and close save variables
--dataID, dataSource, pFrame, tablenumber

AtlasLootCharDB = {}
AtlasLoot_TokenData = {}

local realmName = GetRealmName()

local AtlasLootDBDefaults = {
    profile = {
        EquipCompare = false,
        Opaque = false,
        ItemIDs = false,
        LastBoss = "EmptyTable",
        AtlasLootVersion = "1",
        AtlasNaggedVersion = "",
        PartialMatching = true,
        LootBrowserStyle = 1,
        LootBrowserScale = 1.0,
        SearchOn = {
            All = false,
        },
        AtlasType = "Release",
		savedState = {},
    }
}

--Set Savedvariables defaults
local DefaultSettings  = {
	{
		Database = "AtlasLootCharDB",
		{ TableName = "QuickLooks", {} },
		{ TableName = "SearchResult", {Name = "Search Result" , Type = "Search", Back = true} },
	},
	{	Database = "AtlasLootFilterDB",
		{ TableName = "VanityFilters", {} },
		{ TableName = "CraftingFilters", {} },
	}
}

--[[ TableName = Name of the saved setting
CheckBox = Global name of the checkbox if it has one and first numbered table entry is the boolean
Text = Global name of where the text and first numbered table entry is the default text 
Frame = Frame or button etc you want hidden/shown at start based on condition ]]
local function setupSettingsDB()
    for _, d in ipairs(DefaultSettings) do
		for _, def in ipairs(d) do
			if not _G[d.Database] then _G[d.Database] = {} end
			local db = _G[d.Database]
			if db[def.TableName] == nil then
				if #def > 1 then
					db[def.TableName] = {}
					for _, n in ipairs(def) do
						tinsert(db[def.TableName], n)
					end
				else
					db[def.TableName] = def[1]
				end
			end

			if def.CheckBox then
				_G[def.CheckBox]:SetChecked(db[def.TableName])
			end
			if def.Text then
				_G[def.Text]:SetText(db[def.TableName])
			end
			if def.Frame then
				if db[def.TableName] then _G[def.Frame]:Hide() else _G[def.Frame]:Show() end
			end
		end
    end
end

-- Popup Box for first time users
StaticPopupDialogs["ATLASLOOT_SETUP"] = {
  text = AL["Welcome to Atlasloot Enhanced.  Please take a moment to set your preferences."],
  button1 = AL["Setup"],
  OnAccept = function()
	  AtlasLoot:OptionsToggle();
  end,
  timeout = 0,
  whileDead = 1,
  hideOnEscape = 1
}

--[[
AtlasLoot:OnEnable():
Invoked by the VARIABLES_LOADED event.  Now that we are sure all the assets
the addon needs are in place, we can properly set up the mod
]]
function AtlasLoot:OnEnable()
    self.db = LibStub("AceDB-3.0"):New("AtlasLootDB")
    self.db:RegisterDefaults(AtlasLootDBDefaults)
	setupSettingsDB()
    if AtlasLoot_Data then
        AtlasLoot_Data["EmptyTable"] = {
			Name = AL["Select a Loot Table..."],
			{Name = AL["Select a Loot Table..."]},
		}
    end
	self.db.profile.showUnknownRecipeTooltip = self.db.profile.showUnknownRecipeTooltip or true
	if self.db.profile.knownRecipes then self.db.profile.knownRecipes  = nil end
	if IsAddOnLoaded("TomTom") then
		self.TomTomLoaded = true
	end
	--Setup for minimap icon
	self:MinimapIconSetup()
    --Add the loot browser to the special frames tables to enable closing wih the ESC key
	tinsert(UISpecialFrames, "AtlasLootDefaultFrame")
	--Set up options frame
	self:OptionsInit()
    self:CreateOptionsInfoTooltips()
    --Set visual style for the loot browser
	if self.db.profile.LootBrowserStyle then
		self:SetSkin(self.skinKeys[self.db.profile.LootBrowserStyle][1])
	end

	--If using an opaque items frame, change the alpha value of the backing texture
	if (self.db.profile.Opaque) then
        AtlasLootItemsFrame_Back:SetTexture(0, 0, 0, 1)
        Atlasloot_Difficulty_ScrollFrame_Back:SetTexture(0, 0, 0, 1)
        Atlasloot_SubTableFrame_Back:SetTexture(0, 0, 0, 1)
    else
        AtlasLootItemsFrame_Back:SetTexture(0, 0, 0, 0.05)
        Atlasloot_Difficulty_ScrollFrame_Back:SetTexture(0, 0, 0, 0.05)
        Atlasloot_SubTableFrame_Back:SetTexture(0, 0, 0, 0.05)
	end

	if((AtlasLootCharDB.AtlasLootVersion == nil) or (tonumber(AtlasLootCharDB.AtlasLootVersion) < 40301)) then
		AtlasLootCharDB.AtlasLootVersion = VERSION_MAJOR..VERSION_MINOR..VERSION_BOSSES
		self:OptionsInit()
	end

	collectgarbage("collect")

    local panel = _G["AtlasLootOptionsFrame"]
    panel.name = AL["AtlasLoot"]
    InterfaceOptions_AddCategory(panel)
    --Filter and wishlist options menus creates as part of the next 2 commands
	self:CreateWishlistOptions()
    panel = _G["AtlasLootHelpFrame"]
    panel.name = AL["Help"]
    panel.parent = AL["AtlasLoot"]
    InterfaceOptions_AddCategory(panel)
    if LibStub:GetLibrary("LibAboutPanel", true) then
        LibStub("LibAboutPanel").new(AL["AtlasLoot"], "AtlasLoot")
    end
    self:UpdateLootBrowserScale()
	-- Is wishlist item disabled on load or not
	if AtlasLootWishList["Options"][UnitName("player")]["AutoSortWishlist"] then
		AtlasLootItemsFrame_Wishlist_UnLock:Disable()
	else
		AtlasLootItemsFrame_Wishlist_UnLock:Enable()
	end
	self:LoadItemIDsDatabase()
	self:LoadTradeskillRecipes()
	self:PopulateProfessions()
	self:CreateVanityCollection()
	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
end

function AtlasLoot:Reset(data)
    AtlasLootDefaultFrame:Hide()
    if data == "frames" then
		AtlasLootDefaultFrame:ClearAllPoints()
		AtlasLootDefaultFrame:SetPoint("CENTER", "UIParent", "CENTER", 0, 0)
        self.db.profile.LootBrowserScale = 1.0
        self:UpdateLootBrowserScale()
    elseif data == "quicklooks" then
        AtlasLootCharDB["QuickLooks"] = {}
    elseif data == "wishlist" then
		AtlasLootWishList = {}
		self:WishlistSetup()
        AtlasLootCharDB["SearchResult"] = {}
    elseif data == "all" then
		AtlasLootDefaultFrame:ClearAllPoints()
		AtlasLootDefaultFrame:SetPoint("CENTER", "UIParent", "CENTER", 0, 0)

        self.db.profile.LootBrowserScale = 1.0
        self:UpdateLootBrowserScale()
        AtlasLootCharDB["QuickLooks"] = {}
        AtlasLootCharDB["SearchResult"] = {}
		AtlasLootWishList = {}
		self:WishlistSetup()
    end
    DEFAULT_CHAT_FRAME:AddMessage(BLUE..AL["AtlasLoot"]..": "..RED..AL["Reset complete!"])
end


--[[
AtlasLoot:SlashCommand(msg):
msg - takes the argument for the /atlasloot command so that the appropriate action can be performed
If someone types /atlasloot, bring up the options box
]]
function AtlasLoot:SlashCommand(msg)
	if msg == AL["reset"] then
		self:Reset("frames")
	elseif msg == AL["options"] then
		self:OptionsToggle()
	else
		AtlasLootDefaultFrame:Show()
	end
end

--[[
AtlasLoot:OnInitialize()
Performs inital setup of the mod and registers it for further setup when
the required resources are in place
]]
function AtlasLoot:OnInitialize()
	--Enable the use of /al or /atlasloot to open the loot browser
	SLASH_ATLASLOOT1 = "/atlasloot"
	SLASH_ATLASLOOT2 = "/al"
	SlashCmdList["ATLASLOOT"] = function(msg)
		self:SlashCommand(msg)
	end

	--Sets the default loot tables for the current expansion enabled on the server.
	local xpaclist = {"CLASSIC", "TBC", "WRATH"}
	self.Expac = xpaclist[GetAccountExpansionLevel()+1]
end

function AtlasLoot:RecipeSource(spellID)
	if not spellID then return end
	local cData = AtlasLoot_CraftingData
	local data = {}
	-- extra information on where to find the recipe
	-- trainer learnt
	local trainer = cData["Trainer"][spellID]
	if trainer then tinsert(data, {AL["Source"]..": "..WHITE..trainer}) end
	-- aquire type
	local aquireType = cData["AquireType"][spellID]
	if aquireType then
		tinsert(data, {AL["Source"]..": "..WHITE..cData[aquireType[1]][aquireType[2]][1]})
	end
	-- vendor recipe
	local vendor = cData["Vendor"][spellID]
	if vendor then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Vendor"]})
		for _,v in pairs(vendor) do
			local vendor = AtlasLoot_CraftingData["VendorList"][v]
			tinsert(data, {vendor[1], vendor[2], cords = {vendor[3], vendor[4]}, fac = vendor[5]})
		end
	end
	-- vendor recipe
	local recipeRepVendor = cData["RecipeRepVendor"][spellID]
	if recipeRepVendor then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Vendor"]})
		local vendor = AtlasLoot_CraftingData["VendorList"][spellID]
		for	i = 3, 6 do
			if vendor and vendor[i] then
			tinsert(data, {vendor[1], vendor[2], fac = vendor[i]})
			end
		end
	end
	--limited vendor recipes
	local limitedVendor = cData["LimitedVendor"][spellID]
	if limitedVendor then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Limited Stock"]})
		local sort = {}
		local limited = false
		for i,v in pairs(limitedVendor) do
			 if limited then
				 tinsert(sort[i-1],v)
				 limited = false
			 else
				 sort[i] = {v}
				 limited = true
			 end
		end
		for _,v in pairs(sort) do
			 local vendor = AtlasLoot_CraftingData["VendorList"][v[1]]
			 tinsert(data, {vendor[1], vendor[2], cords = {vendor[3], vendor[4]}, fac = vendor[5], limited = v[2]})
		end
	end
	--mob drop
	local mobDrop = cData["MobDrop"][spellID]
	if mobDrop then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Mob Drop"]})
		for _,v in pairs(mobDrop) do
			local mob = AtlasLoot_CraftingData["MobList"][v]
			local cords = nil
			if mob[3] ~= 0 and mob[4] ~= 0 then
				cords = {mob[3], mob[4]}
			end
			tinsert(data, {mob[1], WHITE..mob[2], cords})
		end
	end
	-- World Drop
	local worldDrop = cData["WorldDrop"][spellID]
	if worldDrop then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["World Drop"]})
		local text = worldDrop[1]
		if worldDrop[2] then
			text = text.." / "..worldDrop[2]
		end
		tinsert(data, {text})
	end
	--quest
	local questDrop = cData["QuestDrop"][spellID]
	if questDrop then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Quest"]})
		for _,v in pairs(questDrop) do
			local quest = AtlasLoot_CraftingData["QuestList"][v]
			tinsert(data, {quest[1],  quest[2], cords = {quest[3], quest[4]}, fac = quest[5]})
		end
	end
	--rep vendor
	local repVendor = cData["RepVendor"][spellID]
	if repVendor then
		tinsert(data, {AL["Source"]..": "..WHITE..AL["Reputation Vendor"]})
		local line1, line2
		local list = {}
		for i,v in pairs(repVendor) do
			 if type(v) == "table" then
				 for i,v in pairs(v) do
					 if i == 1 then
						 line1 = AL["Faction"]..": "..WHITE..v
					 elseif i == 2 then
						 line2 = AL["Required Reputation"]..": "..WHITE..v
					 else
						 tinsert(list,AtlasLoot_CraftingData["VendorList"][v])
					 end
				 end
			 else
				 if i == 1 then
					 line1 = AL["Faction"]..": "..WHITE..v
				 elseif i == 2 then
					 line2 = AL["Required Reputation"]..": "..WHITE..v
				 else
					 tinsert(list,AtlasLoot_CraftingData["VendorList"][v])
				 end
			 end
		end
		tinsert(data, {line1, line2})
		for _,v in pairs(list) do
			local cords
			if v[3] ~= 0 and v[4] ~= 0 then
				cords = {v[3], v[4]}
			end
			tinsert(data, {v[1], WHITE..v[2], cords, fac = v[5]})
		end
	end
	return data
end

--Creates tables for raid tokens from the collections tables
function AtlasLoot:CreateToken(dataID)
	local itemType, slotType, itemName, itemType2
	--orginal dataID
	local orgID = dataID
	--list of item types to find
	local names = { {"HEAD", "INVTYPE_HEAD", "Head"}, {"SHOULDER", "INVTYPE_SHOULDER", "Shoulders"}, {"CHEST", "INVTYPE_CHEST", "Chest", "INVTYPE_ROBE"}, {"WRIST", "INVTYPE_WRIST", "Wrists"}, {"HAND", "INVTYPE_HAND", "Hands"}, {"WAIST", "INVTYPE_WAIST", "Waist"}, {"LEGS", "INVTYPE_LEGS", "Legs"}, {"FEET", "INVTYPE_FEET", "Feet"}, {"FINGER", "INVTYPE_FINGER", "Rings"}, {"BACK", "INVTYPE_CLOAK", "Back"}, {"NECK", "INVTYPE_NECK", "Necklace"}}
	--finds the item type to create a list of
	for _, b in pairs(names) do
		dataID = gsub(dataID, b[1], "")
		slotType = gsub(orgID, dataID, "")
		if slotType == b[1] then
			itemType = b[2]
			itemType2 = b[4]
			itemName = b[3]
			break
		end
	end
	--Creates data set of the item type
	if (AtlasLoot_TokenData[orgID] == nil) then
		AtlasLoot_TokenData[orgID] = {
			Name = itemName,
			Type = AtlasLoot_Data[dataID].Type,
			Back = true,
			NoSubt = true,
			[1] = { Name = itemName },
		}
	end
	local count = #AtlasLoot_Data[dataID][1] * #AtlasLoot_Data[dataID]
	local function addItem(itemID, desc)
		if itemType == select(9, GetItemInfo(itemID)) or itemType2 == select(9, GetItemInfo(itemID)) then
			table.insert(AtlasLoot_TokenData[orgID][1], {itemID = itemID, desc = desc})
		end
		if count == 1 then
			self:ShowItemsFrame(AtlasLootItemsFrame.refresh[1], AtlasLootItemsFrame.refresh[2], AtlasLootItemsFrame.refresh[3])
		end
		count = count - 1
	end
	--Fills table with items
	for _, t in ipairs(AtlasLoot_Data[dataID]) do
		for _, v in ipairs(t) do
			if type(v) == "table" then
				local item = Item:CreateFromID(v.itemID)
				if v.itemID and not item:GetInfo() then
					self:ItemsLoading(1)
					item:ContinueOnLoad(function()
						self:ItemsLoading(-1)
						addItem(v.itemID, t.Name)
					end)
				else
					addItem(v.itemID, t.Name)
				end
			end
		end
	end
end

--Creates a sorted and consolidated loottable of all of an xpacs dungeon loot
function AtlasLoot:CreateOnDemandLootTable(typeL)
	-- Return and show loot table if its already been created
	if AtlasLoot_OnDemand and AtlasLoot_OnDemand[typeL] then return self:ShowItemsFrame(typeL, "AtlasLoot_OnDemand", 1) end
	-- Create ondemand loot table if it dosnt exist
	if not AtlasLoot_OnDemand then AtlasLoot_OnDemand = {} end

	-- Text Conversion
	local equipSlot = {
		INVTYPE_HEAD = BabbleInventory["Head"], INVTYPE_SHOULDER = BabbleInventory["Shoulder"], INVTYPE_CHEST = BabbleInventory["Chest"],
		INVTYPE_WRIST = BabbleInventory["Wrist"], INVTYPE_HAND = BabbleInventory["Hands"], INVTYPE_WAIST = BabbleInventory["Waist"],
		INVTYPE_LEGS = BabbleInventory["Legs"], INVTYPE_FEET = BabbleInventory["Feet"], INVTYPE_FINGER = BabbleInventory["Ring"],
		INVTYPE_CLOAK = BabbleInventory["Back"], INVTYPE_NECK = BabbleInventory["Neck"], INVTYPE_WEAPONOFFHAND = BabbleInventory["Off Hand"],
		INVTYPE_WEAPONMAINHAND = "Mainhand", INVTYPE_TRINKET = "Trinket", INVTYPE_HOLDABLE = "Caster Offhand"}
	
	local function correctText(text)
		text = gsub(text, "Cloth Armor %- Back", "Back")
		text = gsub(text, "Miscellaneous Armor %- " , "")
		text = gsub(text, "Armor %- " , "Armor "..WHITE.."%- ")
		text = gsub(text, "Weapon %- " , WHITE.."%- ")
		return text
	end
	
	-- Combind robes with chest
	local function getEquip(equipLoc)
		if equipLoc == "INVTYPE_ROBE" then
			return "INVTYPE_CHEST"
		end
		return equipLoc
	end

	-- Show the loot table or refresh it
	local firstLoad
	local function showTable()
		if firstLoad then
			self:ShowItemsFrame(AtlasLootItemsFrame.refresh[1], AtlasLootItemsFrame.refresh[2], AtlasLootItemsFrame.refresh[3])
		else
			self:ShowItemsFrame(typeL, "AtlasLoot_OnDemand", 1)
			firstLoad = true
		end
	end

	local unsorted = {}
	-- Creates type catagorys and then adds items to them
	local function sortItem(item, armorSubType, equipLoc, armorType)
		if not unsorted[armorSubType] then unsorted[armorSubType] = {} end
		if equipLoc and not unsorted[armorSubType][getEquip(equipLoc)] then unsorted[armorSubType][getEquip(equipLoc)] = {} end
		if equipLoc then
			tinsert(unsorted[armorSubType][getEquip(equipLoc)], {item, armorType})
		else
			tinsert(unsorted[armorSubType]["Misc"], {item, armorType})
		end
		AtlasLoot_OnDemand[typeL] = {Name = "All Dungeon Items", Type = typeL, filter = true }

		for aType, v in pairs(unsorted) do
			for eLoc, t in pairs(v) do
				for i, items in ipairs(t) do
					local name = equipSlot[getEquip(eLoc)] and aType.." "..items[2].." - "..equipSlot[getEquip(eLoc)] or aType
					if #t > 30 and (i == 1 or i == 31 or i == 61 or i == 91)  then
						tinsert(AtlasLoot_OnDemand[typeL],{Name = correctText(name)..WHITE.." - Page".. math.ceil(i/30) })
					elseif i == 1 then
						tinsert(AtlasLoot_OnDemand[typeL],{Name = correctText(name)})
					end
					tinsert(AtlasLoot_OnDemand[typeL][#AtlasLoot_OnDemand[typeL]], items[1])
				end
			end
		end
		showTable()
	end

	-- Load items to cache and check they are either an armor or weapon
	local function processItem(itemData)
		if not itemData then return end
		local item = Item:CreateFromID(itemData.itemID)
		if itemData.itemID then
			if not item:GetInfo() then
				item:ContinueOnLoad(function()
					self:ItemsLoading(-1)
					local armorType, armorSubType, _, equipLoc = select(6,GetItemInfo(itemData.itemID))
					if (armorType == "Armor" or armorType == "Weapon") then
						sortItem(itemData, armorSubType, equipLoc, armorType)
					end
				end)
			else
				self:ItemsLoading(-1)
				local armorType, armorSubType, _, equipLoc = select(6,GetItemInfo(itemData.itemID))
				if (armorType == "Armor" or armorType == "Weapon") then
					sortItem(itemData, armorSubType, equipLoc, armorType)
				end
			end
		end
	end

	--Fills table with items
	local itemList = {}
	local checkList = {}
	for _, data in pairs(AtlasLoot_Data) do
		if data.Type == typeL then
			for _, t in ipairs(data) do
				for _, itemData in pairs(t) do
					if type(itemData) == "table" and itemData.itemID and not checkList[itemData.itemID] then
						itemData.dropLoc = {data.DisplayName or data.Name, t.Name}
						checkList[itemData.itemID] = true
						tinsert(itemList, {itemData})
					end
				end
			end
		end
	end
	wipe(checkList)
	-- rate limit tied to half the current frame rate
	self:ItemsLoading(#itemList)
	local maxDuration = 500/GetFramerate()
	local startTime = debugprofilestop()
	local function continue()
		startTime = debugprofilestop()
		local task = tremove(itemList)
		while (task) do
			processItem(task[1])
			if (debugprofilestop() - startTime > maxDuration) then
				Timer.After(0, continue)
				return
			end
			task = tremove(itemList)
		end
	end

	return continue()
end


local lastTablenum = 1
--[[
AtlasLoot:ShowItemsFrame(dataID, dataSource, tablenum):
dataID - Name of the loot table
dataSource - Table in the database where the loot table is stored
tablenum - Number of the table with the loot in it
It is the workhorse of the mod and allows the loot tables to be displayed any way anywhere in any mod.
]]
function AtlasLoot:ShowItemsFrame(dataID, dataSource_backup, tablenum)

	local isValid, toShow, itemID, recipeID, orgItemID
	self.vanityItems = {}

    --If the loot table name has not been passed, throw up a debugging statement
	if dataID == nil then
		DEFAULT_CHAT_FRAME:AddMessage("No dataID!")
        return
	end

	--Hide Advanced search if it is up and reshow Querybutton
	AtlasLootDefaultFrame_AdvancedSearchPanel:Hide()

	--Hide Map and reshow lootbackground
	AtlasLootDefaultFrame_Map:Hide()
    AtlaslLoot_LootBackground:Show()
	AtlasLootItemsFrame:Show()

	-- Hide the Filter Check-Box
	AtlasLootFilterCheck:Hide()

	-- Hide the map header lable
	Atlasloot_HeaderLabel:Hide()
	local dataSource = _G[dataSource_backup] or AtlasLoot_Data
	-- Enable map button if there is a map for this table.
	if dataSource_backup ~= "AtlasLoot_OnDemand" and dataSource_backup ~= "AtlasLoot_TokenData" and dataSource[dataID] and dataSource[dataID].Map then
		AtlasLootDefaultFrame_MapButton:Enable()
		-- Stops map reseting to default while still in the same raid/instance table
		if AtlasLootItemsFrame.refresh == nil or dataID ~= AtlasLootItemsFrame.refresh[1] then
			self.MapNum = 1
			self.CurrentMap = dataSource[dataID].Map
			self:SetMapButtonText(self.CurrentMap)
		end
	else
		AtlasLootDefaultFrame_MapButton:Disable()
		AtlasLootDefaultFrame_MapButton:SetText("No Map")
	end

	if dataSource_backup == "AtlasLoot_CurrentWishList" then
		ATLASLOOT_CURRENT_WISHLIST_NUM = AtlasLoot_CurrentWishList["Show"].ListNum
	else
		self.itemUnlock = false
	end

	local difType = false
	-- Checks to see if type is the same
	if self.CurrentType and self.CurrentType ~= dataSource[dataID].Type then
		ItemindexID = self.type[dataSource[dataID].Type] or 2
		difType = true
	end

	-- Saves current types ItemindexID
	if dataSource[dataID].Type then
		self.type[dataSource[dataID].Type] = ItemindexID
	end
	-- Set current type
	self.CurrentType = dataSource[dataID].Type or "Default"

	-- Loads the difficultys into the scrollFrame
	if dataSource[dataID].ListType then
		self:ScrollFrameUpdate(nil,dataSource[dataID].ListType)
	else
		self:ScrollFrameUpdate()
	end

	-- Finds the tablenumber to set where the difficulty slider should be.
	local typeNumber = 1
	local function findTypeNumber()
		for i,v in ipairs(self.Difficultys[dataSource[dataID].Type]) do
			if v[2] == ItemindexID then
				typeNumber = i
				return i
			end
		end
	end

	if dataSource_backup ~= "AtlasLootFilter" then
		self.dataSourceBackup = dataSource_backup
	end

	-- Moves the difficulty scrollslider if the difficulty has changed
	if dataSource[dataID].Type and difType and #self.Difficultys[dataSource[dataID].Type] > 5 and findTypeNumber() > 5 then
		local min, max = AtlasLootDefaultFrameScrollScrollBar:GetMinMaxValues()
		AtlasLootDefaultFrameScrollScrollBar:SetValue(typeNumber * (max / #self.Difficultys[dataSource[dataID].Type]))
	end

	-- Moves the difficulty scrollslider if wishlist
	if dataSource_backup == "AtlasLoot_CurrentWishList" and dataSource[dataID].ListNum > 5 then
		local min, max = AtlasLootDefaultFrameScrollScrollBar:GetMinMaxValues()
		AtlasLootDefaultFrameScrollScrollBar:SetValue(dataSource[dataID].ListNum * (max / #AtlasLootWishList[dataSource[dataID].ListType][dataSource[dataID].ListNum]))
	end

	--For stopping the subtable from changing if its a token table
	if dataSource[dataID].NoSubt == nil and dataID ~= "FilterList" then
		if dataSource[dataID].DisplayName then
			AtlasLootDefaultFrame_SubMenu:SetText(dataSource[dataID].DisplayName)
		else
			AtlasLootDefaultFrame_SubMenu:SetText(dataSource[dataID].Name)
		end
		self:SubTableScrollFrameUpdate(dataID, dataSource_backup, tablenum)
	end

	-- Sets the main page lable
	if dataSource[dataID][tablenum] and dataSource[dataID][tablenum].Name then
		AtlasLoot_BossName:SetText(dataSource[dataID][tablenum].Name)
	else
		AtlasLoot_BossName:SetText("This Is Empty")
		for i = 1, 30, 1 do
			--Use shortcuts for easier reference to parts of the item button
			local itemButton = _G["AtlasLootItem_"..i]
			local hightlightFrame = _G["AtlasLootItem_"..i.."_Highlight"]
				itemButton:Hide()
				itemButton.itemID = nil
				itemButton.spellID = nil
				hightlightFrame:Hide()
				itemButton.hasTrade = false
		end
		return
	end

	if dataSource ~= self.dataSourceBackup and tablenum ~= lastTablenum then
		for i = 1, 30, 1 do
			_G["AtlasLootItem_"..i]:Hide()
			_G["AtlasLootItem_"..i.."_Highlight"]:Hide()
		end
	end

	-- find the right itemID for the difficulty selected
	local function getProperItemConditionals(item)
		isValid = false
		toShow = true
		local itemDif = ItemindexID
		local itemID = item and item.itemID
		local orgItemID = itemID
		if item and item.itemID then
			itemID = item.itemID
			isValid = true

			if(item[self.Difficultys.MIN_DIF]) then
				if item[self.Difficultys.MIN_DIF] > itemDif then
					toShow = false
				end
				itemID = self:FindId(item.itemID, min(self:getMaxDifficulty(item.Type or dataSource[dataID].Type), itemDif), item.Type or dataSource[dataID].Type, dataSource[dataID].Type ) or item.itemID
			end

			if toShow then
				--Sets ItemindexID to normal(2) if it is nil for min/max difficulties.
				if not tonumber(itemDif) then itemDif = self.Difficultys.Normal end

				--Checks if an item has a Maximum difficulty, this is to correct some items that have an entry for higher difficulties then they really do
				if item[self.Difficultys.MAX_DIF] then
					if tonumber(item[self.Difficultys.MAX_DIF]) < itemDif then itemDif = item[self.Difficultys.MAX_DIF] end
				end
				--If something was found in itemID database show that if not show default table item
				itemID = self:FindId(item.itemID, itemDif, item.Type or dataSource[dataID].Type, dataSource[dataID].Type) or item.itemID
			end
		elseif item and (item.spellID or item.icon) or item and itemID then
			isValid = true
			toShow = true
		end
		local recipeID
		if item and item.spellID then
			recipeID = self:GetRecipeID(item.spellID)
		end
		return isValid, toShow, itemID, recipeID, orgItemID
	end

	-- Setup the button for the to be displayed item/spell
	local function setupButton(itemID, i, dataSource, dataID, tablenum, dataSource_backup, item)
		local text, extra
		local itemName, itemQuality, itemSubType, itemEquipLoc, itemColor
		local spellName, spellIcon
		--Use shortcuts for easier reference to parts of the item button
		local itemButton = _G["AtlasLootItem_"..i]
		local iconFrame  = _G["AtlasLootItem_"..i.."_Icon"]
		local nameFrame  = _G["AtlasLootItem_"..i.."_Name"]
		local extraFrame = _G["AtlasLootItem_"..i.."_Extra"]
		local hightlightFrame = _G["AtlasLootItem_"..i.."_Highlight"]
		local spellID = dataSource[dataID][tablenum][i].spellID

		if spellID then
			spellName, _, spellIcon, _, _, _, _, _, _ = GetSpellInfo(spellID)
			if spellName then
				text = spellName
			elseif dataSource[dataID][tablenum][i].name then
				text = dataSource[dataID][tablenum][i].name
				text = self:FixText(text)
			end
			if itemID then
				text = select(4,GetItemQualityColor(item:GetQuality()))..text
			end
			--Adds button highlights if you know a recipe or have a char that knows one
			if CA_IsSpellKnown(spellID) then
				itemButton.hasTrade = true
				hightlightFrame:SetTexture(itemHighlightGreen)
				hightlightFrame:Show()
			else
				itemButton.hasTrade = false
				hightlightFrame:Hide()
				if self:GetKnownRecipes(spellID) then
					hightlightFrame:SetTexture(itemHighlightBlue)
					hightlightFrame:Show()
				end

			end
		elseif itemID then
			itemName, _, itemQuality, _, _, _, itemSubType, _, itemEquipLoc, _ = GetItemInfo(itemID)
			itemName = itemName or item:GetName()
			itemSubType = itemSubType or AtlasLoot_ExtraData["ArmorConversion"][item:GetSubClassID()]
				if not itemName then
					itemID = orgItemID
					itemName, _, itemQuality, _, _, _, itemSubType, _, itemEquipLoc, _ = GetItemInfo(itemID)
				end
			--If the client has the name of the item in cache, use that instead.					
			if dataSource[dataID][tablenum][i].name then
				--If it has a manuel entry use that
				text = dataSource[dataID][tablenum][i].name
				text = self:FixText(text)
			elseif itemName then
				itemQuality = itemQuality or item:GetQuality()
				text = itemQuality and select(4,GetItemQualityColor(itemQuality))..itemName or itemName
			else
				text = ""
			end
			if C_VanityCollection.IsCollectionItemOwned(itemID) and VANITY_ITEMS[itemID] and CA_IsSpellKnown(VANITY_ITEMS[itemID].learnedSpell) and VANITY_ITEMS[itemID].learnedSpell ~= 0 then
				hightlightFrame:SetTexture(itemHighlightGreen)
				hightlightFrame:Show()
			elseif C_VanityCollection.IsCollectionItemOwned(itemID) then
				hightlightFrame:SetTexture(itemHighlightBlue)
				hightlightFrame:Show()
				if dataSource_backup == "AtlasLoot_CurrentWishList" or (VANITY_ITEMS[itemID] and VANITY_ITEMS[itemID].learnedSpell ~= 0 and not CA_IsSpellKnown(VANITY_ITEMS[itemID].learnedSpell)) then
					tinsert(self.vanityItems, itemID)
				end
			end
		else
			if dataSource[dataID][tablenum][i].name then
				--If it has a manuel entry use that
				text = dataSource[dataID][tablenum][i].name
				text = self:FixText(text)
			else
				text = ""
			end
		end

		itemButton.name = text
		--Insert the item description
		if self.FixedItemText[dataSource[dataID][tablenum][i].itemID] then
			extra = self.FixedItemText[dataSource[dataID][tablenum][i].itemID]
		elseif dataSource[dataID][tablenum][i].desc then
			if type(dataSource[dataID][tablenum][i].desc) == "table" then
				local location, boss = dataSource[dataID][tablenum][i].desc[1], dataSource[dataID][tablenum][i].desc[2]
				extra = YELLOW..location..WHITE.." - "..boss	
			else
				extra = dataSource[dataID][tablenum][i].desc
			end
		elseif dataSource[dataID][tablenum][i].dropLoc and (self.dataSourceBackup == "AtlasLoot_OnDemand" or (self.db.profile.showdropLocationOnSearch and dataID == "SearchResult")) then
			local location, boss = dataSource[dataID][tablenum][i].dropLoc[1], dataSource[dataID][tablenum][i].dropLoc[2]
			extra = YELLOW..location..WHITE.." - "..boss
		elseif AtlasLoot_CraftingData["CraftingLevels"] and spellID and AtlasLoot_CraftingData["CraftingLevels"][spellID] and dataID ~= "SearchResult" then
			local lvls = AtlasLoot_CraftingData["CraftingLevels"][spellID]
			extra = LIMEGREEN .. "L-Click:|r "..WHITE..dataSource[dataID].Name.." ( "..ORANGE..lvls[1].."|r "..YELLOW..lvls[2].."|r "..GREEN..lvls[3].."|r "..GREY..lvls[4]..WHITE.." )"
		elseif dataSource[dataID][tablenum][i].lootTable and dataSource[dataID][tablenum][i].lootTable[2] == "Token" then
			extra = "#setToken#"
		elseif itemEquipLoc and itemSubType then
			extra = "=ds="..itemEquipLoc..", "..itemSubType
		else
			extra = ""
		end

		if AtlasLoot_ExtraData[dataSource[dataID][tablenum][i].itemID]and dataID ~= "SearchResult" then
			extra = LIMEGREEN .. "L-Click:|r " .. extra
		end
		if dataSource[dataID][tablenum][i].contentsPreview and dataID ~= "SearchResult" then
			extra = LIMEGREEN .. "L-Click:|r " .. extra
		end

		if dataSource[dataID][tablenum][i].rep then
			extra = extra ..WHITE.." ("..dataSource[dataID][tablenum][i].rep..")"
		end

		if dataSource[dataID][tablenum][i].price then
			extra = extra ..WHITE.." ("..dataSource[dataID][tablenum][i].price..")"
		end

		local recipe = self:GetRecipeData(itemID, "item")
		if recipe and AtlasLoot_CraftingData["CraftingLevels"] and AtlasLoot_CraftingData["CraftingLevels"][recipe.spellID] then
			local lvls = AtlasLoot_CraftingData["CraftingLevels"][recipe.spellID]
			extra = extra ..WHITE.." ( "..lvls[1].." )"
		end

		extra = self:FixText(extra)

		--If there is no data on the texture an item should have, show a big red question mark
		if dataSource[dataID][tablenum][i].icon == "Blank" then
			iconFrame:SetTexture(nil)
		elseif dataSource[dataID][tablenum][i].icon == "?" then
			iconFrame:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
		elseif dataSource[dataID][tablenum][i].icon then
			iconFrame:SetTexture("Interface\\Icons\\"..dataSource[dataID][tablenum][i].icon)
		elseif dataSource[dataID][tablenum][i].itemID then
			iconFrame:SetTexture(GetItemIcon(dataSource[dataID][tablenum][i].itemID))
		elseif spellIcon then
			iconFrame:SetTexture(spellIcon)
		elseif dataSource[dataID][tablenum][i].itemID then
			local icon = item:GetIcon()
			iconFrame:SetTexture(icon)
		end

		if iconFrame:GetTexture() == nil and dataSource[dataID][tablenum][i].icon ~= "Blank" then
			iconFrame:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark")
		end

		itemButton.itemTexture = iconFrame:GetTexture()

		--Highlight items in the wishlist
		if itemID and dataSource_backup ~= "AtlasLoot_CurrentWishList" and (AtlasLootWishList["Options"][UnitName("player")] and AtlasLootWishList["Options"][UnitName("player")]["Mark"]) then
			local xitemexistwish, itemwishicons = self:WishListCheck(itemID, true)
			if xitemexistwish then
				text = itemwishicons.." "..text
			end
		end
		--Set the name and description of the item
		nameFrame:SetText(text)
		extraFrame:SetText(extra)
		extraFrame:Show()
		--For convenience, we store information about the objects in the objects so that it can be easily accessed later
		itemButton.itemID = itemID
		itemButton.spellID = spellID

		--learned spell id is used for items that are part of the ascension vanity collection
		itemButton.learnedSpellID = nil
		if VANITY_ITEMS[itemID] and VANITY_ITEMS[itemID].learnedSpell and VANITY_ITEMS[itemID].learnedSpell ~= 0 then
			itemButton.learnedSpellID = VANITY_ITEMS[itemID].learnedSpell
		end

		itemButton.iteminfo = {}
		if spellID then
			itemButton.iteminfo.idcore = spellID
			itemButton.iteminfo.icontexture = GetItemIcon(spellID)
			itemButton.storeID = itemID
			itemButton.dressingroomID = itemID
		else
			itemButton.iteminfo.idcore = itemID
			itemButton.iteminfo.icontexture = itemID
			itemButton.storeID = itemID
			itemButton.dressingroomID = itemID
		end

		itemButton.craftingData = self:RecipeSource(spellID)
		itemButton.tablenum = tablenum
		itemButton.dataID = dataID
		itemButton.dataSource = dataSource_backup
		itemButton.contentsPreview = dataSource[dataID][tablenum][i].contentsPreview
		itemButton.price = dataSource[dataID][tablenum][i].price or nil
		itemButton.droprate = dataSource[dataID][tablenum][i].droprate or nil
		itemButton.extraInfo = dataSource[dataID][tablenum][i].extraInfo or nil
		itemButton.quest = dataSource[dataID][tablenum][i].quest or nil
		itemButton.item = dataSource[dataID][tablenum][i]

		if dataSource[dataID][tablenum][i].lootTable then
			itemButton.sourcePage = dataSource[dataID][tablenum][i].lootTable
		else
			itemButton.sourcePage = nil
		end

		if dataSource[dataID][tablenum][i][self.Difficultys.DIF_SEARCH] then
			itemButton.difficulty = dataSource[dataID][tablenum][i][self.Difficultys.DIF_SEARCH]
		else
			itemButton.difficulty = ItemindexID
		end

		itemButton.i = 1
		itemButton:Show()
	end

	local function getItemData(itemID, i, orgItemID, item)
		self:ItemsLoading(1)
		item:ContinueOnLoad(function(itemID)
			self:ItemsLoading(-1)
			setupButton(itemID, i, dataSource, dataID, tablenum, dataSource_backup, item)
		end)
	end

	-- Create the loottable
	if (dataID == "SearchResult") or (dataSource_backup == "AtlasLoot_CurrentWishList") or dataSource[dataID][tablenum] then

		--Iterate through each item object and set its properties
		for i = 1, 30, 1 do
			--Use shortcuts for easier reference to parts of the item button
			local itemButton = _G["AtlasLootItem_"..i]
			local hightlightFrame = _G["AtlasLootItem_"..i.."_Highlight"]
			--Check for a valid object (that it exists, and that it has a name
			isValid, toShow, itemID, recipeID, orgItemID = getProperItemConditionals(dataSource[dataID][tablenum][i])
			if isValid and toShow then
				hightlightFrame:Hide()
				if itemID then
					local item = Item:CreateFromID(itemID)
					if not item:GetInfo() then
						getItemData(itemID, i, orgItemID, item)
					end
					setupButton(itemID, i, dataSource, dataID, tablenum, dataSource_backup, item)
				elseif recipeID then
					getItemData(recipeID, i, nil, Item:CreateFromID(recipeID))
				else
					setupButton(itemID, i, dataSource, dataID, tablenum, dataSource_backup, Item:CreateFromID(itemID))
				end
			else
				itemButton:Hide()
				itemButton.itemID = nil
				itemButton.spellID = nil
				hightlightFrame:Hide()
				itemButton.hasTrade = false
			end
			if dataSource[itemID] then
				for _,ID in pairs(dataSource[itemID]) do
					local item = Item:CreateFromID(ID.itemID)
					if ID.itemID and not item:GetInfo() then
						self:ItemsLoading(1)
						item:ContinueOnLoad(function(itemID)
							self:ItemsLoading(-1)
						end)
					end
				end
			end
		end

-----------------------------------------------------------------------------------------------------------------------------

		--Store data about the state of the items frame to allow minor tweaks or a recall of the current loot page
		AtlasLootItemsFrame.refresh = {dataID, dataSource_backup, tablenum}

		if dataID ~= "FilterList" then
			AtlasLootItemsFrame.refreshFilter = {dataID, dataSource_backup, tablenum}
		end

		if dataID ~= "FilterList"  and dataSource[dataID].Back ~= true then
			AtlasLootItemsFrame.refreshOri = {dataID, dataSource_backup, tablenum}
		end

		if dataID == "SearchResult" then
			AtlasLootItemsFrame.refreshSearch = {dataID, dataSource_backup, tablenum}
		elseif not _G["AtlasLootItemsFrame_BACK"]:IsVisible() then
			AtlasLootItemsFrame.refreshSearch = nil
		end

		if dataSource_backup ~= "AtlasLoot_OnDemand" and dataID ~= "SearchResult" and dataSource_backup ~= "AtlasLoot_CurrentWishList" and dataID ~= "FilterList"  and
		dataSource[dataID].Back ~= true and dataID ~= "EmptyTable" and not dataSource[dataID].vanity then
			if not self.db.profile.LastBoss or type(self.db.profile.LastBoss) ~= "table" then self.db.profile.LastBoss = {} end
			self.db.profile.LastBoss[self.Expac] = {dataID, dataSource_backup, tablenum, self.lastModule, self.currentTable, self.moduleName}
			self.db.profile.savedState[self.currentTable] = {dataID, dataSource_backup, tablenum, self.lastModule, self.currentTable, self.moduleName}
		end

		-- Checks dataID with submenus to stop filter button loading on certain tables
		local function filterCheck(find)
			local mtype = { "Reputations", "WorldEvents", "PVP", "Collections", "Vanity"}
			for _, t in pairs (mtype) do
				if AtlasLoot_SubMenus[t..self.Expac] then
					for _, v in ipairs (AtlasLoot_SubMenus[t..self.Expac]) do
						if v[3] and type(v[3]) == "table" then
							for _, sub in ipairs(v[3]) do
								if find == sub[2] then
									return true
								end
							end
						elseif find == v[2] then
							return true
						end	
					end
				end
			end
		end

		-- Show the Filter Check-Box
		if filterCheck(dataID) ~= true or dataSource[dataID].vanity or dataSource[dataID].filter then
			AtlasLootFilterCheck:Show()
		end

		--Hide navigation buttons by default, only show what we need
		_G["AtlasLootItemsFrame_BACK"]:Hide()
		_G["AtlasLootItemsFrame_NEXT"]:Hide()
		_G["AtlasLootItemsFrame_PREV"]:Hide()
		_G["AtlasLootItemsFrame_NEXT"]:SetParent("AtlasLootItemsFrame")
		_G["AtlasLootItemsFrame_PREV"]:SetParent("AtlasLootItemsFrame")
		_G["AtlasLootItemsFrame_NEXT"]:ClearAllPoints()
		_G["AtlasLootItemsFrame_NEXT"]:SetPoint("BOTTOMRIGHT", "AtlasLootItemsFrame", "BOTTOMRIGHT",-5,5)
		_G["AtlasLootItemsFrame_PREV"]:ClearAllPoints()
		_G["AtlasLootItemsFrame_PREV"]:SetPoint("BOTTOMLEFT", "AtlasLootItemsFrame", "BOTTOMLEFT",5,5)
		_G["AtlasLootItemsFrame_Wishlist_Options"]:Hide()
		_G["AtlasLootItemsFrame_Wishlist_Share"]:Hide()
		_G["AtlasLootItemsFrame_Wishlist_Swap"]:Hide()
		_G["AtlasLootItemsFrame_Wishlist_UnLock"]:Hide()
		_G["AtlasLootItemsFrame_Wishlist_Vanity_Learn"]:Hide()
		_G["AtlasLootItemsFrame_Spell_Vanity_Learn"]:Hide()

		-- Show Wishlist buttons when a wishlist in showing
		if dataSource_backup == "AtlasLoot_CurrentWishList" then
			_G["AtlasLootItemsFrame_Wishlist_Options"]:Show()
			_G["AtlasLootItemsFrame_Wishlist_Share"]:Show()
			_G["AtlasLootItemsFrame_Wishlist_Swap"]:Show()
			_G["AtlasLootItemsFrame_Wishlist_UnLock"]:Show()
			_G["AtlasLootItemsFrame_Wishlist_Vanity_Learn"]:Show()
			if dataSource[dataID].ListType == "Shared" then
				AtlasLootItemsFrame_Wishlist_Swap:SetText("Own")
			elseif dataSource[dataID].ListType == "Own" then
				AtlasLootItemsFrame_Wishlist_Swap:SetText("Shared")
			end
		end

		if dataSource[dataID].vanity then
			_G["AtlasLootItemsFrame_Spell_Vanity_Learn"]:Show()
		end

		local tablebase = {dataID, dataSource_backup}
		if dataID == "FilterList" then
			tablebase = {AtlasLootItemsFrame.refreshOri[1],AtlasLootItemsFrame.refreshOri[2]}
			tablenum = AtlasLootItemsFrame.refreshOri[3]
		end

		if AtlasLootItemsFrame.refresh and AtlasLootItemsFrame.refreshOri and tablenum ~= #_G[AtlasLootItemsFrame.refreshOri[2]][AtlasLootItemsFrame.refreshOri[1]] and dataSource_backup ~= "AtlasLoot_TokenData" and dataID ~= "SearchResult" or tablenum ~= #_G[AtlasLootItemsFrame.refresh[2]][AtlasLootItemsFrame.refresh[1]] and dataID == "SearchResult" then
			_G["AtlasLootItemsFrame_NEXT"]:Show()
			_G["AtlasLootItemsFrame_NEXT"].tablenum = tablenum + 1
			_G["AtlasLootItemsFrame_NEXT"].tablebase = tablebase
		end

		if tablenum ~= 1 and dataSource_backup ~= "AtlasLoot_TokenData" then
			_G["AtlasLootItemsFrame_PREV"]:Show()
			_G["AtlasLootItemsFrame_PREV"].tablenum = tablenum - 1
			_G["AtlasLootItemsFrame_PREV"].tablebase = tablebase
		end

		if dataSource[dataID].Back or self.backEnabled then
			_G["AtlasLootItemsFrame_BACK"]:Show()
		elseif dataID ~= "FilterList" then
			AtlasLootItemsFrame.refreshBack = {dataID, dataSource_backup, tablenum}
		end
	end

	lastTablenum = tablenum

	--Anchor the item frame where it is supposed to be
	if self.filterEnable and dataID ~= "FilterList" then
		self:HideFilteredItems()
	end
	if dataID ~= "SearchResult" and dataSource_backup ~= "AtlasLoot_OnDemand" then
		--preload items from the rest of the instance table
		self:PreLoadLootTable(dataSource, dataID, ItemindexID)
	end

end

-- List of Moduel Names
AtlasLoot.ModuleName = {
	["AtlasLootOriginalWoW"] = "AtlasLoot_OriginalWoW";
	["AtlasLootBurningCrusade"] = "AtlasLoot_BurningCrusade";
	["AtlasLootCraftingOriginalWoW"] = "AtlasLoot_Crafting_OriginalWoW";
	["AtlasLootCraftingBurningCrusade"] = "AtlasLoot_Crafting_TBC";
	["AtlasLootCraftingWotLK"] = "AtlasLoot_Crafting_Wrath";
	["AtlasLootWorldEvents"] = "AtlasLoot_WorldEvents";
	["AtlasLootWotLK"] = "AtlasLoot_WrathoftheLichKing";
	["AtlasLootVanity"] = "AtlasLoot_Vanity";
}

AtlasLoot.dataModules = {
	"AtlasLoot_OriginalWoW",
	"AtlasLoot_BurningCrusade",
	"AtlasLoot_WrathoftheLichKing",
	"AtlasLoot_Crafting_OriginalWoW",
	"AtlasLoot_Crafting_TBC",
	"AtlasLoot_Crafting_Wrath",
	"AtlasLoot_WorldEvents",
	"AtlasLoot_Vanity"
}

--[[
AtlasLoot:LoadAllModules()
Used to load all available LoD modules
]]
function AtlasLoot:LoadAllModules()
	local loadedModules = {}
	local flag = 0
	for _, module in pairs(self.dataModules) do
		loadedModules[module] = LoadAddOn(module)
	end

	for module, state in pairs(loadedModules) do
		if not state then
			LoadAddOn(module)
			flag = 1
		end
	end

	if flag == 1 then
		if self.DebugMessages then
			DEFAULT_CHAT_FRAME:AddMessage(GREEN..AL["AtlasLoot"]..": "..WHITE..AL["All Available Modules Loaded"])
		end
		collectgarbage("collect")
	end
end

--[[
AtlasLoot:SetFavorites(number)
sets the favorite when alt right clicked
]]
function AtlasLoot:SetFavorites(num)
    if AtlasLootItemsFrame.refresh[2] == "AtlasLoot_CurrentWishList" then
        AtlasLootCharDB["QuickLooks"][num]={AtlasLoot_CurrentWishList["Show"].ListType, "AtlasLootWishList", AtlasLoot_CurrentWishList["Show"].ListNum, self.lastModule, self.currentTable, _G["AtlasLootWishList"][AtlasLoot_CurrentWishList["Show"].ListType][AtlasLoot_CurrentWishList["Show"].ListNum].Name}
    else
        AtlasLootCharDB["QuickLooks"][num]={AtlasLootItemsFrame.refreshOri[1], AtlasLootItemsFrame.refreshOri[2], AtlasLootItemsFrame.refreshOri[3], self.lastModule, self.currentTable, _G[AtlasLootItemsFrame.refreshOri[2]][AtlasLootItemsFrame.refreshOri[1]][AtlasLootItemsFrame.refreshOri[3]].Name}
    end
end

-- Used to precache all the items in a raid/instance
local isLoaded = {}
function AtlasLoot:PreLoadLootTable(dataSource, dataID, ItemindexID)
	if isLoaded[dataID] and isLoaded[dataID][ItemindexID] then return end
	for _, instance in ipairs(dataSource[dataID]) do
		for _, boss in pairs(instance) do
			if type(boss) == "table" then
				local itemID = ItemIDsDatabase[boss.itemID] and ItemIDsDatabase[boss.itemID][ItemindexID] or boss.itemID
				if itemID then
					local item = Item:CreateFromID(itemID)
					if item and not item:GetInfo() then
						self:ItemsLoading(1)
						item:ContinueOnLoad(function(itemID)
							self:ItemsLoading(-1)
						end)
					end
				end
			end
		end
	end
	if not isLoaded[dataID] then isLoaded[dataID] = {} end
	isLoaded[dataID][ItemindexID] = true
end




-- Loads the Item Variations into a table from the data content folder
function AtlasLoot:LoadItemIDsDatabase()
	local content = C_ContentLoader:Load("ItemVariationData")
	content:SetParser(function(index, data)
		-- run for each item in the data
	if index ~= 0 and data.Normal ~= 0 and not ItemIDsDatabase[data.Normal] then
			ItemIDsDatabase[data.Normal] = {}
			ItemIDsDatabase[data.Normal]["MythicRaid"] = tonumber("13"..data.Normal)
			table.insert(ItemIDsDatabase[data.Normal],data.Bloodforged)
			table.insert(ItemIDsDatabase[data.Normal],data.HeroicBloodforged)
			table.insert(ItemIDsDatabase[data.Normal],data.Normal)
			if data.Heroic ~= 0 then table.insert(ItemIDsDatabase[data.Normal],data.Heroic) end
				for _,v in ipairs(data["Mythic"]) do
					if v ~= 0 then
						table.insert(ItemIDsDatabase[data.Normal],v)
					end
				end
		end
	end)

	-- This will run over time (usually about 30s for a file this size), but will maintain playable fps while running.
	content:ParseAsync()
end

function AtlasLoot:UNIT_SPELLCAST_SUCCEEDED(event, arg1, arg2 , arg3)
	if arg1 == "player" and arg2 == "Learning" then
		self:PopulateProfessions()
	end
end

function AtlasLoot:PopulateProfessions()
	self.db.profile.professions = self.db.profile.professions or {}
	for _, skillID in pairs(PRIMARY_PROFESSIONS) do
		local _, _, _, skillMaxRank = GetSkillInfo(skillID)
		if skillMaxRank and skillMaxRank > 0 then
			self.db.profile.professions[skillID] = self.db.profile.professions[skillID] or { knownRecipes = {} }
		end
	end
	for _, skillID in pairs(SECONDARY_PROFESSIONS) do
		local _, _, _, skillMaxRank = GetSkillInfo(skillID)
		if skillMaxRank and skillMaxRank > 0 then
			self.db.profile.professions[skillID] = self.db.profile.professions[skillID] or { knownRecipes = {} }
		end
	end
	for prof, _ in pairs(self.db.profile.professions) do
		if TRADESKILL_RECIPES[prof] then
			for _,cat in pairs(TRADESKILL_RECIPES[prof]) do
				for _,recipe in pairs(cat) do
					if CA_IsSpellKnown(recipe.SpellEntry) then
						self.db.profile.professions[prof].knownRecipes[recipe.SpellEntry] = true
					end
				end
			end
		end
	end
end


function AtlasLoot:LoadTradeskillRecipes()
	if TRADESKILL_RECIPES then return end
		TRADESKILL_RECIPES = {}
		TRADESKILL_CRAFTS = {}

		local fmtSubClass = "ITEM_SUBCLASS_%d_%d"
		local fmtTotem = "SPELL_TOTEM_%d"
		local fmtObject = "SPELL_FOCUS_OBJECT_%d"

		local content = C_ContentLoader:Load("TradeSkillRecipeData")

		local function GetToolName(toolID)
			return _G[format(fmtTotem, toolID)]
		end

		content:SetParser(function(_, data)
			if not TRADESKILL_RECIPES[data.SkillIndex] then
				TRADESKILL_RECIPES[data.SkillIndex] = {}
			end

			data.Category = _G[format(fmtSubClass, data.CreatedItemClass, data.CreatedItemSubClass)]

			if not TRADESKILL_RECIPES[data.SkillIndex][data.Category] then
				TRADESKILL_RECIPES[data.SkillIndex][data.Category] = {}
			end

			data.IsHighRisk = toboolean(data.IsHighRisk)

			-- reformat reagents
			data.Reagents = {}
			local reagents = data.ReagentData:SplitToTable(",")
			for _, reagentString in ipairs(reagents) do
				local item, count = reagentString:match("(%d*):(%d*)")
				item = tonumber(item)
				count = tonumber(count)
				if item and item ~= 0 and count and count ~= 0 then
					tinsert(data.Reagents, {item, count})
				end
			end

			if #data.Reagents > 0 then
				data.ReagentData = nil

				-- reformat tools (totems)
				data.Tools = data.TotemCategories:SplitToTable(",", GetToolName)
				data.TotemCategories = nil

				data.SpellFocusObject = _G[format(fmtObject, data.SpellFocusObject)]

				tinsert(TRADESKILL_RECIPES[data.SkillIndex][data.Category], data)
				if data.CreatedItemEntry > 0 then
					TRADESKILL_CRAFTS[data.CreatedItemEntry] = data
				end
			end
		end)

		content:Parse()
end

local function CollectionNames(cat)
	local C_names = {
		["Axe1H"] = "One-Handed Axes",
		["Axe2H"] = "Two-Handed Axes",
		["Sword1H"] = AL["One-Handed Sword"],
		["Sword2H"] = AL["Two-Handed Sword"],
		["Mace1H"] = AL["One-Handed Mace"],
		["Mace2H"] = AL["Two-Handed Mace"],
	}
	return C_names[cat] or cat
end

function AtlasLoot:CreateVanityCollection()
	local function findGroup(group)
		for cat,v in pairs(Enum.VanityCategory) do
			if type(v) == "table" then
				for catT, t in pairs(v) do
					if not AtlasLoot_Data[catT] then AtlasLoot_Data[catT] = { Name = CollectionNames(catT), vanity = true, Module = "AtlasLoot_Ascension_Vanity" } end
					if bit.contains(group, t) then
						return catT
					end
				end
			else
				if not AtlasLoot_Data[cat] then AtlasLoot_Data[cat] = { Name = CollectionNames(cat), vanity = true, Module = "AtlasLoot_Ascension_Vanity" } end
				if bit.contains(group, v) then
					return cat
				end
			end
		end
		if not AtlasLoot_Data["Uncategorized"] then AtlasLoot_Data["Uncategorized"] = { Name = CollectionNames("Uncategorized"), vanity = true, Module = "AtlasLoot_Ascension_Vanity" } end
		return "Uncategorized"
	end

	for _,item in pairs(VANITY_ITEMS) do
		local group = findGroup(item.group)
		if not group then break end
		if #AtlasLoot_Data[group] == 0 or #AtlasLoot_Data[group][#AtlasLoot_Data[group]] == 30 then
			tinsert(AtlasLoot_Data[group], {Name = "Page "..(#AtlasLoot_Data[group] +1)})
		end
		local contentsPreview
		if item.contentsPreview and #item.contentsPreview > 1 then
			contentsPreview = {}
			for _,itemID in pairs(item.contentsPreview) do
				tinsert(contentsPreview, { itemID = itemID })
			end
		end
		local description
		if item.description ~= "" then
			description = item.description
		end

		tinsert(AtlasLoot_Data[group][#AtlasLoot_Data[group]], { itemID = item.itemid, extraInfo = description, contentsPreview = contentsPreview, vanityItem = true })
	end
end