--[[------------------------------------------------------------------
--SousChef.lua
--Author: Wobin
--v0.0.1

inspired by ingeniousclown's Research Assistant

------------------------------------------------------------------]]--
local LAM = LibStub:GetLibrary("LibAddonMenu-1.0")
local BACKPACK = ZO_PlayerInventoryBackpack
local BANK = ZO_PlayerBankBackpack
local GUILD_BANK = ZO_GuildBankBackpack
local GUILD_SHOP = ZO_TradingHouse

local COOKING_RANK_1 = [[SousChef\media\One.dds]]
local COOKING_RANK_2 = [[SousChef\media\Two.dds]]
local COOKING_RANK_3 = [[SousChef\media\Three.dds]]
local COOKING_RANK_4 = [[SousChef\media\Four.dds]]
local COOKING_RANK_5 = [[SousChef\media\Five.dds]]
local COOKING_RANK_6 = [[SousChef\media\Six.dds]]
local COOKING_RANK_1B = [[SousChef\media\One_flat.dds]]
local COOKING_RANK_2B = [[SousChef\media\Two_flat.dds]]
local COOKING_RANK_3B = [[SousChef\media\Three_flat.dds]]
local COOKING_RANK_4B = [[SousChef\media\Four_flat.dds]]
local COOKING_RANK_5B = [[SousChef\media\Five_flat.dds]]
local COOKING_RANK_6B = [[SousChef\media\Six_flat.dds]]

local COOKING = { COOKING_RANK_1, COOKING_RANK_2, COOKING_RANK_3, COOKING_RANK_4, COOKING_RANK_5, COOKING_RANK_6 }
local COOKINGB = { COOKING_RANK_1B, COOKING_RANK_2B, COOKING_RANK_3B, COOKING_RANK_4B, COOKING_RANK_5B, COOKING_RANK_6B }

local CANLEARN = [[/esoui/art/loot/loot_finesseitem.dds]]
local containerHooks = { INVENTORY_BACKPACK, INVENTORY_BANK, INVENTORY_GUILD_BANK }
local itemQuality = { ITEM_QUALITY_MAGIC = { 0, 0, 1 }, ITEM_QUALITY_NORMAL = {1,1,1}, ITEM_QUALITY_ARCANE = {1, 0, 1}}
local Pantry = {}
local Cookbook = {}
local ReverseCookbook = {}
local settings = nil
local slotLines = {}
local hookedFunctions = {}
local hookedDataFunction

local function GetItemID(link)
	return tonumber(string.match(string.match(link, "%d+:"), "%d+"))
end

function EndsWith(String,End)
   return End=='' or string.sub(String,-string.len(End))==End
end

local function MatchInCookbook(bag, slot)
	return Cookbook[GetItemName(bag, slot):lower():gsub(" ","")]
end

local function MatchInGlobalCookbook(bag, slot)
	return settings.Cookbook[GetItemName(bag,slot):lower():gsub(" ", "")]
end

 rowClicked = {}

local function AddDetails(row)
	if not row.dataEntry or not row.dataEntry.data or rowClicked[row] then return false end
	local bagId = row.dataEntry.data.bagId
	local slotIndex = row.dataEntry.data.slotIndex

	if GetItemType(bagId, slotIndex) == ITEMTYPE_RECIPE then
		local gmatch = MatchInGlobalCookbook(bagId, slotIndex)
		if gmatch then
			ItemTooltip:AddLine("")
			ItemTooltip:AddLine("Known by ", "ZoFontWinH5", 1,1,1, BOTTOM, MODIFY_TEXT_TYPE_UPPERCASE)
			for i,v in pairs(gmatch) do
				ItemTooltip:AddLine(i)
			end
			rowClicked[row] = true
			return
		end
	end


	if ((GetItemCraftingInfo(bagId, slotIndex)) ~= CRAFTING_TYPE_PROVISIONING) then	return false end

	local usableIngredient = ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))]
	if settings.showAltKnowledge then usableIngredient = settings.ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))] end
	if usableIngredient then
		ItemTooltip:AddLine("Used in:")
		for i,v in ipairs(usableIngredient) do
			ItemTooltip:AddLine(v)
		end
		rowClicked[row] = true
	end
	return false
end

local function getIcon(row)
	local rankIcon = slotLines[row:GetName()]
	if(not rankIcon) then
		rankIcon =  WINDOW_MANAGER:CreateControl(row:GetName() .. "SousChef", row, CT_TEXTURE)
		slotLines[row:GetName()] = rankIcon
		if row:GetOwningWindow():GetName() ~= "ZO_TradingHouse" then
			ZO_PreHookHandler(row, "OnMouseDown", AddDetails)
			ZO_PreHookHandler(row, "OnMouseExit", function(self) rowClicked[self] = nil end )
		end
	end
	return rankIcon
end

local rowHandler = {}

local function AddRankToSlot(row)
	local bagId = row.dataEntry.data.bagId
	local slotIndex = row.dataEntry.data.slotIndex

	local rankIcon = getIcon(row)

	-- Allow for ingeniousclown's Inventory Grid View
	if row:GetWidth() - row:GetHeight() < 5 then	-- if we're mostly square
		rankIcon:SetDimensions(20,20)
		rankIcon:SetAnchor(TOPLEFT, row, TOPLEFT, 2)
	else
		rankIcon:SetDimensions(30, 30)
		rankIcon:SetAnchor(CENTER, row, CENTER, 200)
	end

	rankIcon:SetHidden(true)

	if ((GetItemCraftingInfo(bagId, slotIndex)) == CRAFTING_TYPE_PROVISIONING) then
		local texture = Pantry[GetItemID(GetItemLink(bagId, slotIndex))]
		if settings.showAltKnowledge then texture = settings.Pantry[GetItemID(GetItemLink(bagId, slotIndex))] end
		if texture then
			rankIcon:SetColor(settings.colour[1], settings.colour[2], settings.colour[3])
			rankIcon:SetHidden(false)
			if settings.boldIcon then
				rankIcon:SetTexture(COOKINGB[texture])
			else
				rankIcon:SetTexture(COOKING[texture])
			end

		end
	else
		if GetItemType(bagId, slotIndex) == ITEMTYPE_RECIPE then
			local match = MatchInCookbook(bagId, slotIndex)
			local gmatch = MatchInGlobalCookbook(bagId, slotIndex)
			if (match and settings.checkKnown == "known") or
			   (not match and settings.checkKnown == "unknown")then
				rankIcon:SetTexture(CANLEARN)
				rankIcon:SetHidden(false)
				if not match and gmatch and settings.checkKnown == "unknown" and settings.markAlt then
					rankIcon:SetColor(1,1,1,0.2)
				else
					rankIcon:SetColor(1,1,1,1)
				end
			end
		end

	end
end

local function AddTradingSlot(row, result)
	local rankIcon = getIcon(row)

	rankIcon:SetHidden(true)

	if EndsWith(result.name, GetString(SI_ITEMTYPE29)) then
		local match = Cookbook[result.name:lower():gsub(" ","")]
		local gmatch = settings.Cookbook[result.name:lower():gsub(" ","")]
		if (match and settings.checkKnown == "known") or
		   (not match and settings.checkKnown == "unknown")then
			rankIcon:SetDimensions(30, 30)
			rankIcon:SetAnchor(CENTER, row, CENTER, 230)
			rankIcon:SetTexture(CANLEARN)
			rankIcon:SetHidden(false)
			if not match and gmatch and settings.checkKnown == "unknown" and settings.markAlt then
				rankIcon:SetColor(1,1,1,0.2)
			else
				rankIcon:SetColor(1,1,1,1)
			end
		end
	end
end

local function AddRecipe(Cookbook, link)
	for _,v in pairs(Cookbook) do
		if v == link then return end
	end
	table.insert(Cookbook, link)
end


local function ParseRecipes()
	local lists = GetNumRecipeLists()
	for listIndex = 1, lists do
		local name, count = GetRecipeListInfo(listIndex)
		for recipeIndex = 1, count do
			if GetRecipeInfo(listIndex, recipeIndex) then
				-- Store the recipes known
				local recipeName = (GetRecipeResultItemInfo(listIndex, recipeIndex)):gsub(" ",""):lower() .. "recipe"
				Cookbook[recipeName] = true
				if not settings.Cookbook[recipeName] then
					settings.Cookbook[recipeName] = {}
				end
				settings.Cookbook[recipeName][GetUnitName("player")] = true
				local _, _, ingredientCount, level = GetRecipeInfo(listIndex, recipeIndex)
				for ingredientIndex = 1, ingredientCount do
					local link = GetItemID(GetRecipeIngredientItemLink(listIndex, recipeIndex, ingredientIndex, LINK_STYLE_NORMAL))
					-- Store the fact that the ingredient is used
					Pantry[link] = level
					settings.Pantry[link] = level
					-- Store the recipe it's used in
					if not ReverseCookbook[link] then ReverseCookbook[link] = {} end
					AddRecipe(ReverseCookbook[link], GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS))
					-- Store the global reference
					if not settings.ReverseCookbook[link] then settings.ReverseCookbook[link] = {} end
					AddRecipe(settings.ReverseCookbook[link], GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS))
				end
			end

		end
	end
end

local function SousChefCreateSettings()
	local panel = LAM:CreateControlPanel("SousChef", "Sous Chef")

	LAM:AddHeader(panel, "SousChef_General", "Settings")

  	LAM:AddDropdown(panel, "markLearnt", "Mark if recipes are ",
						"How do you want Sous Chef to indicate your knowledge of a recipe?",
						{"known", "unknown"}, function() return settings.checkKnown end,
						function(valueString) settings.checkKnown = valueString end)
	LAM:AddCheckbox(panel, "markAltKnows", "Alternate Character Check", "Indicate if an alt knows the recipe on unknown recipes. Will only work if the above setting is set to 'unknown'",
						function() return settings.markAlt end,
						function(value) settings.markAlt = not settings.markAlt end)
	LAM:AddCheckbox(panel, "showAltKnows", "Alternate Character Recipe Knowledge", "Show rank indicators on alts for all recipe knowledge of all alternate characters",
						function() return settings.showAltKnowledge end,
						function(value) settings.showAltKnowledge = not settings.showAltKnowledge end)
	LAM:AddCheckbox(panel, "useBold", "Use bolder icons", "Swap out rank icon to a more flat display",
						function() return settings.boldIcon end,
						function(value) settings.boldIcon = not settings.boldIcon end)
	LAM:AddColorPicker(panel, "setColour", "Indicator colour",
						"Allows you to set the colour of the indicator",
						function() return settings.colour[1], settings.colour[2], settings.colour[3] end,
						function(r,g,b) settings.colour[1] = r; settings.colour[2] = g; settings.colour[3] = b end)

end

local function HookTrading(...)
	if hookedDataFunction then return end
	hookedDataFunction = ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback
	ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback = function(...)
		local row, data = ...
		hookedDataFunction(...)
		AddTradingSlot(row, data)
	end
end
local function SousChef_Loaded(eventCode, addOnName)

	if(addOnName ~= "SousChef") then
        return
    end

	local defaults = {
		watching = true,
		checkKnown = "unknown",
		markAlt = false,
		colour = {1, 1, 1},
		Cookbook = {},
		Pantry = {},
		ReverseCookbook = {},
		showAltKnowledge = false,
		boldIcon = false
	}

	settings = ZO_SavedVars:NewAccountWide("SousChef_Settings", 6, nil, defaults)

    SLASH_COMMANDS["/SCDebug"] = function()
		d("Debug mode on")
		SCCookbook = Cookbook
		SCRCookbook = ReverseCookbook
		SCPantry = Pantry
		SCslotList = slotLines
		SCsettings = settings
	end
	local function tablelength(T)
		local count = 0
		for _ in pairs(T) do count = count + 1 end
		return count
	end

	SLASH_COMMANDS['/scstats'] = function()
		d("Number of recipes known: ".. tablelength(settings.Cookbook))
		d("Number of ingredients tracked: "..tablelength(settings.Pantry))
	end

	SousChefCreateSettings()

	ParseRecipes()



	-- Now we want to hook into the function that sets the details on the inventory slot
	for _,v in pairs(PLAYER_INVENTORY.inventories) do
		local listView = v.listView
		if listView and listView.dataTypes and listView.dataTypes[1] then
			hookedFunctions = listView.dataTypes[1].setupCallback

			listView.dataTypes[1].setupCallback =
				function(rowControl, slot)
					hookedFunctions(rowControl, slot)
					AddRankToSlot(rowControl)
				end
		end
	end
	ZO_ScrollList_RefreshVisible(BACKPACK)
	ZO_ScrollList_RefreshVisible(BANK)
	ZO_ScrollList_RefreshVisible(GUILD_BANK)

	EVENT_MANAGER:RegisterForEvent("SousChefTRading", EVENT_TRADING_HOUSE_RESPONSE_RECEIVED, HookTrading)
	EVENT_MANAGER:RegisterForEvent("SousChefLearnt", EVENT_RECIPE_LEARNED, ParseRecipes)

end

local function SousChef_Initialized()
	EVENT_MANAGER:RegisterForEvent("SousChefLoaded", EVENT_ADD_ON_LOADED, SousChef_Loaded)
end



SousChef_Initialized()