local _version = "0.8-20400"
local tinsert = table.insert
local type, next, pairs, getglobal = type, next, pairs, getglobal
local tostring, tonumber = tostring, tonumber
local format = string.format
local string = string

-- table with all the keys in it.  each key is a table
local _bindings = {}

local _entries = {}

local _layouts = {}
local _defaultLayout

if (not BindingsReminder) then BindingsReminder = {} end
local BindingsReminder = BindingsReminder


-- to hold button stuff
BindingsReminder.bLayout = {}

local permutations = {"SHIFT","CTRL","ALT","ALT-SHIFT","ALT-CTRL","CTRL-SHIFT","ALT-CTRL-SHIFT"}
local function _buildBindingsTable(reset)
	if reset then _bindings = {} end
	local keyTbl
	local action
	for i=1,#BindingsReminder.cLayout do
		local button = BindingsReminder.cLayout[i]
		if (type(button) == "table") then button = button[1] end
		action = GetBindingAction(button)
		if (action and action ~= "") then
			if (not _bindings[button]) then _bindings[button] = {} end
			_bindings[button]['command'] = action
		else
			if _bindings[button] then
				_bindings[button]['command'] = nil
			end
		end
		for j=1,#permutations do
			action = GetBindingAction(permutations[j].."-"..button)
			if (action and action ~= "") then
				if (not _bindings[button]) then _bindings[button] = {} end
				_bindings[button][permutations[j]] = action
			else
				if (_bindings[button]) then
					_bindings[button][permutations[j]] = nil
				end
			end
		end
	end
end

function BindingsReminder.RegisterLayout(name, description, layout, default)
	if default then _defaultLayout = layout end
	tinsert(_layouts, {name, description, layout})
	table.sort(_layouts, function(a, b) return a[1] > b[1] end)
end

function BindingsReminder.DumpBadKeys()
	for button,tbl in pairs(_bindings) do
		local frame = BindingsReminder.bLayout[button]
		if (not frame or #frame < 1) then
			DEFAULT_CHAT_FRAME:AddMessage(string.format("Button not found: |cFFFF0000%s|r",button))
		else
			DEFAULT_CHAT_FRAME:AddMessage(string.format("Button found: |cFF00FF00%s|r",button))
		end
	end
end

function BindingsReminder.Tooltip(f)
	local key = _entries[f]
	local val = GetBindingText(key,"KEY_")
	GameTooltip_SetDefaultAnchor(GameTooltip,UIParent)
	GameTooltip:AddLine(val)
	if (_bindings[key]) then
		GameTooltip:AddLine()
		--GameTooltip:AddLine(string.format("Command: %s",tostring(_bindings[key]['command'])),.85,.85,.85,1)
		for combo,command in pairs(_bindings[key]) do
			local command2 = getglobal("BINDING_NAME_"..command)
			GameTooltip:AddLine(string.format("|cFFFF0000%s|r: %s",tostring(combo),command2 or tostring(command)),.85,.85,.85,1)
		end
	end
	GameTooltip:Show()
end

function BindingsReminder.UpdateTable()
	_buildBindingsTable()
	local frames = _entries
	for frame in pairs(_entries) do
		if (frame and type(frame.UnlockHighlight) == "function") then
			frame:UnlockHighlight()
		end
	end
	for button,tbl in pairs(_bindings) do
		if next(tbl) then
			local frames = BindingsReminder.bLayout[button]
			if (next(frames)) then
				for i=1,#frames do
					if (frames[i] and type(frames[i].LockHighlight) == "function") then frames[i]:LockHighlight() end
				end
			end
		end
	end
end

function BindingsReminder.CreateKeyBoard()
	BindingsReminder.cLayout = _defaultLayout
end

local function _getKey(key)
	if (type(BindingsReminder.cLayout[key]) == "table") then
		return BindingsReminder.cLayout[key][1]
	else
		return BindingsReminder.cLayout[key]
	end
end

local function _getText(key)
	if (type(BindingsReminder.cLayout[key]) == "table") then
		return BindingsReminder.cLayout[key][2]
	else
		return BindingsReminder.cLayout[key]
	end
end

function BindingsReminder.UpdateLayout()
	_bindings = {}
	_entries = {}
	BindingsReminder.bLayout = {}
	for i=1,96 do
		local f = getglobal("BR_"..i)
		BindingsReminder.SetText(f, true)
		BindingsReminder.KeyToKey(f)
	end

end

function BindingsReminder.SetText(f, reset)
	local name = f:GetName()
	local key = string.match(name,"^BR_(.+)$")
	local test = _getKey(tonumber(key))
	if (test) then
		_entries[f] = test
	end
	getglobal(f:GetName().."Text"):SetText(_getText(tonumber(key)))
end

function BindingsReminder.KeyToKey(f)
	local entry = _entries[f]
	if (not BindingsReminder.bLayout[entry]) then BindingsReminder.bLayout[entry] = {} end
	tinsert(BindingsReminder.bLayout[entry],f)
end

function BindingsReminder.DumpBindingsTable()
	_buildBindingsTable()
end

function BindingsReminder.CommandHandler(msg)
	msg = string.lower(msg)
	local tbl = {strsplit(' ', msg)}
	if (msg == "show") then
		-- show the GUI
		BindingsReminderFrame:Show()
	elseif (msg == "hide") then
		-- hide the GUI
		BindingsReminderFrame:Hide()
	elseif (msg == "dumpbad") then
		BindingsReminder.DumpBadKeys()
	--elseif (msg == "help") then
	elseif (msg == "layouts") then
		DEFAULT_CHAT_FRAME:AddMessage("Available layouts:")
		for i=1,#_layouts do
			local name, description = _layouts[i][1], _layouts[i][2]
			DEFAULT_CHAT_FRAME:AddMessage(format("%s: %s", name, description))
		end
	elseif (tbl[1] == "layout") then
		local newLayout = tbl[2]
		for i=1,#_layouts do
			if string.lower(_layouts[i][1]) == newLayout then
				BindingsReminder.cLayout = _layouts[i][3]
			end
		end
		BindingsReminder.UpdateLayout()
		BindingsReminder.UpdateTable()
	else
		DEFAULT_CHAT_FRAME:AddMessage("BindingsReminder v".._version)
		DEFAULT_CHAT_FRAME:AddMessage("show: show the keyboard")
		DEFAULT_CHAT_FRAME:AddMessage("hide: hide the keyboard")
		DEFAULT_CHAT_FRAME:AddMessage("layouts: show the available layouts")
		DEFAULT_CHAT_FRAME:AddMessage("layout <newLayout>: update the keyboard for a new layout")
	end
end

local _found = false
for cmd in pairs(SlashCmdList) do
	local i = 1
	local pre = "SLASH_"..cmd
	local test = getglobal(pre..i)
	while test do
		if (test == "/br") then
			_found = true
			break
		end
		i = i + 1
		test = getglobal(pre..i)
	end
end
SLASH_BINDINGSREMINDER1 = "/bindingsreminder"
if (not _found) then SLASH_BINDINGSREMINDER2 = "/br" end
SlashCmdList["BINDINGSREMINDER"] = BindingsReminder.CommandHandler

local f = CreateFrame("Frame")
local onEvent = function(frame, event, ...)
	local func = BindingsReminder[event]
	if func and type(func) == "function" then
		func(...)
	end
end

local onShow = function(frame)
	BindingsReminder.UpdateTable()
	BindingsReminderFrame:Show()
end

local onHide = function(frame)
	BindingsReminder.UpdateTable()
end

f:SetScript("OnEvent", onEvent)
f:RegisterEvent("ADDON_LOADED")
-- hack to get around myBindings2 set scripting this
GameMenuButtonKeybindings:HookScript("OnClick", onShow)

function BindingsReminder.ADDON_LOADED(addon)
	if addon == "Blizzard_BindingUI" then
		KeyBindingFrame:HookScript("OnShow", onShow)
		KeyBindingFrame:HookScript("OnHide", onHide)
		KeyBindingFrame:HookScript("OnKeyDown", onHide)
	end
end
