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

inspired by ingeniousclown's Research Assistant

------------------------------------------------------------------]]--
SousChef = {}

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

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}}
SousChef.Pantry = {}
SousChef.Cookbook = {}
SousChef.ReverseCookbook = {}
SousChef.settings = nil
SousChef.slotLines = {}
SousChef.hookedFunctions = {}
SousChef.hookedDataFunction = nil

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

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

local function StartsWith(String,Start)
    return Start=='' or string.sub(String, 1, string.len(Start))==Start
end

local function CleanString(entry)
    return entry:gsub("%^(%a+)", ""):gsub(" ",""):gsub("-",""):lower()
end

local function MatchesRecipe(entry)
    return CleanString(entry):find(CleanString(GetString(SI_ITEMTYPE29)))
end

local function MatchInCookbook(name)
    name = CleanString(name)
    for recipe,known in pairs(SousChef.Cookbook) do
        if StartsWith(name,recipe) or EndsWith(name, recipe) then
            if (#recipe + #CleanString(GetString(SI_ITEMTYPE29)) - #name) < 3 then
                return known
            end
        end
    end
	return nil
end

local function MatchInGlobalCookbook(name)
    name = CleanString(name)
    for recipe,known in pairs(SousChef.settings.Cookbook) do
        if StartsWith(name,recipe) or EndsWith(name, recipe) then
            if (#recipe + #CleanString(GetString(SI_ITEMTYPE29)) - #name) < 3 then
                return known
            end
        end
    end
    return nil
end

 rowClicked = {}

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

	if MatchesRecipe(rowInfo.name) then
        local gmatch = MatchInGlobalCookbook(rowInfo.name)
        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 = SousChef.ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))]
	if SousChef.settings.showAltKnowledge then usableIngredient = SousChef.settings.ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))] end
	if usableIngredient then
		ItemTooltip:AddLine("Used in:", "ZoFontWinH5", 1,1,1, BOTTOM, MODIFY_TEXT_TYPE_UPPERCASE)
		for i,v in ipairs(usableIngredient) do
			ItemTooltip:AddLine(v)
		end
		rowClicked[row] = true
	end
	return false
end

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

local rowHandler = {}

local function AddRankToSlot(row)
    local slot = row.dataEntry.data
    local bagId = slot.bagId
    local slotIndex = slot.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 = SousChef.Pantry[GetItemID(GetItemLink(bagId, slotIndex))]
		if SousChef.settings.showAltKnowledge then texture = SousChef.settings.Pantry[GetItemID(GetItemLink(bagId, slotIndex))] end
		if texture then
			rankIcon:SetColor(SousChef.settings.colour[1], SousChef.settings.colour[2], SousChef.settings.colour[3])
			rankIcon:SetHidden(false)
			if SousChef.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(slot.name)
			local gmatch = MatchInGlobalCookbook(slot.name)
			if (match and SousChef.settings.checkKnown == "known") or
			   (not match and SousChef.settings.checkKnown == "unknown")then
				rankIcon:SetTexture(CANLEARN)
				rankIcon:SetHidden(false)
				if not match and gmatch and SousChef.settings.checkKnown == "unknown" and SousChef.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 MatchesRecipe(result.name) then
		local match = MatchInCookbook(result.name)
		local gmatch = MatchInGlobalCookbook(result.name)
		if (match and SousChef.settings.checkKnown == "known") or
		   (not match and SousChef.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 SousChef.settings.checkKnown == "unknown" and SousChef.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 = CleanString((GetRecipeResultItemInfo(listIndex, recipeIndex)))
                SousChef.Cookbook[recipeName] = true
				if not SousChef.settings.Cookbook[recipeName] then
                    SousChef.settings.Cookbook[recipeName] = {}
				end
                SousChef.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
                    SousChef.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0)
                    SousChef.settings.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0)
					-- Store the recipe it's used in
					if not SousChef.ReverseCookbook[link] then SousChef.ReverseCookbook[link] = {} end
					AddRecipe(SousChef.ReverseCookbook[link], zo_strformat(SI_TOOLTIP_ITEM_NAME, GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)))
					-- Store the global reference
					if not SousChef.settings.ReverseCookbook[link] then SousChef.settings.ReverseCookbook[link] = {} end
					AddRecipe(SousChef.settings.ReverseCookbook[link], zo_strformat(SI_TOOLTIP_ITEM_NAME, GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)))
				end
			end

		end
	end
end

local function SousChefCreateSettings()
    d("Creating menu")
	local panel = LAM:CreateControlPanel("SousChefMenu", "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 SousChef.settings.checkKnown end,
						function(valueString) SousChef.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 SousChef.settings.markAlt end,
						function(value) SousChef.settings.markAlt = not SousChef.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 SousChef.settings.showAltKnowledge end,
						function(value) SousChef.settings.showAltKnowledge = not SousChef.settings.showAltKnowledge end)
	LAM:AddCheckbox(panel, "useBold", "Use bolder icons", "Swap out rank icon to a more flat display",
						function() return SousChef.settings.boldIcon end,
						function(value) SousChef.settings.boldIcon = not SousChef.settings.boldIcon end)
	LAM:AddColorPicker(panel, "setColour", "Indicator colour",
						"Allows you to set the colour of the indicator",
						function() return SousChef.settings.colour[1], SousChef.settings.colour[2], SousChef.settings.colour[3] end,
						function(r,g,b) SousChef.settings.colour[1] = r; SousChef.settings.colour[2] = g; SousChef.settings.colour[3] = b end)

end

local function HookTrading(...)
	if SousChef.hookedDataFunction then return end
    SousChef.hookedDataFunction = ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback
	ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback = function(...)
		local row, data = ...
        SousChef.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
	}

    SousChef.settings = ZO_SavedVars:NewAccountWide("SousChef_Settings", 8, nil, defaults)

	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(SousChef.settings.Cookbook))
		d("Number of ingredients tracked: "..tablelength(SousChef.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
            SousChef.hookedFunctions = listView.dataTypes[1].setupCallback

			listView.dataTypes[1].setupCallback =
				function(rowControl, slot)
                    SousChef.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()