
-- Old mappings now deprecated. Left here to support addons already using them,
-- but these will be removed in the future, so update to the new format.
MYBINDINGS_CATEGORY_BARS			= "bars"
MYBINDINGS_CATEGORY_CHAT			= "chat"
MYBINDINGS_CATEGORY_CLASS			= "class"
MYBINDINGS_CATEGORY_COMBAT			= "combat"
MYBINDINGS_CATEGORY_COMPILATIONS	= "compilations"
MYBINDINGS_CATEGORY_INTERFACE		= "interface"
MYBINDINGS_CATEGORY_INVENTORY		= "inventory"
MYBINDINGS_CATEGORY_MAP				= "map"
MYBINDINGS_CATEGORY_OTHERS			= "others"
MYBINDINGS_CATEGORY_PROFESSIONS		= "professions"
MYBINDINGS_CATEGORY_QUESTS			= "quests"
MYBINDINGS_CATEGORY_RAID			= "raid"

-- Key binding to open up the myBindings window.
BINDING_HEADER_MYBINDINGS		= MYBINDINGS_NAME
BINDING_CATEGORY_MYBINDINGS		= "interface"
BINDING_NAME_MYBINDINGS_OPEN	= MYBINDINGS_KEYBIND_OPEN


--[[--------------------------------------------------------------------------
  Class Definition
-----------------------------------------------------------------------------]]

myBindings = AceAddonClass:new({
	name				 = MYBINDINGS_NAME,
	description			 = MYBINDINGS_DESCRIPTION,
	category			 = BINDING_CATEGORY_MYBINDINGS,
	optionsFrame		 = "myBindingsOptionsFrame",
	version				 = "1.3",
	releaseDate			 = "10-11-2005",
	author				 = "Turan",
	email				 = "turan@wowace.com",
	website				 = "http://www.wowace.com",
	aceCompatible		 = "100",
	db					 = AceDbClass:new("myBindingsDB"),
	cmd					 = AceChatCmdClass:new(MYBINDINGS_COMMANDS, MYBINDINGS_CMD_OPTIONS),

	maxMenuLines		 = 18,
	maxMenuLineHeight	 = 22,
	maxBindingLines		 = 17,
	maxBindingLineHeight = 25,

	categoriesSort		 = {
		MYBINDINGS_CATEGORY_GAME,
		ACE_CATEGORY_BARS,
		ACE_CATEGORY_CHAT,
		ACE_CATEGORY_CLASS,
		ACE_CATEGORY_COMBAT,
		ACE_CATEGORY_COMPILATIONS,
		ACE_CATEGORY_INTERFACE,
		ACE_CATEGORY_INVENTORY,
		ACE_CATEGORY_MAP,
		ACE_CATEGORY_OTHERS,
		ACE_CATEGORY_PROFESSIONS,
		ACE_CATEGORY_QUESTS,
		ACE_CATEGORY_RAID
	},
	gameBindings		 = {},
	currentMenuSelection = nil,
	confirmKeyBind		 = nil
})
myBindings:RegisterForLoad()

function myBindings:Initialize()
	if( myBindings_LoadCategories ) then myBindings_LoadCategories() end

	self.Msg	= function(...) self.cmd:result(format(unpack(arg))) end
	self.Error  = function(...) self.cmd:result(ACEG_LABEL_ERROR, " ", format(unpack(arg))) end

	self.savedKeyBindingFrame = KeyBindingFrame
	self.frame = myBindingsOptionsFrame
	self.currentProfile = self.profilePath[2]
end

-- Data Management

function myBindings:GetBind(val)
	if( not val ) then
		return self.db:get(self.profilePath, "bindings")
	else
		return self.db:get({self.profilePath, "bindings"}, val)
	end
end
function myBindings:SetBind(var, val)
	self.db:set({self.profilePath, "bindings"}, var, val)
end
function myBindings:ClearBinds()
	self.db:set(self.profilePath, "bindings")
end

function myBindings:GetCat(var)
	return self.db:get({"categories"}, var)
end
function myBindings:SetCat(var, val)
	self.db:set({"categories"}, var, val)
end

--

function myBindings:Enable()
	-- Override the existing key bindings dialog so that myBindingsOptionsFrame will
	-- get called just like any other UIPanel frame.
	KeyBindingFrame = myBindingsOptionsFrame
	GameMenuButtonKeybindings:Hide()
	myBindingsGameMenuButton:Show()

	self:RegisterEvent("ACE_PROFILE_LOADED")

	self:SetGameBindings()
	self:ParseBindings()
	self:LoadBindings(GetCurrentBindingSet())
	self:UpdateLoadedLabel()

	UIPanelWindows[self.optionsFrame] = {area = "center", pushable = 0}
	self.frame.selected   = nil
end

function myBindings:Disable()
	KeyBindingFrame = self.savedKeyBindingFrame
	GameMenuButtonKeybindings:Show()
	myBindingsGameMenuButton:Hide()
end

function myBindings:ACE_PROFILE_LOADED()
	if( self.profilePath[2] == self.currentProfile ) then return end
	self.currentProfile = self.profilePath[2]
	self:LoadBindings(GetCurrentBindingSet())
	self:UpdateLoadedLabel()
end


--[[--------------------------------------------------------------------------
  Initialize Bindings List
-----------------------------------------------------------------------------]]

function myBindings:SetGameBindings()
	-- This is just a reference list to check later which bindings are part of the
	-- standard game controls.
	self.gameBindings[BINDING_HEADER_ACTIONBAR]		 = 1
	self.gameBindings[BINDING_HEADER_CAMERA]		 = 1
	self.gameBindings[BINDING_HEADER_CHAT]			 = 1
	self.gameBindings[BINDING_HEADER_INTERFACE]		 = 1
	self.gameBindings[BINDING_HEADER_MISC]			 = 1
	self.gameBindings[BINDING_HEADER_MOVEMENT]		 = 1
	self.gameBindings[BINDING_HEADER_TARGETING]		 = 1
	self.gameBindings[BINDING_HEADER_MULTIACTIONBAR] = 1
	self.gameBindings[BINDING_HEADER_BLANK]			 = 1
	self.gameBindings[BINDING_HEADER_BLANK2]		 = 1
	self.gameBindings[BINDING_HEADER_BLANK3]		 = 1
end

function myBindings:ParseBindings()
	local categories  = {}
	local commandName, binding1, binding2, header, addOnCat

	self.menuHeaders		= {}
	self.bindingIndexes		= {}
	self.expandedCategories	= {}

	for index = 1, GetNumBindings(), 1 do
		commandName, binding1, binding2 = GetBinding(index)

		if( strsub(commandName, 1, 6) == "HEADER" ) then
			header = getglobal("BINDING_"..commandName)
			if( (header or "") == "" ) then header = strsub(commandName, 8) end

			self.bindingIndexes[header] = {}

			-- Add to appropriate category
			if( self.gameBindings[header] ) then
				if( not categories[MYBINDINGS_CATEGORY_GAME] ) then
					categories[MYBINDINGS_CATEGORY_GAME] = {}
				end
				table.insert(categories[MYBINDINGS_CATEGORY_GAME], header)
			else
				addOnCat = getglobal(
					"ACE_CATEGORY_"..
					strupper(
						self:GetCat(strsub(commandName, 8)) or
						getglobal("BINDING_CATEGORY_"..strsub(commandName, 8)) or
						"others"
					)
				) or ACE_CATEGORY_OTHERS
				if( not categories[addOnCat] ) then categories[addOnCat] = {} end
				table.insert(categories[addOnCat], header)
			end
		elseif( header ) then
			-- Need to save the index so it can be used later to reference this command
			-- in the API's bindings list.
			table.insert(self.bindingIndexes[header], index)
		end
	end

	-- Now place all the sorted categories and headers into one list for easy
	-- display later on.
	for index, category in self.categoriesSort do
		if( categories[category] ) then
			table.sort(categories[category])
			table.insert(self.menuHeaders, {text=category, isCategory=TRUE})
			for i, header in categories[category] do
				table.insert(self.menuHeaders, {text=header, category=category})
			end
		end
	end
end


--[[--------------------------------------------------------------------------
  Dialog Handling Methods
-----------------------------------------------------------------------------]]

function myBindings:HeadingsUpdate()
	local numHeaders = table.getn(self.menuHeaders)
	local offset	 = FauxScrollFrame_GetOffset(myBindingsOptionsHeadingsScrollFrame)
	local hdrinx	 = 0
	local visible	 = 0
	local line		 = 0
	local header, menuItem, button

	-- In case we were waiting for a key bind confirmation, cancel it.
	self:CancelKeyBind()

	-- Browse the lines
	while ( line < self.maxMenuLines ) do
		if( ((offset + line) <= numHeaders) and (hdrinx < numHeaders) ) then
			hdrinx	= hdrinx + 1
			header = self.menuHeaders[hdrinx]

			if( header.isCategory ) then
				visible = visible + 1
				if( visible > offset ) then
					line = line + 1
					getglobal("myBindingsOptionsBindCategory"..line.."NormalText"):SetText(header.text)
--					getglobal("myBindingsOptionsBindCategory"..line.."HighlightText"):SetText(header.text)
					getglobal("myBindingsOptionsBindCategory"..line):Show()
					getglobal("myBindingsOptionsBindHeader"..line):Hide()
				end
			elseif( self.expandedCategories[header.category] ) then
				visible = visible + 1
				if( visible > offset ) then
					line	   = line + 1
					menuItem   = getglobal("myBindingsOptionsBindHeader"..line)
					button	   = getglobal("myBindingsOptionsBindHeader"..line.."Button")

					getglobal("myBindingsOptionsBindHeader"..line.."ButtonNormalText"):SetText(header.text)
--					getglobal("myBindingsOptionsBindHeader"..line.."ButtonHighlightText"):SetText(header.text)
					getglobal("myBindingsOptionsBindCategory"..line):Hide()
					menuItem:Show()

					if( self.currentMenuSelection == header.text ) then
						myBindingsOptionsFrameBindingsTitle:SetText(header.text)
						menuItem:SetBackdropBorderColor(.9, .9, 0)
						menuItem:SetBackdropColor(1.0, 1.0, 0.5)
						button:LockHighlight()
					else
						menuItem:SetBackdropBorderColor(0.4, 0.4, 0.4)
						menuItem:SetBackdropColor(0.15, 0.15, 0.15)
						button:UnlockHighlight()
					end

					self.frame.highlightID = self.frame:GetParent():GetID()
				end
			end
		else
			line = line + 1
			getglobal("myBindingsOptionsBindCategory"..line):Hide()
			getglobal("myBindingsOptionsBindHeader"..line):Hide()
		end
	end

	FauxScrollFrame_Update(myBindingsOptionsHeadingsScrollFrame,
						   self:GetMenuNumVisible(),
						   self.maxMenuLines,
						   self.maxMenuLineHeight
						   )
end

function myBindings:ExpandCollapseHeadings(val)
	for index, header in self.menuHeaders do
		if( header.isCategory ) then
			self.expandedCategories[header.text] = val
		end
	end
end

function myBindings:GetMenuNumVisible()
	local numVisible = 0

	for index = 1, table.getn(self.menuHeaders), 1 do
		if( self.menuHeaders[index].isCategory ) then
			numVisible = numVisible + 1
		elseif( self.expandedCategories[self.menuHeaders[index].category] ) then
			numVisible = numVisible + 1
		end
	end

	return numVisible
end

function myBindings:CategoryOnClick(text)
	self.expandedCategories[text] = (not self.expandedCategories[text])
	self:HeadingsUpdate()
end

function myBindings:HeaderOnClick()
	self.currentMenuSelection = this:GetText()
	self:HeadingsUpdate()
	self:BindingsUpdate()
end


--[[--------------------------------------------------------------------------
  Bindings ScrollFrame Methods
-----------------------------------------------------------------------------]]

-- Copied from Blizzard's UI as a temporary fix for game patch 1800. Since the
-- default key binding frame is no longer loaded at start, this function is
-- not available if the default key bind frame is never opened, which it probably
-- never is if someone is using myBindings. 10/11/2005
function KeyBindingFrame_GetLocalizedName(name, prefix)
	if ( not name ) then
		return "";
	end
	local tempName = name;
	local i = strfind(name, "-");
	local dashIndex = nil;
	while ( i ) do
		if ( not dashIndex ) then
			dashIndex = i;
		else
			dashIndex = dashIndex + i;
		end
		tempName = strsub(tempName, i + 1);
		i = strfind(tempName, "-");
	end

	local modKeys = '';
	if ( not dashIndex ) then
		dashIndex = 0;
	else
		modKeys = strsub(name, 1, dashIndex);
		if ( GetLocale() == "deDE") then
			modKeys = gsub(modKeys, "CTRL", "STRG");
		end
	end

	local variablePrefix = prefix;
	if ( not variablePrefix ) then
		variablePrefix = "";
	end
	local localizedName = nil;
	if ( IsMacClient() ) then
		-- see if there is a mac specific name for the key
		localizedName = getglobal(variablePrefix..tempName.."_MAC");
	end
	if ( not localizedName ) then
		localizedName = getglobal(variablePrefix..tempName);
	end
	if ( not localizedName ) then
		localizedName = tempName;
	end
	return modKeys..localizedName;
end

function myBindings:BindingsUpdate()
	local header		= self.currentMenuSelection
	local indexes		= self.bindingIndexes[header]
	local scrollOffset	= FauxScrollFrame_GetOffset(myBindingsOptionsBindingsScrollFrame)
	local bindLine, commandName, numCommands, keyOffset
	local keyBindingButton1, keyBindingButton1NormalTexture, keyBindingButton1PushedTexture,
		  keyBindingButton2, keyBindingButton2NormalTexture, keyBindingButton2PushedTexture,
		  keyBindingDescription

	-- In case we were waiting for a key bind confirmation, cancel it.
	if( not myBindingsOptionsBindingsScrollFrame.buttonPressed ) then
		self:CancelKeyBind()
	end

	if( indexes ) then
		numCommands = table.getn(indexes)
	else
		numCommands = 0
	end

	-- Browse the lines
	for line = 1, self.maxBindingLines, 1 do
		keyOffset		  = scrollOffset + line
		keyBindingButton1 = getglobal("myBindingsOptionsBindingLine"..line.."Key1Button")
		keyBindingButton2 = getglobal("myBindingsOptionsBindingLine"..line.."Key2Button")

		if( keyOffset <= numCommands ) then
			bindLine	= getglobal("myBindingsOptionsBindingLine"..line)
			commandName, binding1, binding2 = GetBinding(self.bindingIndexes[header][keyOffset])

			keyBindingButton1NormalTexture = getglobal("myBindingsOptionsBindingLine"..line.."Key1ButtonNormalTexture")
			keyBindingButton1PushedTexture = getglobal("myBindingsOptionsBindingLine"..line.."Key1ButtonPushedTexture")
			keyBindingButton2NormalTexture = getglobal("myBindingsOptionsBindingLine"..line.."Key2ButtonNormalTexture")
			keyBindingButton2PushedTexture = getglobal("myBindingsOptionsBindingLine"..line.."Key2ButtonPushedTexture")
			keyBindingLabel				   = getglobal("myBindingsOptionsBindingLine"..line.."Label")

			keyBindingLabel:SetText(KeyBindingFrame_GetLocalizedName(commandName, "BINDING_NAME_"))

			if( binding1 ) then
				keyBindingButton1:SetText(
								KeyBindingFrame_GetLocalizedName(binding1, "KEY_")
								)
				keyBindingButton1:SetAlpha(1)
			else
				keyBindingButton1:SetText(NORMAL_FONT_COLOR_CODE..NOT_BOUND..FONT_COLOR_CODE_CLOSE)
				keyBindingButton1:SetAlpha(0.8)
			end

			if( binding2 ) then
				keyBindingButton2:SetText(
								KeyBindingFrame_GetLocalizedName(binding2, "KEY_")
								)
				keyBindingButton2:SetAlpha(1)
			else
				keyBindingButton2:SetText(NORMAL_FONT_COLOR_CODE..NOT_BOUND..FONT_COLOR_CODE_CLOSE)
				keyBindingButton2:SetAlpha(0.8)
			end

			if( myBindingsOptionsBindingsScrollFrame.selected == commandName ) then
				if( myBindingsOptionsBindingsScrollFrame.keyID == 1 ) then
					keyBindingButton1:LockHighlight()
					keyBindingButton2:UnlockHighlight()
				else
					keyBindingButton2:LockHighlight()
					keyBindingButton1:UnlockHighlight()
				end
			else
				keyBindingButton1:UnlockHighlight()
				keyBindingButton2:UnlockHighlight()
			end

			keyBindingButton1.commandName = commandName
			keyBindingButton2.commandName = commandName

			bindLine:Show()
		else
			keyBindingButton1.commandName = nil
			keyBindingButton2.commandName = nil
			getglobal("myBindingsOptionsBindingLine"..line):Hide()
		end
	end

	FauxScrollFrame_Update(myBindingsOptionsBindingsScrollFrame,
						   numCommands,
						   self.maxBindingLines,
						   self.maxBindingLineHeight
						   )
end

function myBindings:DeselectButton()
	myBindingsOptionsFrameOutputText:SetText("")
	myBindingsOptionsBindingsScrollFrame.selected	   = nil
	myBindingsOptionsBindingsScrollFrame.buttonPressed = nil
	myBindingsOptionsBindingsScrollFrame.keyID		   = nil
	self:BindingsUpdate()
end

function myBindings:BindingOnClick(button)
	if( myBindingsOptionsBindingsScrollFrame.buttonPressed == this ) then
		-- Code to be able to deselect or select another key to bind
		if( button == "LeftButton" or button == "RightButton" ) then
			-- Deselect button if it was the pressed previously pressed
			self:DeselectButton()
		else
			self:OnKeyDown(button)
		end
	else
		myBindingsOptionsFrameUnbindButton:Enable()
		myBindingsOptionsBindingsScrollFrame.selected	   = this.commandName
		myBindingsOptionsBindingsScrollFrame.buttonPressed = this
		myBindingsOptionsBindingsScrollFrame.keyID		   = this:GetID()
		myBindingsOptionsFrameOutputText:SetText(
			format(BIND_KEY_TO_COMMAND,
				   KeyBindingFrame_GetLocalizedName(this.commandName, "BINDING_NAME_")
				   )
			)
		self:BindingsUpdate()
	end
end

function myBindings:OnKeyDown(button)
	if( arg1 == "PRINTSCREEN" ) then
		Screenshot()
		return
	end

	-- Convert the mouse button names
	if( button == "LeftButton" ) then
		button = "BUTTON1"
	elseif( button == "RightButton" ) then
		button = "BUTTON2"
	elseif( button == "MiddleButton" ) then
		button = "BUTTON3"
	elseif( button == "Button4" ) then
		button = "BUTTON4"
	elseif( button == "Button5" ) then
		button = "BUTTON5"
	end

	if( myBindingsOptionsBindingsScrollFrame.selected ) then
		local keyPressed = arg1

		if( button ) then
			if( button == "BUTTON1" or button == "BUTTON2" ) then
				return
			end
			keyPressed = button
		else
			keyPressed = arg1
		end

		if( keyPressed == "UNKNOWN" ) then
			return
		end
		if( keyPressed == "SHIFT" or keyPressed == "CTRL" or keyPressed == "ALT") then
			return
		end
		if( IsShiftKeyDown() ) then
			keyPressed = "SHIFT-"..keyPressed
		end
		if( IsControlKeyDown() ) then
			keyPressed = "CTRL-"..keyPressed
		end
		if( IsAltKeyDown() ) then
			keyPressed = "ALT-"..keyPressed
		end

		local oldAction = GetBindingAction(keyPressed)
		if( (oldAction ~= "") and (oldAction ~= myBindingsOptionsBindingsScrollFrame.selected) ) then
			local key1, key2 = GetBindingKey(oldAction)
			if( (not key1 or key1 == keyPressed) and ((not key2) or (key2 == keyPressed)) ) then
				--Error message
				myBindingsOptionsFrameOutputText:SetText(
					format(MYBINDINGS_BOUND_ERROR,
						   keyPressed,
						   KeyBindingFrame_GetLocalizedName(oldAction, "BINDING_NAME_")
						   )
					)
				self.confirmKeyBind = TRUE
			end
		end

		if( self.confirmKeyBind ) then
			myBindingsOptionsFrameConfirmBindButton:Show()
			myBindingsOptionsFrameConfirmBindButton.keyPressed = keyPressed
			myBindingsOptionsFrameCancelBindButton:Show()
		else
			self:BindKey(keyPressed)
		end
	else
		if( arg1 == "ESCAPE" ) then
			LoadBindings(GetCurrentBindingSet())
			myBindingsOptionsFrameOutputText:SetText("")
			myBindingsOptionsBindingsScrollFrame.selected = nil
			HideUIPanel(this)
		end
	end
end

function myBindings:BindKey(keyPressed)
	local key1, key2 = GetBindingKey(myBindingsOptionsBindingsScrollFrame.selected)

	if( key1 ) then SetBinding(key1); end
	if( key2 ) then SetBinding(key2); end

	if( myBindingsOptionsBindingsScrollFrame.keyID == 1 ) then
		self:SetBinding(keyPressed, myBindingsOptionsBindingsScrollFrame.selected, key1)
		if( key2 ) then
			SetBinding(key2, myBindingsOptionsBindingsScrollFrame.selected)
		end
	else
		if( key1 ) then
			self:SetBinding(key1, myBindingsOptionsBindingsScrollFrame.selected)
		end
		self:SetBinding(keyPressed, myBindingsOptionsBindingsScrollFrame.selected, key2)
	end

	myBindingsOptionsBindingsScrollFrame.selected	   = nil
	myBindingsOptionsBindingsScrollFrame.buttonPressed = nil
	self:BindingsUpdate()
	myBindingsOptionsFrameOutputText:SetText(KEY_BOUND)
end

function myBindings:SetBinding(key, selectedBinding, oldKey)
	if( SetBinding(key, selectedBinding) ) then
		return
	else
		if( oldKey ) then
			SetBinding(oldKey, selectedBinding)
		end
		--Error message
		myBindingsOptionsFrameOutputText:SetText(
			"Can't bind mousewheel to actions with up and down states"
			)
	end
end

function myBindings:ConfirmKeyBind()
	self:BindKey(this.keyPressed)
end

function myBindings:CancelKeyBind()
	self.confirmKeyBind = FALSE

	-- Button highlighting stuff
	myBindingsOptionsBindingsScrollFrame.selected = nil
	if( myBindingsOptionsBindingsScrollFrame.buttonPressed ) then
		myBindingsOptionsBindingsScrollFrame.buttonPressed:UnlockHighlight()
		myBindingsOptionsBindingsScrollFrame.buttonPressed = nil
	end

	myBindingsOptionsFrameConfirmBindButton:Hide()
	myBindingsOptionsFrameConfirmBindButton.keyPressed = nil
	myBindingsOptionsFrameCancelBindButton:Hide()
	myBindingsOptionsFrameUnbindButton:Disable()
	myBindingsOptionsFrameOutputText:SetText("")
end

function myBindings:UnbindKey()
	if( not myBindingsOptionsBindingsScrollFrame.selected ) then return end

	local key1, key2 = GetBindingKey(myBindingsOptionsBindingsScrollFrame.selected)

	if( myBindingsOptionsBindingsScrollFrame.keyID == 1 ) then
		if( key1 ) then SetBinding(key1) end
		if( key2 ) then
			SetBinding(key2, myBindingsOptionsBindingsScrollFrame.selected)
		end
	elseif( key2 ) then SetBinding(key2)
	end

	self:CancelKeyBind()
	self:BindingsUpdate()
end


--[[--------------------------------------------------------------------------
  Binding Methods
-----------------------------------------------------------------------------]]

function myBindings:LoadGameDefaultBindings()
	LoadBindings(DEFAULT_BINDINGS)
	self:BindingsUpdate()
end

function myBindings:LoadBindings()
	-- If there's no binding set in the current profile, don't do anything or this
	-- will wipe out all settings, leaving mouse-control of the game only.
	if( not self:GetBind() ) then return end

	local commandName, binding1, binding2, command

	for index = 1, GetNumBindings(), 1 do
		commandName, binding1, binding2 = GetBinding(index)

		-- I don't know why, but if the bindings aren't first erased, then attempting
		-- to overwrite the values from the stored values will wipe out all the second
		-- key bindings. They need clearing anyway in case the stored binding set
		-- doesn't have values, meaning these bindings should be empty.
		if( binding1 ) then SetBinding(binding1) end
		if( binding2 ) then SetBinding(binding2) end

		command = self:GetBind(commandName)
		if( command ) then
			if( command.bind1 ) then SetBinding(command.bind1, commandName, binding1) end
			if( command.bind2 ) then SetBinding(command.bind2, commandName, binding2) end
		end
	end

	SaveBindings(GetCurrentBindingSet())
	self:BindingsUpdate()
end

function myBindings:SaveBindings()
	-- Save the bindings in the system first.
	SaveBindings(GetCurrentBindingSet())

	local commandName, binding1, binding2

	-- Empty the stored bindings first.
	self:ClearBinds()

	for index = 1, GetNumBindings(), 1 do
		commandName, binding1, binding2 = GetBinding(index)
		local key1, key2 = GetBindingKey(commandName)
		-- Don't save empty bindings
		if( binding1 or binding2 ) then
			self:SetBind(commandName, {bind1 = binding1, bind2 = binding2})
		end
	end

	self:CloseInterface()
end


--[[--------------------------------------------------------------------------
  Display Methods
-----------------------------------------------------------------------------]]

function myBindings:UpdateLoadedLabel()
	myBindingsOptionsFrameBindingsLoadedLabel:SetText(
		format(MYBINDINGS_LABEL_BINDINGS_LOADED, self.profilePath[2])
	)
end

function myBindings:OpenInterface()
	if( self.disabled ) then return; end

	if( not self.frame:IsVisible() ) then
		ShowUIPanel(self.frame)
		self.dontOpenGameMenu = TRUE
		self:HeadingsUpdate()
		self:BindingsUpdate()
	end
end

function myBindings:CloseInterface()
	myBindingsOptionsBindingsScrollFrame.selected = nil
	HideUIPanel(self.frame)
end

function myBindings:OnShow()
	self:HeadingsUpdate()
	self:BindingsUpdate()
end

function myBindings:OnHide()
	self:CancelKeyBind()

	-- Check if it's currently showing an options frame or the myAddOns options frame.
	if( (not MYADDONS_ACTIVE_OPTIONSFRAME) and
		 (not self.dontOpenGameMenu) and
		 ( (not myAddOnsFrame) or (not myAddOnsFrame:IsVisible())) ) then
		ShowUIPanel(GameMenuFrame)
				-- Check if the options frame was opened by myAddOns
	elseif( MYADDONS_ACTIVE_OPTIONSFRAME == this ) then
		ShowUIPanel(myAddOnsFrame)
	end

	self.dontOpenGameMenu = FALSE
end

--[[--------------------------------------------------------------------------
  Chat Handlers
-----------------------------------------------------------------------------]]

function myBindings:SetCategory(opt)
	local header, cat = unpack(ace.ParseWords(opt))

	if( (not header) or (not cat) ) then
		self.Error(MYBINDINGS_TEXT_INVALID_ENTRY)
		return
	elseif( not getglobal("ACE_CATEGORY_"..strupper(cat)) ) then
		self.Error(MYBINDINGS_TEXT_CAT_INVALID, cat)
		return
	end

	local try, valid = getglobal("BINDING_HEADER_"..header)
	if( try ) then
		valid = header
	else
		try = getglobal("BINDING_HEADER_"..strlower(header))
		if( try ) then
			valid = strlower(header)
		else
			try = getglobal("BINDING_HEADER_"..strupper(header))
			if( try ) then
				valid = strupper(header)
			else
				self.Error(MYBINDINGS_TEXT_HDR_INVALID, header)
				return
			end
		end
	end

	self:SetCat(valid, cat)
	self:ParseBindings()
	self.Msg(MYBINDINGS_TEXT_CAT_SET, valid, getglobal("ACE_CATEGORY_"..strupper(cat)))
end

function myBindings:SetBindOpt(opt)
	local oldaction = nil
	local key, action = unpack(ace.ParseWords(opt))
	key = string.upper(key)
	-- Attempt to clear the binding. If this is an invalid key, it'll fail.
	oldaction = GetBindingAction( key )
	if not SetBinding(key, nil) then
		if not SetBinding(key, oldaction) then
			self.cmd:msg( "Error - " .. key .. " is not a valid key!" )
		end
	elseif action then
		if SetBinding(key, action) then
			self.cmd:msg( "Key " .. key .. " successfully bound to action " .. action .. ".")
		else
			self.cmd:msg( "Action " .. action .. " is not valid!" )
			SetBinding(key, oldaction)
		end
	else
		self.cmd:msg( "Key " .. key .. " cleared." )
	end
end
