local LAM2 = LibStub("LibAddonMenu-2.0")


---------------------SETTINGS----------------------

local KBS = {}
KBS.Defaults = {}
KBS.Defaults.Global = {}
KBS.Defaults.Global.GlobalTargetSystem = false --TODO: Implement to make all characters use same target table
KBS.Defaults.Global.BindingTarget = "Main"   --TODO: Implement as global target table name
KBS.Defaults.Global.AvailKeyTables = {[1] = "Main"}
KBS.Defaults.Global.KeyTables = {Main}
KBS.Defaults.Global.KeyTables.Main = {}
KBS.Defaults.Character = {}
KBS.Defaults.Character.DelTarget = "Main"
KBS.Defaults.Character.saveType = "Global"
KBS.Defaults.Character.BindingTarget = "Main"
KBS.Defaults.Character.SyncMode = "Manual"

KBS.CODE_VERSION = 0.51
KBS.SAVED_VAR_VERSION = 0.4
KBS.UsableOnly = true
KBS.SettingsFile = "KeyBindSwapperSettings"
KBS.Name = "Talen-Shei's Keybind Swapper"
KBS.SVProfile = "KBSMultiAccount" -- Experimental stuff here.

---------------------------KEYBIND MANAGEMENT-------------------------------
--[[
	-- Useage:		getKeyBinds(saveTable)
	-- @param:		{saveTable} Table in/to be created in KBS.Global.KeyTables
	-- Used By:		saveBinds
]]
function getKeyBinds(saveTable)
	saveTable.BindTable = {}
	local layers = GetNumActionLayers()
	for layer = 1, layers, 1 do
		name,numcat = GetActionLayerInfo(layer)
		-- d(layer..":"..name..":  " ..numcat)
		saveTable.BindTable[layer] = {}
		saveTable.BindTable[layer].Name = name
		saveTable.BindTable[layer].LayerNumber = layer
		saveTable.BindTable[layer].NumberOfCategories= numcat
		saveTable.BindTable[layer].Category = {}
		for cat = 1, numcat, 1 do
			catname, numactions = GetActionLayerCategoryInfo(layer,cat)
			-- d(name..":"..catname..":  "..numactions)
			saveTable.BindTable[layer].Category[cat] = {}
			saveTable.BindTable[layer].Category[cat].Name = catname
			saveTable.BindTable[layer].Category[cat].NumActions = numactions
			saveTable.BindTable[layer].Category[cat].Actions = {}
			for action = 1, numactions, 1 do
				actionname, isRebindable, isHidden = GetActionInfo(layer,cat,action)
				-- d(actionname..":  "..tostring(isRebindable).." | "..tostring(isHidden))
				saveTable.BindTable[layer].Category[cat].Actions[action] = {}
				saveTable.BindTable[layer].Category[cat].Actions[action].Name = actionname
				saveTable.BindTable[layer].Category[cat].Actions[action].isRebindable = isRebindable
				saveTable.BindTable[layer].Category[cat].Actions[action].isHidden = isHidden
				saveTable.BindTable[layer].Category[cat].Actions[action].Keys = {}
				for index = 1, 2 do
					keycode, keymod1, keymod2, keymod3, keymod4 = GetActionBindingInfo(layer,cat,action,index)
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index] = {}
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index].KeyCode = keycode
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod1 = keymod1
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod2 = keymod2
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod3 = keymod3
					saveTable.BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod4 = keymod4
				end
			end
		end
	end
end

--[[
	-- Useage:		setKeyBinds(profile)
	-- @param:		{profile} Name of table in KBS.Global.KeyTables, if invalid we will use the saved target table
	-- Used By:		Import Profile button, /setkeys
]]
function setKeyBinds(profile)
	local isSafe = true
	if profile then
		isSafe = false
		for i=1, #KBS.Global.AvailKeyTables do
			if KBS.Global.AvailKeyTables[i] == profile then
				isSafe = true
				-- d("we checked if it was safe")
			end
		end
		if isSafe == true then
			for layer = 1, #KBS.Global.KeyTables[profile].BindTable do
				for cat = 1, #KBS.Global.KeyTables[profile].BindTable[layer].Category do
					for action = 1, #KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions do
						if KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].isRebindable == true and KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].isHidden == false then
							for index = 1, #KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys do
								keycode = KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyCode
								keymod1 = KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod1
								keymod2 = KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod2
								keymod3 = KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod3
								keymod4 = KBS.Global.KeyTables[profile].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod4
								if IsProtectedFunction("BindKeyToAction") then
									CallSecureProtected("BindKeyToAction", layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
								else
									BindKeyToAction(layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
								end
							end
						end
					end
				end
			end
		end
	else
		-- d("We didn't check if it was safe")
		for layer = 1, #KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable do
			for cat = 1, #KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category do
				for action = 1, #KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions do
					if  KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].isRebindable == true and KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].isHidden == false then
						for index = 1, #KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys do
							keycode = KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyCode
							keymod1 = KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod1
							keymod2 = KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod2
							keymod3 = KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod3
							keymod4 = KBS.Global.KeyTables[KBS.Character.BindingTarget].BindTable[layer].Category[cat].Actions[action].Keys[index].KeyMod4
							if keycode == 0 and keymod1 == 0 and keymod2 == 0 and keymod3 == 0 and keymod4 == 0 then
								if IsProtectedFunction("UnbindKeyFromAction") then
									CallSecureProtected("UnbindKeyFromAction", layer,cat,action,index)
									-- d(layer..cat..action..index)
								else
									BindKeyToAction(layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
									-- d(layer..cat..action..index)
								end
							else
								if IsProtectedFunction("BindKeyToAction") then
									CallSecureProtected("BindKeyToAction", layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
									-- d(layer..cat..action..index)
								else
									BindKeyToAction(layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
									-- d(layer..cat..action..index)
								end
							end
						end
					end
				end
			end
		end
	end
end

--[[
	-- Useage:		saveBinds(saveType, saveTable)
	-- @param:		{arg1} Global/Character Global Profile or Private Profile
	-- @param:		{arg2} Name of table to create or overwrite
	-- Used By:		Save Profile Button, /savekeys
]]
function saveBinds(arg1, arg2)
	if arg2 == nil then
		if arg1 == nil then
			arg1 = KBS.Character.saveType
		end
		if arg1 == "Global" then
			getKeyBinds(KBS.Global.KeyTables.Main)
		else
			getKeyBinds(KBS.Character.KeyTables.Main)
		end
	else
		if arg1 == nil then
			arg1 = KBS.Character.saveType
		end
		if arg1 == "Global" then
			KBS.Global.KeyTables[arg2] = {}
			getKeyBinds(KBS.Global.KeyTables[arg2])
		else
			KBS.Character.KeyTables[arg2] = {}
			getKeyBinds(KBS.Character.KeyTables[arg2])
		end
	end
end


-------------------PROFILE MANAGEMENT------------------


function removeProfile(profile)
	KBS.Global.KeyTables[profile] = nil
	for i=1,#KBS.Global.AvailKeyTables do
		if KBS.Global.AvailKeyTables[i] == profile then
			table.remove(KBS.Global.AvailKeyTables, i)
		end
	end
end

function createNewProfile(name)
	if KBS.Character.saveType == "Global" then
		for i=1, #KBS.Global.AvailKeyTables do
			if KBS.Global.AvailKeyTables[i] == name then
				return
			end
		end
		table.insert(KBS.Global.AvailKeyTables, name)
		KBS.Global.KeyTables[name] = {}
	else
		for i=1, #KBS.Character.AvailKeyTables do
			if KBS.Character.AvailKeyTables[i] == name then
				return
			end
		end
		table.insert(KBS.Character.AvailKeyTables, name)
		KBS.Character.KeyTables[name] = {}
	end
end


---------------------LAM 2.0 SETTINGS--------------------------


local function CreateSettingsMenu()
	local colorYellow = "|cFFFF22"

	local panelData = {
		type = "panel",
		name = "Keybind Swapper",
		displayName = colorYellow.."Talen-Shei's Awesome Keybind Swapper",
		author = "Talen-Shei",
		version = KBS.CODE_VERSION,
		slashCommand = "/keybinds",
		registerForRefresh = true,
		registerForDefaults = true,
	}

	local cntrlOptionsPanel = LAM2:RegisterAddonPanel("KBS_Options", panelData)

	optionsData = {
		[1] = {
		type = "header",
		name = colorYellow.."Loading",
		width = "full",
		},
		[2] = {
			type = "description",
			text = "A Tool to save and import keybind profiles."..colorYellow.."For the time being please do not use Per-Character Save Type.",
		},
		[3] = {
			type = "dropdown",
			name = "Save Type",
			choices = {"Global", "Per Character"},
			default = "Global",
			getFunc = function() return KBS.Character.saveType end,
			setFunc = function(bValue) KBS.Character.saveType = bValue end,
		},
		[4] = {
			type = "dropdown",
			name = "Profile",
			choices = KBS.Global.AvailKeyTables,
			sort = "name-up",
			reference = "KBSProfiles",
			default = "Main",
			getFunc = function() return KBS.Character.BindingTarget end,
			setFunc = function(bValue) KBS.Character.BindingTarget = bValue end,
		},
		[5] = {
			type = "dropdown",
			name = "Sync Mode",
			choices = {"Manual", "Automatic"},
			default = "Manual",
			getFunc = function() return KBS.Character.SyncMode end,
			setFunc = function(bValue) KBS.Character.SyncMode = bValue end,
		},
		[6] = {
			type = "button",
			name = "Save Profile",
			tooltip = "Over-write previous profile.",
			func = function() saveBinds(KBS.Character.saveType, KBS.Character.BindingTarget) end,
			width = "half",	--or "half" (optional)
			-- warning = "This will over-write the previous profile.",	--(optional)
		},
		[7] = {
			type = "button",
			name = "Import Profile",
			tooltip = "Import keybinds from Global Profile.",
			func = function() setKeyBinds() end,
			width = "half",	--or "half" (optional)
			-- warning = "Will need to reload the UI.",	--(optional)
		},
		[8] = {
			type = "editbox",
			name = "New Profile",
			-- tooltip = "Save After Entering!",
			getFunc = function() return KBS.Character.BindingTarget end,
			setFunc = function(text) createNewProfile(text)
				KBS.Character.BindingTarget = text
				saveBinds()
				KBSProfiles:UpdateChoices()
				KBSProfilesDel:UpdateChoices()
			end,
			isMultiline = false,	--boolean
			width = "full",	--or "half" (optional)
			warning = "Save After Entering!",	--(optional)
			default = "Crafter",	--(optional)
		},
		[9] = {
			type = "header",
			name = colorYellow.."Deletion",
			width = "full",
		},
		[10] = {
			type = "description",
			text = "Options For Profile Deletion",
		},
		[11] = {
			type = "dropdown",
			name = "Profile",
			choices = KBS.Global.AvailKeyTables,
			sort = "name-up",
			reference = "KBSProfilesDel",
			default = "Main",
			getFunc = function() return KBS.Character.DelTarget end,
			setFunc = function(bValue) KBS.Character.DelTarget = bValue end,
		},
		-- [11] = {
		-- 	type = "dropdown",
		-- 	name = "Profile",
		-- 	choices = KBS.Global.AvailKeyTables,
		-- 	sort = "name-up",
		-- 	default = "Main",
		-- 	reference = "KBSProfilesDel",
		-- 	-- tooltip = "Select a profile for Deletion",
		-- 	getFunc = function() return KBS.Global.AvailKeyTables end,
		-- 	setFunc = function(bValue) KBS.Character.DelTarget = bValue end,
		-- 	-- width = "half",
		-- },
		[12] = {
			type = "button",
			name = "DELETE",
			tooltip = "Delete currently selected profile",
			func = function() removeProfile(KBS.Character.DelTarget)
				if KBS.Character.DelTarget == KBS.Character.BindingTarget then
					KBS.Character.BindingTarget = KBS.Global.AvailKeyTables[1]
				end
				KBS.Character.DelTarget = KBS.Global.AvailKeyTables[1]
				KBSProfiles:UpdateChoices()
				KBSProfilesDel:UpdateChoices()
			end,
			width = "full",	--or "half" (optional)
			-- warning = "Will need to reload the UI.",	--(optional)
		},
	}

	LAM2:RegisterOptionControls("KBS_Options", optionsData)
end


----------------------INITIALIZATION--------------------


function InitializePlugin ()
    if type(KBSMultiAccount) ~= "table" then
    	d("We're populating")
        KBSMultiAccount = KBS.Defaults.Global
        KBS.Global = KBSMultiAccount
    else
        KBS.Global = KBSMultiAccount
    end
	KBS.Character = ZO_SavedVars:New(KBS.SettingsFile, KBS.SAVED_VAR_VERSION, nil, KBS.Defaults.Character, KBS.SVProfile)
	EVENT_MANAGER:UnregisterForEvent("KeyBindSwapper", EVENT_ADD_ON_LOADED)
	if KBS.Character.SyncMode == "Automatic" then
		setKeyBinds()
	end
end


-------------------------LOAD--------------------------

local function OnPluginLoaded(event, addon)
	if addon ~= "KeyBindSwapper" then return end

    -- LoadSettings()
    InitializePlugin() --Create settings variables and unregister for onload
    CreateSettingsMenu() -- LAM2.0

    -- Set Slash Commands
    SLASH_COMMANDS["/loadkeys"] = setKeyBinds
    SLASH_COMMANDS["/importkeys"] = setKeyBinds
    SLASH_COMMANDS["/savekeys"] = saveBinds
    SLASH_COMMANDS["/exportkeys"] = saveBinds
end

EVENT_MANAGER:RegisterForEvent("KeyBindSwapper", EVENT_ADD_ON_LOADED, OnPluginLoaded)