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

inspired by ingeniousclown's Research Assistant
Thanks to Ayantir for the French translations, and sirinsidiator for the German

------------------------------------------------------------------]]--

SousChef = {}
SousChef.Utility = {}
SousChef.Media = {}

local SousChef = SousChef
local u = SousChef.Utility

local LAM = LibStub:GetLibrary("LibAddonMenu-2.0")

local BACKPACK = ZO_PlayerInventoryBackpack
local BANK = ZO_PlayerBankBackpack
local GUILD_BANK = ZO_GuildBankBackpack

SousChef.Pantry = {}
SousChef.Cookbook = {}
SousChef.CookbookIndex = {}
SousChef.ReverseCookbook = {}
SousChef.settings = nil
SousChef.slotLines = {}
SousChef.hookedFunctions = {}
SousChef.hookedDataFunction = nil
SousChef.lang = GetCVar("Language.2")
if SousChef.lang ~= "en" and SousChef.lang ~= "de" and SousChef.lang ~= "fr" then SousChef.lang = "en" end

local rowHandler = {}

local typeIconLookup = {
	-- en
	["Grilled"] = 9,
	["Bread and Pies"] = 10,
	["Soup and Stew"] = 11,
	["Beer"] = 12,
	["Spirits"] = 13,
	["Wine"] = 14,
	-- de
	["Gegrillt"] = 9,
	["Brot und Kuchen"] = 10,
	["Suppen und Eintöpfe"] = 11,
	["Bier"] = 12,
	["Getränke"] = 13,
	["Wein"] = 14,
	-- fr
	["Grillades"] = 9,
	["Pain et Tartes"] = 10,
	["Soupe et Ragoût"] = 11,
	["Bi\195\169re"] = 12,
	["Spiritueux"] = 13,
	["Vin"] = 14,
}


-- FUNCTIONS
-- AddRecipe(Cookbook, link) adds the linked recipe to the player cookbook if it isn't there already.
local function AddRecipe(Cookbook, link)
	for _,v in pairs(Cookbook) do
		if v == link then return end
	end
	table.insert(Cookbook, link)
end

-- RefreshViews() incorporates changes to the rendered inventory if it is visible.
function SousChef:RefreshViews()
	ZO_ScrollList_RefreshVisible(BACKPACK)
	ZO_ScrollList_RefreshVisible(BANK)
	ZO_ScrollList_RefreshVisible(GUILD_BANK)
end

-- ParseRecipes() goes through the player's known recipes and records their info.
function SousChef: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 = u.CleanString((GetRecipeResultItemInfo(listIndex, recipeIndex)))
				-- in this character's cookbook
                SousChef.Cookbook[recipeName] = true
				-- and in the settings, so other characters can see what recipes this character knows
				if not SousChef.settings.Cookbook[recipeName] then
                    SousChef.settings.Cookbook[recipeName] = {}
				end
                SousChef.settings.Cookbook[recipeName][GetUnitName("player")] = true

				-- now record information about the recipe's ingregients
				local _, _, ingredientCount, level, _, specialType = GetRecipeInfo(listIndex, recipeIndex)
				-- store the recipe's index numbers and number of ingredients
				-- XXX: why does this table get indexed with the formatted item name, but the Pantry table uses the whole link?
				SousChef.CookbookIndex[GetItemLinkName(GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS))] =
					{listIndex = listIndex, recipeIndex = recipeIndex, numIngredients = ingredientCount}
				-- now, for every ingredient in the current recipe...
				for ingredientIndex = 1, ingredientCount do
					local link = u.GetItemID(GetRecipeIngredientItemLink(listIndex, recipeIndex, ingredientIndex, LINK_STYLE_DEFAULT))
					-- Store the fact that the ingredient is used
                    if ingredientIndex < 3 or not SousChef.settings.showSpecialIngredients then
						-- if this isn't a special ingredient, or if the user doesn't want special ingredients marked as special, just record the highest-tier recipe this ingredient appears in
						-- for this character,
                        SousChef.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0)
						-- and across characters
                        SousChef.settings.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0)
                    else
						-- if this is a special ingredient, record:
						-- 						type icon number if user wants type icons,								7 if ingredient is a flavoring,						8 otherwise (ie, ingredient is a spice)
                        SousChef.Pantry[link] = SousChef.settings.typeIcon and typeIconLookup[name] or specialType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FLAVORING and 7 or 8
                        SousChef.settings.Pantry[link] = SousChef.settings.typeIcon and typeIconLookup[name] or specialType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FLAVORING and 7 or 8
                    end
					-- Store the recipe it's used in to the character reverseCookbook
					if not SousChef.ReverseCookbook[link] then SousChef.ReverseCookbook[link] = {} end
					AddRecipe(SousChef.ReverseCookbook[link], GetItemLinkName(GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)))
					-- ...and to the account-wide reverseCookbook
					if not SousChef.settings.ReverseCookbook[link] then SousChef.settings.ReverseCookbook[link] = {} end
					AddRecipe(SousChef.settings.ReverseCookbook[link], GetItemLinkName(GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)))
				end
			end
		end
	end
	SousChef:RefreshViews()
end

-- SousChefCreateSettings() creates the configuration menu for the add-on
local function SousChefCreateSettings()
	local str = SousChef.Strings[SousChef.lang]
	local panelData = {
		type = "panel",
		name = "Sous Chef",
		displayName = "Sous Chef",
		author = "Wobin & KatKat42 & CrazyDutchGuy",
		version = "2.9",
		registerForRefresh = true,
		slashCommand = "/souschef",
	}

	LAM:RegisterAddonPanel("SousChefSettings", panelData)

	local optionsMenu = {
		[1] = {
			type = "header",
			name = str.MENU_RECIPE_HEADER,
			width = "full",
		},

		[2] = {
			type = "checkbox",
			name = str.MENU_PROCESS_RECIPES,
			tooltip = str.MENU_PROCESS_RECIPES_TOOLTIP,
			getFunc = function() return SousChef.settings.processRecipes end,
			setFunc = function(value) SousChef.settings.processRecipes = value end,
			width = "full",
		},

		[3] = {
			type = "dropdown",
			name = str.MENU_MARK_IF_KNOWN,
			tooltip = str.MENU_MARK_IF_KNOWN_TOOLTIP,
			choices = {str.MENU_KNOWN, str.MENU_UNKNOWN},
			getFunc = function()
				if SousChef.settings.checkKnown == "known" then
					return str.MENU_KNOWN
				elseif SousChef.settings.checkKnown == "unknown" then
					return str.MENU_UNKNOWN
				else
					-- can't happen
					d("Yikes! MENU_MARK_IF_KNOWN getter")
					return str.MENU_UNKNOWN
				end
			end,
			setFunc = function(valueString)
				if valueString == str.MENU_KNOWN then
					SousChef.settings.checkKnown = "known"
				elseif valueString == str.MENU_UNKNOWN then
					SousChef.settings.checkKnown = "unknown"
				else
					-- can't happen
					d("Oops! MENU_MARK_IF_KNOWN setter")
					SousChef.settings.checkKnown = "unknown"
				end
			end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[4] = {
			type = "checkbox",
			name = str.MENU_MARK_IF_ALT_KNOWS,
			tooltip = str.MENU_MARK_IF_ALT_KNOWS_TOOLTIP,
			getFunc = function() return SousChef.settings.markAlt end,
			setFunc = function(value) SousChef.settings.markAlt = value SousChef:RefreshViews() end,
			disabled = function() return (not SousChef.settings.processRecipes) or (SousChef.settings.checkKnown == "known") end,
		},

		[5] = {
			type = "checkbox",
			name = str.MENU_TOOLTIP_IF_ALT_KNOWS,
			tooltip = str.MENU_TOOLTIP_IF_ALT_KNOWS_TOOLTIP,
			getFunc = function() return SousChef.settings.showAltKnowledge end,
			setFunc = function(value) SousChef.settings.showAltKnowledge = value SousChef:RefreshViews() end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[6] = {
			type = "checkbox",
			name = str.MENU_MATCHER,
			tooltip = str.MENU_MATCHER_TOOLTIP,
			getFunc = function() return SousChef.settings.experimentalMatch end,
			setFunc = function(value) SousChef.settings.experimentalMatch = value end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[7] = {
			type = "checkbox",
			name = str.MENU_SORT_PROVISIONING,
			tooltip = str.MENU_SORT_PROVISIONING_TOOLTIP,
			getFunc = function() return SousChef.settings.sortProvisioningTable end,
			setFunc = function(value)
				SousChef.settings.sortProvisioningTable = value
				if value then
					SousChef:HookGetRecipeInfo()
				else
					SousChef:UnhookGetRecipeInfo()
				end
			end,
		},

		[8] = {
			type = "header",
			name = str.MENU_TOOLTIP_HEADER,
			width = "full",
		},

		[9] = {
			type = "checkbox",
			name = str.MENU_TOOLTIP_CLICK,
			tooltip = str.MENU_TOOLTIP_CLICK_TOOLTIP,
			warning = str.MENU_RELOAD,
			getFunc = function() return SousChef.settings.showOnClick end,
			setFunc = function(value) SousChef.settings.showOnClick = value end,
		},

		[10] = {
			type = "checkbox",
			name = str.MENU_RESULT_COUNTS,
			tooltip = str.MENU_RESULT_COUNTS_TOOLTIP,
			getFunc = function() return SousChef.settings.showCounts end,
			setFunc = function(value) SousChef.settings.showCounts = value end,
		},

		[11] = {
			type = "checkbox",
			name = str.MENU_ALT_USE,
			tooltip = str.MENU_ALT_USE_TOOLTIP,
			getFunc = function() return SousChef.settings.showAltIngredientKnowledge end,
			setFunc = function(value) SousChef.settings.showAltIngredientKnowledge = value SousChef:RefreshViews() end,
		},

		[12] = {
			type = "header",
			name = str.MENU_INDICATOR_HEADER,
			width = "full",
		},

		[13] = {
			type = "checkbox",
			name = str.MENU_ICON_SET,
			tooltip = str.MENU_ICON_SET_TOOLTIP,
			getFunc = function() return SousChef.settings.boldIcon end,
			setFunc = function(value) SousChef.settings.boldIcon = value SousChef:RefreshViews() end,
		},

		[14] = {
			type = "checkbox",
			name = str.MENU_SPECIAL_ICONS,
			tooltip = str.MENU_SPECIAL_ICONS_TOOLTIP,
			getFunc = function() return SousChef.settings.showSpecialIngredients end,
			setFunc = function(value)
				SousChef.settings.showSpecialIngredients = value
				SousChef.ParseRecipes()
			end,
		},

		[15] = {
			type = "checkbox",
			name = str.MENU_SPECIAL_TYPES,
			tooltip = str.MENU_SPECIAL_TYPES_TOOLTIP,
			getFunc = function() return SousChef.settings.typeIcon end,
			setFunc = function(value) SousChef.settings.typeIcon = value SousChef.ParseRecipes() SousChef:RefreshViews() end,
			disabled = function() return not SousChef.settings.showSpecialIngredients end,
		},

		[16] = {
			type = "colorpicker",
			name = str.MENU_INDICATOR_COLOR,
			tooltip = str.MENU_INDICATOR_COLOR_TOOLTIP,
			getFunc = function() return SousChef.settings.colour[1], SousChef.settings.colour[2], SousChef.settings.colour[3] end,
			setFunc = function(r,g,b)
				SousChef.settings.colour[1] = r
				SousChef.settings.colour[2] = g
				SousChef.settings.colour[3] = b
				SousChef:RefreshViews()
			end,
		},

		[17] = {
			type = "colorpicker",
			name = str.MENU_SHOPPING_COLOR,
			tooltip = str.MENU_SHOPPING_COLOR_TOOLTIP,
			getFunc = function() return SousChef.settings.shoppingColour[1], SousChef.settings.shoppingColour[2], SousChef.settings.shoppingColour[3] end,
			setFunc = function(r,g,b)
				SousChef.settings.shoppingColour[1] = r
				SousChef.settings.shoppingColour[2] = g
				SousChef.settings.shoppingColour[3] = b
				SousChef:RefreshViews()
			end,
		},

		[18] = {
			type = "checkbox",
			name = str.MENU_ONLY_MARK_SHOPPING,
			tooltip = str.MENU_ONLY_MARK_SHOPPING_TOOLTIP,
			getFunc = function() return SousChef.settings.onlyShowShopping end,
			setFunc = function(value) SousChef.settings.onlyShowShopping = value SousChef:RefreshViews() end,
		},

		[19] = {
			type = "checkbox",
			name = str.MENU_SORT_INGREDIENTS,
			tooltip = str.MENU_SORT_INGREDIENTS_TOOLTIP,
			getFunc = function() return SousChef.settings.sortKnownIngredients end,
			setFunc = function(value)
				SousChef.settings.sortKnownIngredients = not SousChef.settings.sortKnownIngredients
				if not SousChef.settings.sortKnownIngredients then
					SousChef.UnregisterSort()
				else
					SousChef.SetupSort()
				end
			end,
		},
	}

	LAM:RegisterOptionControls("SousChefSettings", optionsMenu)
end

-- SousChef_Loaded(eventCode, addOnName) runs when the EVENT_ADD_ON_LOADED event fires.
local function SousChef_Loaded(eventCode, addOnName)
	if(addOnName ~= "SousChef") then return end

	-- default config settings
	local defaults = {
		--watching = true,
		checkKnown = "unknown",
		markAlt = false,
		colour = {1, 1, 1},
		shoppingColour = {0,1,1},
		Cookbook = {},
		Pantry = {},
		ReverseCookbook = {},
		showAltKnowledge = false,
		showAltIngredientKnowledge = false,
		boldIcon = false,
		typeIcon = true,
        experimentalMatch = false,
        processRecipes = true,
        showSpecialIngredients = false,
        ignoredRecipes = {},
        showOnClick = false,
        showCounts = true,
        shoppingList = {},
        onlyShowShopping = false,
        qualityChecked = false,
        sortProvisioningTable = true,
        sortKnownIngredients = false
	}

	local localized = SousChef.Strings[SousChef.lang]

	-- Fetch the saved variables
    SousChef.settings = ZO_SavedVars:NewAccountWide("SousChef_Settings", 9, SousChef.lang, defaults)

	-- redo some saved vars with the new format
	for ingredient, recipes in pairs(SousChef.settings.ReverseCookbook) do
		for index, linkOrName in pairs(recipes) do
			if (string.find(linkOrName, "|H1:", 1, true) ~= nil) then
				linkOrName = GetItemLinkName(linkOrName)
			end
		end
	end

	for recipe, chars in pairs(SousChef.settings.shoppingList) do
		if (string.find(recipe, "|H1:", 1, true) ~= nil) then
			SousChef.settings.shoppingList[GetItemLinkName(recipe)] = chars
			SousChef.settings.shoppingList[recipe] = nil
		end
	end

	-- define some slash commands
	SLASH_COMMANDS['/scstats'] = function()
		d(localized.SC_NUM_RECIPES_KNOWN.. NonContiguousCount(SousChef.settings.Cookbook))
		d(localized.SC_NUM_INGREDIENTS_TRACKED..NonContiguousCount(SousChef.settings.Pantry))
	end
	SLASH_COMMANDS['/sciadd'] = SousChef.AddRecipeToIgnoreList
	SLASH_COMMANDS['/sciremove'] = SousChef.RemoveRecipeFromIgnoreList
	SLASH_COMMANDS['/scilist'] = SousChef.ListIgnoredRecipes

	-- initialize the configuration menu
	SousChefCreateSettings()

	-- parse the recipes this character knows, in a second
	zo_callLater(SousChef.ParseRecipes, 1000)

	SousChef:UpdateProvisioningTable()
	SousChef:HookGetRecipeInfo()

	if SousChef.settings.sortKnownIngredients then SousChef.SetupSort() end

	ZO_CreateStringId("SI_BINDING_NAME_SC_MARK_RECIPE", localized.KEY_MARK)

	-- Now we register for some events, and hook into the function that sets the details on the inventory slot
	zo_callLater(SousChef.HookEvents, 3000)
end

-- HookEvents() registers the add-on for some events
function SousChef.HookEvents()
	-- let us know if we're opening a trading house, so we can look at its contents
	EVENT_MANAGER:RegisterForEvent("SousChefTrading", EVENT_TRADING_HOUSE_RESPONSE_RECEIVED, SousChef.HookTrading)
	-- let us know if we've learned a new recipe, so we can integrate it into our cookbook
	EVENT_MANAGER:RegisterForEvent("SousChefLearnt", EVENT_RECIPE_LEARNED, SousChef.ParseRecipes)
	-- let us know when we open a crafting station, so we can sort the recipe tree
    EVENT_MANAGER:RegisterForEvent("SousChefProvi", EVENT_CRAFTING_STATION_INTERACT, function(...) SousChef:HookRecipeTree(...) end)
    EVENT_MANAGER:RegisterForEvent("SousChefProviEnd", EVENT_END_CRAFTING_STATION_INTERACT, function() SousChef:UnhookRecipeTree() end)
    -- and finally, hook the opening of the inventory, bank, guild bank, and loot windows so we can add icons and hook the tooltips
    SousChef.HookInventory()
end

EVENT_MANAGER:RegisterForEvent("SousChefLoaded", EVENT_ADD_ON_LOADED, SousChef_Loaded)