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

inspired by ingeniousclown's Research Assistant

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

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

local rowHandler = {}

local typeIconLookup = {
	["Grilled"] = 9,
	["Bread and Pies"] = 10,
	["Soup and Stew"] = 11,
	["Beer"] = 12,
	["Spirits"] = 13,
	["Wine"] = 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[zo_strformat(SI_TOOLTIP_ITEM_NAME, 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], zo_strformat(SI_TOOLTIP_ITEM_NAME, 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], zo_strformat(SI_TOOLTIP_ITEM_NAME, 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 panelData = {
		type = "panel",
		name = "Sous Chef",
		displayName = "Sous Chef",
		author = "Wobin & KatKat42 & CrazyDutchGuy",
		version = "1.18",
		registerForRefresh = true,
	}

	LAM:RegisterAddonPanel("SousChefSettings", panelData)

	local optionsMenu = {
		[1] = {
			type = "header",
			name = "Recipe Options",
			width = "full",
		},

		[2] = {
			type = "checkbox",
			name = "Have Sous Chef check for recipes",
			tooltip = "Non English clients may want to untick this if the experimental matching isn't sufficient",
			getFunc = function() return SousChef.settings.processRecipes end,
			setFunc = function(value)
								SousChef.settings.processRecipes = not SousChef.settings.processRecipes
							end,
			width = "full",
		},

		[3] = {
			type = "dropdown",
			name = "Mark if recipes are ",
			tooltip = "How do you want Sous Chef to indicate your knowledge of a recipe?",
			choices = {"known", "unknown"},
			getFunc = function() return SousChef.settings.checkKnown end,
			setFunc = function(valueString) SousChef.settings.checkKnown = valueString end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[4] = {
			type = "checkbox",
			name = "Alternate Character Check",
			tooltip = "Indicate if an alt knows the recipe on unknown recipes. Will only work if the above setting is set to 'unknown'",
			getFunc = function() return SousChef.settings.markAlt end,
			setFunc = function(value) SousChef.settings.markAlt = not SousChef.settings.markAlt SousChef:RefreshViews() end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[5] = {
			type = "checkbox",
			name = "Alternate Character Recipe Knowledge",
			tooltip = "Show in tooltips which characters know a recipe",
			getFunc = function() return SousChef.settings.showAltKnowledge end,
			setFunc = function(value) SousChef.settings.showAltKnowledge = not SousChef.settings.showAltKnowledge SousChef:RefreshViews() end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[6] = {
			type = "checkbox",
			name = "Use the Experimental Recipe Matcher",
			tooltip = "Currently Sous Chef cannot match reliably in other languages. This will attempt to match as best it can by stripping out common prepositions so that the recipe and result match better. (NOTE: please file a typo bug report with Zenimax if you find recipe names that don't match their results exactly)",
			getFunc = function() return SousChef.settings.experimentalMatch end,
			setFunc = function(value) SousChef.settings.experimentalMatch = not SousChef.settings.experimentalMatch end,
			disabled = function() return not SousChef.settings.processRecipes end,
		},

		[7] = {
			type = "checkbox",
			name = "Sort the Provisioning Table",
			tooltip = "Will sort the provisioning table by Rank, Quality, then Name (but not by required level)",
			getFunc = function() return SousChef.settings.sortProvisioningTable end,
			setFunc = function(value) SousChef.settings.sortProvisioningTable = not SousChef.settings.sortProvisioningTable end,
		},

		[8] = {
			type = "header",
			name = "Tooltip Options",
			width = "full",
		},

		[9] = {
			type = "checkbox",
			name = "Show Sous Chef in Ingredient tooltips after Mouse Click",
			tooltip = "Only show Sous Chef information in ingredient tooltips after a mouse click, to save space",
			warning = "Requires UI Reload",
			getFunc = function() return SousChef.settings.showOnClick end,
			setFunc = function(value) SousChef.settings.showOnClick = not SousChef.settings.showOnClick end,
		},

		[10] = {
			type = "checkbox",
			name = "Show Recipe Result Counts",
			tooltip = "Show how many of each recipe can be made in the Ingredient tooltip",
			getFunc = function() return SousChef.settings.showCounts end,
			setFunc = function(value) SousChef.settings.showCounts = not SousChef.settings.showCounts end,
		},

		[11] = {
			type = "checkbox",
			name = "Alternate Character Ingredient Knowledge",
			tooltip = "Indicte if an alt uses the ingredients",
			getFunc = function() return SousChef.settings.showAltIngredientKnowledge end,
			setFunc = function(value) SousChef.settings.showAltIngredientKnowledge = not SousChef.settings.showAltIngredientKnowledge SousChef:RefreshViews() end,
		},

		[12] = {
			type = "header",
			name = "Indicator Options",
			width = "full",
		},

		[13] = {
			type = "checkbox",
			name = "Use bolder icons",
			tooltip = "Swap out rank icons to a more flat display",
			getFunc = function() return SousChef.settings.boldIcon end,
			setFunc = function(value) SousChef.settings.boldIcon = not SousChef.settings.boldIcon SousChef:RefreshViews() end,
		},

		[14] = {
			type = "checkbox",
			name = "Show Special Ingredients",
			tooltip = "If an ingredient is considered a Spice/Flavour, indicate that rather than the tier of the highest tier recipe that uses it",
			getFunc = function() return SousChef.settings.showSpecialIngredients end,
			setFunc = function(value)
							SousChef.settings.showSpecialIngredients = not SousChef.settings.showSpecialIngredients
							SousChef.ParseRecipes()
						end,
		},

		[15] = {
			type = "checkbox",
			name = "Show Special Ingredient Types",
			tooltip = "Use the icon for the type of food it's a special ingredient for, eg Grilled",
			getFunc = function() return SousChef.settings.typeIcon end,
			setFunc = function(value) SousChef.settings.typeIcon = not SousChef.settings.typeIcon SousChef.ParseRecipes() SousChef:RefreshViews() end,
			disabled = function() return not SousChef.settings.showSpecialIngredients end,
		},

		[16] = {
			type = "colorpicker",
			name = "Indicator Colour",
			tooltip = "Allows you to set the colour of the recipe indicator",
			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 = "Shopping List Indicator Colour",
			tooltip = "Allows you to set the colour of hte indicator for ingredients in your Shopping List",
			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 = "Only Mark Shopping List Ingredients",
			tooltip = "Only mark ingredients on your Shopping List",
			getFunc = function() return SousChef.settings.onlyShowShopping end,
			setFunc = function(value) SousChef.settings.onlyShowShopping = not SousChef.settings.onlyShowShopping SousChef:RefreshViews() end,
		},

		[19] = {
			type = "checkbox",
			name = "Sort Ingredients in Inventory",
			tooltip = "Will sort known ingredients by rank",
			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)

	ZO_CreateStringId("SI_BINDING_NAME_SC_MARK_RECIPE", "Mark Recipe")
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
	}

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

	local function tablelength(T)
		local count = 0
		for _ in pairs(T) do count = count + 1 end
		return count
	end

	-- define some slash commands
	SLASH_COMMANDS['/scstats'] = function()
		d("Number of recipes known: ".. tablelength(SousChef.settings.Cookbook))
		d("Number of ingredients tracked: "..tablelength(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

	-- 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)