local LAM2 = LibStub("LibAddonMenu-2.0")


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

local KBS = {}

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


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.Global.Version = KBS.SAVED_VAR_VERSION
KBS.Defaults.Character = {}
KBS.Defaults.Character.DelTarget = "Main"
KBS.Defaults.Character.saveType = "Global"
KBS.Defaults.Character.BindingTarget = "Main"
KBS.Defaults.Character.SyncMode = "Manual"
KBS.Defaults.Account = {}
KBS.Defaults.Account.SingleTarget = false
KBS.Defaults.Account.BindingTarget = "Main"
KBS.Defaults.Account.AutoSync = false


---------------------------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 throw error
	-- Used By:		Import Profile button, /setkeys
]]
function setKeyBinds(profile)
	local isSafe = false
	if profile then
		for i=1, #KBS.Global.AvailKeyTables do
			if KBS.Global.AvailKeyTables[i] == profile then
				isSafe = true
			end
		end
	elseif KBS.Account.SingleTarget then
		for i=1, #KBS.Global.AvailKeyTables do
			if KBS.Global.AvailKeyTables[i] == KBS.Account.BindingTarget then
				profile = KBS.Account.BindingTarget
				d("Loading Profile: "..profile)
				isSafe = true
			end
		end
	else
		for i=1, #KBS.Global.AvailKeyTables do
			if KBS.Global.AvailKeyTables[i] == KBS.Character.BindingTarget then
				profile = KBS.Character.BindingTarget
				d("Loading Profile: "..profile)
				isSafe = true
			end
		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 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)
								else
									BindKeyToAction(layer,cat,action,index,keycode,keymod1,keymod2,keymod3,keymod4)
								end
							else
								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
		d("KBS: Loaded profile: "..profile)
	else
		d("Error: Profile '"..profile.."' Not found!")
	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(profile)
	if profile then
		getKeyBinds(KBS.Global.KeyTables[profile])
	elseif KBS.Account.SingleTarget == true then
		getKeyBinds(KBS.Global.KeyTables[KBS.Account.BindingTarget])
		profile = KBS.Account.BindingTarget
	else
		getKeyBinds(KBS.Global.KeyTables[KBS.Character.BindingTarget])
		profile = KBS.Character.BindingTarget
	end
	d("KBS: Saved to profile: "..profile)
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] = {}
		d("KBS: Created new profile: "..name)
	end
end

function getProfile()
	if KBS.Account.SingleTarget == true then
		return KBS.Account.BindingTarget
	else
		return KBS.Character.BindingTarget
	end
end

function setProfile(value)
	profile = getProfile()
	profile = value
end

function setBindingTarget(target)
	if KBS.Account.SingleTarget == true then
		KBS.Account.BindingTarget = target
	else
		KBS.Character.BindingTarget = target
	end
	d("KBS: Set active profile to '"..target.."'")
end

-- function getBindingTarget()
-- 	if KBS.Account.SingleTarget then
-- 		return KBS.Account.BindingTarget
-- 	else
-- 		return KBS.Character.BindingTarget
-- 	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.",
		},
		-- [3] = {
		-- 	type = "dropdown",
		-- 	name = "Save Type",
		-- 	choices = {"Global", "Account"},
		-- 	default = "Global",
		-- 	getFunc = function() return KBS.Character.saveType end,
		-- 	setFunc = function(bValue) KBS.Character.saveType = bValue end,
		-- },
		[3] = {
			type = "checkbox",
			name = "Single Target Mode",
			tooltip = "This sets an entire account to sync to one profile.",
			getFunc = function() return KBS.Account.SingleTarget end,
			setFunc = function(value) KBS.Account.SingleTarget = value end,
			width = "full",	--or "half" (optional)
			-- disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
			-- warning = "Will need to reload the UI.",	--(optional)
			default = KBS.Defaults.Account.SingleTarget,	--(optional)
			reference = "MyAddonCheckbox"	--(optional) unique global reference to control
		},
		[4] = {
			type = "dropdown",
			name = "Profile",
			choices = KBS.Global.AvailKeyTables,
			tooltip = "Profile to load/save to",
			sort = "name-up",
			reference = "KBSProfiles",
			default = "Main",
			getFunc = function() profile = getProfile() return profile end,
			setFunc = function(bValue) setBindingTarget(bValue) end,
			 -- KBS.Character.BindingTarget = bValue end,
		},
		[5] = {
			type = "checkbox",
			name = "AccountWide auto-sync",
			tooltip = "This sets an entire account to sync to one profile.",
			getFunc = function() return KBS.Account.AutoSync end,
			setFunc = function(value) KBS.Account.AutoSync = value end,
			width = "full",	--or "half" (optional)
			-- disabled = function() return db.someBooleanSetting end,	--or boolean (optional)
			-- warning = "Will need to reload the UI.",	--(optional)
			default = KBS.Defaults.Account.AutoSync,	--(optional)
		},
		[6] = {
			type = "button",
			name = "Save Profile",
			tooltip = "Over-write previous profile.",
			func = function() saveBinds(getProfile()) 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() profile = getProfile() return profile end,
			setFunc = function(text) createNewProfile(text)
				setBindingTarget(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
				if KBS.Character.DelTarget == KBS.Account.BindingTarget then
					KBS.Account.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
	elseif KBSMultiAccount.Version ~= KBS.SAVED_VAR_VERSION then
		KBSMultiAccount = {}
		KBSMultiAccount = KBS.Defaults.Global
		KBS.Global = KBSMultiAccount
    else
        KBS.Global = KBSMultiAccount
    end
	KBS.Account = ZO_SavedVars:NewAccountWide(KBS.SettingsFile, KBS.SAVED_VAR_VERSION, nil, KBS.Defaults.Account, KBS.SVProfile)
	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)
	local profile = getProfile()
	if type(KBS.Global.KeyTables[profile].BindTable) ~= "table" then
		saveBinds()
		d("KBS: First start on fresh data!")
	end
	if KBS.Account.SingleTarget == true then
		if KBS.Account.AutoSync == true then
			setKeyBinds(KBS.Account.BindingTarget)
		end
	elseif 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)