---[[
--Register LAM with LibStub
local MAJOR, MINOR = "LibNeed4Research", 5
local ln4r, oldminor = LibStub:NewLibrary(MAJOR, MINOR)
if not ln4r then return end	--the same or newer version of this lib is already loaded into memory
--]]

local ASV
local LIBNEED4RESEARCHVARVERSION = 2  -- DO NOT CHANGE

local varDefaults = {
	KnownTraitTable = {},
	KnownRecipeTable = {},
	PlayerNames = {},
}

local tIsTraitResearchable = {
	[ITEM_TRAIT_TYPE_ARMOR_DIVINES] 		= true,
	[ITEM_TRAIT_TYPE_ARMOR_EXPLORATION] 	= true,
	[ITEM_TRAIT_TYPE_ARMOR_IMPENETRABLE] 	= true,
	[ITEM_TRAIT_TYPE_ARMOR_INFUSED] 		= true,
	[ITEM_TRAIT_TYPE_ARMOR_INTRICATE] 		= false,
	[ITEM_TRAIT_TYPE_ARMOR_ORNATE] 			= false,
	[ITEM_TRAIT_TYPE_ARMOR_REINFORCED]		= true,
	[ITEM_TRAIT_TYPE_ARMOR_STURDY] 			= true,
	[ITEM_TRAIT_TYPE_ARMOR_TRAINING] 		= true,
	[ITEM_TRAIT_TYPE_ARMOR_WELL_FITTED]		= true,
	[ITEM_TRAIT_TYPE_ARMOR_NIRNHONED] 		= true,

	[ITEM_TRAIT_TYPE_WEAPON_CHARGED] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_DEFENDING] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_INFUSED] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_INTRICATE] 		= false,
	[ITEM_TRAIT_TYPE_WEAPON_ORNATE] 		= false,
	[ITEM_TRAIT_TYPE_WEAPON_POWERED] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_PRECISE] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_SHARPENED] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_TRAINING] 		= true,
	[ITEM_TRAIT_TYPE_WEAPON_WEIGHTED]	 	= true,
	[ITEM_TRAIT_TYPE_WEAPON_NIRNHONED] 		= true,

	[ITEM_TRAIT_TYPE_JEWELRY_ARCANE] 		= false,
	[ITEM_TRAIT_TYPE_JEWELRY_HEALTHY]	 	= false,
	[ITEM_TRAIT_TYPE_JEWELRY_ORNATE] 		= false,
	[ITEM_TRAIT_TYPE_JEWELRY_ROBUST] 		= false,

	[ITEM_TRAIT_TYPE_NONE] 					= false,
}

-- Used to find the crafting type & research Index for items
local tEquipTypes = {
	[ITEMTYPE_ARMOR] = {
		--[ARMORTYPE_NONE] 	= {}, -- jewelry is excluded --
		[ARMORTYPE_LIGHT] 	= {
			["CRAFTINGSKILLTYPE"] 	= CRAFTING_TYPE_CLOTHIER,
			[EQUIP_TYPE_CHEST]		= 1,
			[EQUIP_TYPE_FEET]		= 2,
			[EQUIP_TYPE_HAND]		= 3,
			[EQUIP_TYPE_HEAD]		= 4,
			[EQUIP_TYPE_LEGS]		= 5,
			[EQUIP_TYPE_SHOULDERS]	= 6,
			[EQUIP_TYPE_WAIST]		= 7,
		},
		[ARMORTYPE_MEDIUM] 	= {
			["CRAFTINGSKILLTYPE"] 	= CRAFTING_TYPE_CLOTHIER,
			[EQUIP_TYPE_CHEST]		= 8,
			[EQUIP_TYPE_FEET]		= 9,
			[EQUIP_TYPE_HAND]		= 10,
			[EQUIP_TYPE_HEAD]		= 11,
			[EQUIP_TYPE_LEGS]		= 12,
			[EQUIP_TYPE_SHOULDERS]	= 13,
			[EQUIP_TYPE_WAIST]		= 14,
		},
		[ARMORTYPE_HEAVY] 	= {
			["CRAFTINGSKILLTYPE"] 	= CRAFTING_TYPE_BLACKSMITHING,
			[EQUIP_TYPE_CHEST]		= 8,
			[EQUIP_TYPE_FEET]		= 9,
			[EQUIP_TYPE_HAND]		= 10,
			[EQUIP_TYPE_HEAD]		= 11,
			[EQUIP_TYPE_LEGS]		= 12,
			[EQUIP_TYPE_SHOULDERS]	= 13,
			[EQUIP_TYPE_WAIST]		= 14,
		},
	},
	[ITEMTYPE_WEAPON] = {
		[WEAPONTYPE_SHIELD]				= {
			[EQUIP_TYPE_OFF_HAND] = 6, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
		[WEAPONTYPE_AXE]				= {
			[EQUIP_TYPE_ONE_HAND] = 1, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_DAGGER]				= {
			[EQUIP_TYPE_ONE_HAND] = 7, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_HAMMER]				= {
			[EQUIP_TYPE_ONE_HAND] = 2, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_SWORD]				= {
			[EQUIP_TYPE_ONE_HAND] = 3, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_TWO_HANDED_AXE]		= {
			[EQUIP_TYPE_TWO_HAND] = 4, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_TWO_HANDED_HAMMER]	= {
			[EQUIP_TYPE_TWO_HAND] = 5, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_TWO_HANDED_SWORD]	= {
			[EQUIP_TYPE_TWO_HAND] = 6, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_BLACKSMITHING},
		[WEAPONTYPE_BOW]				= {
			[EQUIP_TYPE_TWO_HAND] = 1, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
		[WEAPONTYPE_FIRE_STAFF]			= {
			[EQUIP_TYPE_TWO_HAND] = 2, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
		[WEAPONTYPE_FROST_STAFF]		= {
			[EQUIP_TYPE_TWO_HAND] = 3, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
		[WEAPONTYPE_LIGHTNING_STAFF] 	= {
			[EQUIP_TYPE_TWO_HAND] = 4, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
		[WEAPONTYPE_HEALING_STAFF]		= {
			[EQUIP_TYPE_TWO_HAND] = 5, ["CRAFTINGSKILLTYPE"] = CRAFTING_TYPE_WOODWORKING},
	},
}


------------------------------------------------------------------------
-- Get Trait Index --
------------------------------------------------------------------------
local function GetTraitIndex(_BagIdOrLink, _iSlotId)
	local lLink = _BagIdOrLink
	if _iSlotId then
		lLink = GetItemLink(_BagIdOrLink,_iSlotId)
	end
	local iTraitType = GetItemLinkTraitInfo(lLink)
	if not tIsTraitResearchable[iTraitType] then return end

	if ((iTraitType == ITEM_TRAIT_TYPE_WEAPON_NIRNHONED)
	or (iTraitType == ITEM_TRAIT_TYPE_ARMOR_NIRNHONED)) then
		return 9
	end
	return (iTraitType % 10)
end

local function GetResearchInfo(_BagIdOrLink, _iSlotId)
	local lLink = _BagIdOrLink
	if _iSlotId then
		lLink = GetItemLink(_BagIdOrLink, _iSlotId)
	end

	local iTraitType = GetItemLinkTraitInfo(lLink)
	if not tIsTraitResearchable[iTraitType] then return end

	local iItemType = GetItemLinkItemType(lLink)
	local iSubType = 0 -- 0 is the same return as WEAPONTYPE_NONE & ARMORTYPE_NONE

	if iItemType == ITEMTYPE_ARMOR then
		iSubType = GetItemLinkArmorType(lLink)
	elseif iItemType == ITEMTYPE_WEAPON then
		iSubType = GetItemLinkWeaponType(lLink)
	else
		return
	end

	if not (tEquipTypes[iItemType] and tEquipTypes[iItemType][iSubType]) then return end

	local iEquipType 			= GetItemLinkEquipType(lLink)
	local iCraftingSkillType 	= tEquipTypes[iItemType][iSubType]["CRAFTINGSKILLTYPE"]
	local iResearchLineIndex 	= tEquipTypes[iItemType][iSubType][iEquipType]
	local iTraitIndex 			= GetTraitIndex(_BagIdOrLink, _iSlotId)

	return iCraftingSkillType, iResearchLineIndex, iTraitIndex
end

--[[
ZO_CraftingUtils_IsTraitAppliedToWeapons(traitType)
ZO_CraftingUtils_IsTraitAppliedToArmor(traitType)
--]]

local function IsTraitNeeded(_sPlayerName, _iCraftingSkillType, _iResearchLineIndex, _iTraitIndex)
	--[[ checks to make sure were not getting called to early by an addon, before the libraries saved vars have loaded. Even though this is local, this is called from a function they can access.
	--]]
	if not (ASV and ASV.KnownTraitTable and ASV.KnownTraitTable[_sPlayerName]) then return true end
	if not ASV.KnownTraitTable[_sPlayerName][_iCraftingSkillType] then return true end
	if not ASV.KnownTraitTable[_sPlayerName][_iCraftingSkillType][_iResearchLineIndex] then return true end

	if ASV.KnownTraitTable[_sPlayerName][_iCraftingSkillType][_iResearchLineIndex][_iTraitIndex] then
		return false
	end
	return true
end

function ln4r:DoesPlayerNeedTrait(_sPlayerName, _iBagIdOrLink, _iSlotId)
	local iCraftingSkillType, iResearchLineIndex, iTraitIndex = GetResearchInfo(_iBagIdOrLink, _iSlotId)

	-- Its either not a researchable ItemType or doesn't have a researchable trait
	if not (iCraftingSkillType and iResearchLineIndex and iTraitIndex) then return false end

	if IsTraitNeeded(_sPlayerName, iCraftingSkillType, iResearchLineIndex, iTraitIndex) then
		return true, iCraftingSkillType, iResearchLineIndex, iTraitIndex
	end
	return false
end

function ln4r:DoAnyPlayersNeedTrait(_iBagIdOrLink, _iSlotId)
	local iCraftingSkillType, iResearchLineIndex, iTraitIndex = GetResearchInfo(_iBagIdOrLink, _iSlotId)

	-- Its either not a researchable ItemType or doesn't have a researchable trait
	if not (iCraftingSkillType and iResearchLineIndex and iTraitIndex) then return end

	--[[ check to make sure were not getting called to early by an addon, before the libraries saved vars have loaded. Default to true, player needs, so nothing bad happens to the item.
	--]]
	if not (ASV and ASV.PlayerNames) then return end

	local sCurrentPlayerName = GetUnitName("player")

	local tPlayersThatNeed = {
		CraftingSkillType	= iCraftingSkillType,
		ResearchLineIndex 	= iResearchLineIndex,
		TraitIndex 			= iTraitIndex,
		PlayerCount 		= 0,
		PlayerNames			= {},
		PlayerNeeds			= false,
		OtherNeeds			= false,
	}

	for sPlayerName,v in pairs(ASV.PlayerNames) do
		if IsTraitNeeded(sPlayerName, iCraftingSkillType, iResearchLineIndex, iTraitIndex) then
			tPlayersThatNeed.PlayerCount = tPlayersThatNeed.PlayerCount + 1

			if sPlayerName == sCurrentPlayerName then
				tPlayersThatNeed.PlayerNeeds = true
			else
				tPlayersThatNeed.OtherNeeds = true
			end
			tPlayersThatNeed.PlayerNames[sPlayerName] = true
		end
	end
	if tPlayersThatNeed.PlayerCount > 0 then
		return tPlayersThatNeed
	end
end
--[[
function ln4r:GetRecipeIndices(_iBagIdOrLink, _iSlotId)
	local lLink = _iBagIdOrLink
	if _iSlotId then
		lLink = GetItemLink(_iBagIdOrLink, _iSlotId)
	end

	local iItemType = GetItemLinkItemType(lLink)
	if iItemType ~= ITEMTYPE_RECIPE then return end

	local lRecipeResultItemLink = GetItemLinkRecipeResultItemLink(lLink)
	local iNumRecipeLists = GetNumRecipeLists()

	for iRecipeListIndex = 1, iNumRecipeLists do
		local _, iNumRecipes = GetRecipeListInfo(iRecipeListIndex)
		for iRecipeIndex = 1, iNumRecipes do
			local lRecipeResultTableLink = GetRecipeResultItemLink(iRecipeListIndex, iRecipeIndex)
			if lRecipeResultItemLink == lRecipeResultTableLink then
				return iRecipeListIndex, iRecipeIndex, lRecipeResultItemLink
			end
		end
	end
end
--]]
function ln4r:DoesPlayerNeedRecipe(_sPlayerName, _iBagIdOrLink, _iSlotId)
	--[[ check to make sure were not getting called to early by an addon, before the libraries saved vars have loaded. --]]
	if not (ASV and ASV.KnownRecipeTable and ASV.KnownRecipeTable[_sPlayerName]) then return end

	local lLink = _iBagIdOrLink
	if _iSlotId then
		lLink = GetItemLink(_iBagIdOrLink, _iSlotId)
	end

	local iItemType = GetItemLinkItemType(lLink)
	if iItemType ~= ITEMTYPE_RECIPE then return false end

	local lRecipeResultItemLink = GetItemLinkRecipeResultItemLink(lLink)
	local sItemId = select(4,ZO_LinkHandler_ParseLink(lRecipeResultItemLink))
	local iItemId = tonumber(sItemId)

	if type(iItemId) == "number" and ASV.KnownRecipeTable[_sPlayerName][iItemId] then
		return false
	end
	return true
end

function ln4r:DoAnyPlayersNeedRecipe(_iBagIdOrLink, _iSlotId)
	local lLink = _iBagIdOrLink
	if _iSlotId then
		lLink = GetItemLink(_iBagIdOrLink, _iSlotId)
	end

	local iItemType = GetItemLinkItemType(lLink)
	if iItemType ~= ITEMTYPE_RECIPE then return end
	-- check to make sure were not getting called to early by an addon, before the libraries saved
	-- vars have loaded.
	if not (ASV and ASV.PlayerNames) then return end

	local sCurrentPlayerName = GetUnitName("player")

	local tPlayersThatNeed = {
		CraftingSkillType	= CRAFTING_TYPE_PROVISIONING,
		PlayerCount 		= 0,
		PlayerNames			= {},
		PlayerNeeds			= false,
		OtherNeeds			= false,
	}
	for sPlayerName,v in pairs(ASV.PlayerNames) do
		local bPlayerNeedsRecipe = ln4r:DoesPlayerNeedRecipe(sPlayerName, _iBagIdOrLink, _iSlotId)
		if bPlayerNeedsRecipe then
			tPlayersThatNeed.PlayerCount = tPlayersThatNeed.PlayerCount + 1

			if sPlayerName == sCurrentPlayerName then
				tPlayersThatNeed.PlayerNeeds = true
			else
				tPlayersThatNeed.OtherNeeds = true
			end
			tPlayersThatNeed.PlayerNames[sPlayerName] = true
		end
	end
	if tPlayersThatNeed.PlayerCount > 0 then
		return tPlayersThatNeed
	end
end


local function AddKnownTrait(_EventCode,  _iCraftingSkillType,  _iResearchLineIndex,  _iTraitIndex)
	if _iCraftingSkillType == CRAFTING_TYPE_INVALID then return end
	local sPlayerName = GetUnitName("player")

	if not ASV.KnownTraitTable[sPlayerName][_iCraftingSkillType][_iResearchLineIndex] then
		ASV.KnownTraitTable[sPlayerName][_iCraftingSkillType][_iResearchLineIndex] = {}
	end

    local iTraitType  = GetSmithingResearchLineTraitInfo(_iCraftingSkillType, _iResearchLineIndex, _iTraitIndex)

	if iTraitType ~= ITEM_TRAIT_TYPE_NONE then
		ASV.KnownTraitTable[sPlayerName][_iCraftingSkillType][_iResearchLineIndex][_iTraitIndex] = true
	end
end

local function AddKnownRecipe(_EventCode, _iRecipeListIndex, _iRecipeIndex)
	local sPlayerName = GetUnitName("player")
    local lRecipeResultItemLink = GetRecipeResultItemLink(_iRecipeListIndex, _iRecipeIndex)
	local sItemId = select(4,ZO_LinkHandler_ParseLink(lRecipeResultItemLink))
	local iItemId = tonumber(sItemId)

	if type(iItemId) == "number" then
		ASV.KnownRecipeTable[sPlayerName][iItemId] = true
	end
end

local function UpdateUnKnownRecipes()
	for iRecipeListIndex = 1, GetNumRecipeLists()  do
		local sRecipeListName, iNumRecipes = GetRecipeListInfo(iRecipeListIndex)
		for iRecipeIndex = 1, iNumRecipes do
			local bIsKnown, sRecipeName = GetRecipeInfo(iRecipeListIndex, iRecipeIndex)
			if bIsKnown then
				AddKnownRecipe(nil, iRecipeListIndex, iRecipeIndex)
			end
		end
	end
end

local function UpdateCraftingSkillTraits(_iCraftingSkillType)
	for iResearchLineIndex = 1, GetNumSmithingResearchLines(_iCraftingSkillType) do
		local _,_, iNumTraits = GetSmithingResearchLineInfo(_iCraftingSkillType, iResearchLineIndex)
		for iTraitIndex = 1, iNumTraits do
			local iTraitType, _, bIsKnown = GetSmithingResearchLineTraitInfo(_iCraftingSkillType, iResearchLineIndex, iTraitIndex)
			-- if its not known, check to see if we are researching it --
			if bIsKnown or GetSmithingResearchLineTraitTimes(_iCraftingSkillType, iResearchLineIndex, iTraitIndex) ~= nil then
				AddKnownTrait(nil,  _iCraftingSkillType,  iResearchLineIndex,  iTraitIndex)
			end
		end
	end
end
local function UpdateUnKnownTraits()
	UpdateCraftingSkillTraits(CRAFTING_TYPE_BLACKSMITHING)
	UpdateCraftingSkillTraits(CRAFTING_TYPE_CLOTHIER)
	UpdateCraftingSkillTraits(CRAFTING_TYPE_WOODWORKING)
end

---------------------------------------------------------------------------------
---- Update Tables ----
--	Called during initialization() --
---------------------------------------------------------------------------------
local function UpdateTables()
	local sPlayerName = GetUnitName("player")

	if not ASV.KnownTraitTable[sPlayerName] then
		ASV.KnownTraitTable[sPlayerName] = {
			[CRAFTING_TYPE_BLACKSMITHING] 	= {},
			[CRAFTING_TYPE_CLOTHIER] 		= {},
			[CRAFTING_TYPE_WOODWORKING] 	= {},
		}
	end
	if not ASV.KnownRecipeTable[sPlayerName] then
		ASV.KnownRecipeTable[sPlayerName] = {}
	end
	if not ASV.PlayerNames[sPlayerName] then
		ASV.PlayerNames[sPlayerName] = true
	end

	UpdateUnKnownTraits()
	UpdateUnKnownRecipes()
end

local function OnAddOnLoaded(_event, _sAddonName)
	if _sAddonName == "ZO_Ingame" then
		ln4r:Initialize()
	end
end
function ln4r:Initialize()
	ln4r.AccountSavedVariables = ZO_SavedVars:NewAccountWide("ZO_Ingame_SavedVariables", LIBNEED4RESEARCHVARVERSION, "LibNeed4ResearchVars", varDefaults)

	ASV = ln4r.AccountSavedVariables
	--Need4Research = ln4r.AccountSavedVariables
	UpdateTables()

	-- register for events
	EVENT_MANAGER:RegisterForEvent("LibNeed4Research", EVENT_SMITHING_TRAIT_RESEARCH_STARTED, AddKnownTrait)
	EVENT_MANAGER:RegisterForEvent("LibNeed4Research", EVENT_RECIPE_LEARNED, AddKnownRecipe)

	-- Unregister events
	EVENT_MANAGER:UnregisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED)
end

EVENT_MANAGER:RegisterForEvent("LibNeed4Research", EVENT_ADD_ON_LOADED, OnAddOnLoaded)