---
-- AutoBar
-- Copyright 2004, 2005, 2006 original author.
-- New Stuff Copyright 2006 Toadkiller of Proudmoore.

-- Configurable set of 24 buttons that seeks out configured items
-- in your pack for use. Intended primarily for consumables. Not
-- for use with spells, skills, trinkets, or powers.
--
-- Maintained by Azethoth / Toadkiller of Proudmoore.  Original author Saien of Hyjal
-- http://www.wowace.com/wiki/AutoBar
-- http://www.curse-gaming.com/en/wow/addons-4430-1-autobar-toadkiller.html

-- Coming Attractions:
-- Set operations / calculated categories.
-- Multible bars or individually draggable buttons?
-- Exchange profiles
-- Hide Microbuttons option
-- Indication of when an object being edited is obscured by a higher layer.
-- Named Custom Categories, Named button ranges.
-- Inventory & Instance checks
-- Buff detection: Don't show buff items if buffed already
-- Equipped Slot itmes.
-- Crafting slots
-- Spell Slots
-- Full Mount support, including spell mounts and stance switching

-- Next Up:
-- ItemClasses-2.0, UseItem-2.0, CursorItem-2.0, Tablet-2.0, AceDB
-- Bartender support?
-- Named Slots
-- Dragging from bag straight to bar.
-- Fix Unbind Key

-- 2.00.00.11 beta
-- Espanol or something!  Tx shiftos!
-- Fixed illegal use of Show();
-- Right Click self targets
-- Removed obsolete option to disable popups
-- Popup on shift is broken for now

-- 2.00.00.10 beta
-- Just fixing externals for ace

-- 2.00.00.09 beta
-- Switch to PeriodicTable-2.0
-- mana & hp thresholds now based on PT so wont get out of sync again
-- Set header framestrata to DIALOG so popups dont popunder
-- Booze category added.  Temporary until buffs are overhauled.
-- HideTooltips checkbox works again
-- Docking adjusted a bit but not completely redone yet
-- Add ItemId to tooltip so missing items can be reported easily!

-- 2.00.00.08 beta
-- Reduced the key bindings in Blizzards Keybind UI to only the config toggle.
-- Added basic Tooltip support.
-- Update bar after binding changes

-- 2.00.00.07 beta
-- Alt self target support added
-- Close & disable config during combat
-- Cooldown support added
-- Hotkey display support added to bar buttons

-- 2.00.00.06 beta
-- Fixed lib path issue

-- 2.00.00.05 beta
-- Left & Right clicking a button fixed.  Should target offhand weapon for right click once more.
-- Fixed at least one instance of the itemCount error.
-- Draghandle can be hidden once more
-- First cut at fixing docking.  It works & is tested only for the chat frame.  Offsets still need adjusting and new anchor frames used or hilarity does ensue.
-- More keybinding progress.  Now saves for single & shared profile.

-- 2.00.00.04 beta
-- Unbind button now actually unbinds key binding
-- Revert button will now revert key binds made since the last time done or revert was pressed or the mod loaded. Escaping out of config neither reverts nor commits.

-- 2.00.00.03
-- Fixed popups
-- Quest category added.  Slot 24 for non-rogues.
-- Disable health & mana change updates.  No point since we can't change items during combat anymore & out of combat you can just eat something.
-- First cut at Key binding tab.  Mostly works, left click to set left mouse button binding, right click to set right mouse button binding.

-- 2.00.00.02
-- Some gimped keybindings workaround.  It sort of works off the blizz interface but you can lose bindings if u open it during combat.
-- It may be unstable in some other ways, I seem to lose the bindings from time to time but haven't noticed why yet.
-- This will have to do for now.  I may add explicit per slot binding if this is too lame for real use.
-- Show category icons for 0 item slots works again
-- Show empty slots kinda works but still some strangeness when used with category icons off.

-- 2.00.00.01
-- Make blizz clock cooldown show up again
-- Some progress on drag handle
-- Got rid of Compost

-- 2.00.00.00
-- First rough cut.  Using Secure State Header & Buttons for the bar & popups.
-- Hacking around the lack of an inventory item button with itemId other than direct bag slot & by name.
-- Oops, didnt ship the config.  Doh!

-- See Changelist.lua for older versions


local _G = getfenv(0);
local L = AceLibrary("AceLocale-2.2"):new("AutoBar");

BINDING_HEADER_AUTOBAR_SEP = L["AUTOBAR"];
BINDING_NAME_AUTOBAR_CONFIG = L["CONFIG_WINDOW"];
BINDING_NAME_AUTOBAR_BUTTON1 = L["BUTTON"] .. " 1";
BINDING_NAME_AUTOBAR_BUTTON2 = L["BUTTON"] .. " 2";
BINDING_NAME_AUTOBAR_BUTTON3 = L["BUTTON"] .. " 3";
BINDING_NAME_AUTOBAR_BUTTON4 = L["BUTTON"] .. " 4";
BINDING_NAME_AUTOBAR_BUTTON5 = L["BUTTON"] .. " 5";
BINDING_NAME_AUTOBAR_BUTTON6 = L["BUTTON"] .. " 6";
BINDING_NAME_AUTOBAR_BUTTON7 = L["BUTTON"] .. " 7";
BINDING_NAME_AUTOBAR_BUTTON8 = L["BUTTON"] .. " 8";
BINDING_NAME_AUTOBAR_BUTTON9 = L["BUTTON"] .. " 9";
BINDING_NAME_AUTOBAR_BUTTON10 = L["BUTTON"] .. " 10";
BINDING_NAME_AUTOBAR_BUTTON11 = L["BUTTON"] .. " 11";
BINDING_NAME_AUTOBAR_BUTTON12 = L["BUTTON"] .. " 12";
BINDING_NAME_AUTOBAR_BUTTON13 = L["BUTTON"] .. " 13";
BINDING_NAME_AUTOBAR_BUTTON14 = L["BUTTON"] .. " 14";
BINDING_NAME_AUTOBAR_BUTTON15 = L["BUTTON"] .. " 15";
BINDING_NAME_AUTOBAR_BUTTON16 = L["BUTTON"] .. " 16";
BINDING_NAME_AUTOBAR_BUTTON17 = L["BUTTON"] .. " 17";
BINDING_NAME_AUTOBAR_BUTTON18 = L["BUTTON"] .. " 18";
BINDING_NAME_AUTOBAR_BUTTON19 = L["BUTTON"] .. " 19";
BINDING_NAME_AUTOBAR_BUTTON20 = L["BUTTON"] .. " 20";
BINDING_NAME_AUTOBAR_BUTTON21 = L["BUTTON"] .. " 21";
BINDING_NAME_AUTOBAR_BUTTON22 = L["BUTTON"] .. " 22";
BINDING_NAME_AUTOBAR_BUTTON23 = L["BUTTON"] .. " 23";
BINDING_NAME_AUTOBAR_BUTTON24 = L["BUTTON"] .. " 24";

function AutoBarConfig_Toggle(msg)
	if (not InCombatLockdown()) then
		local loaded, message = LoadAddOn("AutoBarConfig");
		if (loaded) then
			PlaySound("igMainMenuOpen");
			if (not AutoBarConfig.initialized) then
				AutoBarConfig:TabButtonInitialize();
				AutoBarConfig.initialized = true;
			end

			if (AutoBarConfigFrame:IsVisible()) then
				AutoBarConfigFrame:Hide();
			else
				AutoBarConfigFrame:Show();
			end
		else
			PlaySound("TellMessage");
			DEFAULT_CHAT_FRAME:AddMessage(L["LOAD_ERROR"]..message);
		end
	end
end


local options = {
	type = 'execute',
	desc = "Toggle the config panel",
	func = AutoBarConfig_Toggle,
}


-- If the Debug library is available then use it
if AceLibrary:HasInstance("AceDebug-2.0") then
	AutoBar = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceConsole-2.0", "AceDB-2.0", "AceDebug-2.0");
else
	AutoBar = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceConsole-2.0", "AceDB-2.0");
end
AutoBar:RegisterChatCommand({L["SLASHCMD_SHORT"], L["SLASHCMD_LONG"]}, options)
AutoBar:RegisterDB("AutoBarDB", "AutoBarDBPC")
AutoBar:RegisterDefaults("char", {
--		profile = {};
--		profile.useCharacter = true;
--		profile.useShared = false;
--		profile.useClass = false;
--		profile.useBasic = false;
--		profile.edit = 1;
--		profile.shared = "_SHARED1";
--		profile.layout = 1;
--		profile.layoutProfile = AutoBar.currentPlayer;
	}
)

AUTOBAR_MAXBUTTONS = 24;
AUTOBAR_MAXPOPUPBUTTONS = 12;
AUTOBAR_MAXSLOTCATEGORIES = 16;
local AUTOBAR_SHIFTSTATE = AUTOBAR_MAXBUTTONS * AUTOBAR_MAXPOPUPBUTTONS; -- state offset when shift is held down

AutoBar_Debug = nil;

AutoBar_SearchedForItems = {};
local AutoBar_ButtonItemList = {};
local AutoBar_ButtonItemList_Reversed = {};
local AutoBar_Buttons_CurrentItems = {};


function AutoBar:OnInitialize()
	AutoBar.currentPlayer = UnitName("player") .. " - " .. GetCVar("realmName");

	AutoBar.inWorld = false;
	AutoBar.inCombat = false;	-- For item use restrictions
	AutoBar.inBG = false;		-- For battleground only items

	AutoBarItemList:OnInitialize();
	AutoBarProfile.Initialize();
	AutoBar:LayoutInitialize();
end


function AutoBar:OnEnable()
	-- Called when the addon is enabled
	self:RegisterEvent("PLAYER_ENTERING_WORLD")
	self:RegisterEvent("PLAYER_LEAVING_WORLD")
	self:RegisterEvent("BAG_UPDATE")
	self:RegisterEvent("UPDATE_BINDINGS")

	-- For item use restrictions
	self:RegisterEvent("ZONE_CHANGED_NEW_AREA")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	self:RegisterEvent("PLAYER_ALIVE")
	self:RegisterEvent("BAG_UPDATE_COOLDOWN")
	self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS")
end


function AutoBar:OnDisable()
	-- Called when the addon is disabled
end


function AutoBar:PLAYER_ENTERING_WORLD()
	AutoBar.inCombat = false;
	local scanned = false;
	if (not AutoBar.initialized) then
		AutoBar.ConfigChanged();
		profileLoaded = true;
		scanned = true;
		AutoBar.initialized = true;
	end

	if (not AutoBar.inWorld) then
		AutoBar.inWorld = true;
		if (not scanned) then
			AutoBar_ScanBags();
		end
	end
	AutoBar:LayoutUpdate();
	AutoBar.ssHeader:SetAttribute("state", "0");
end


function AutoBar:PLAYER_LEAVING_WORLD()
	AutoBar.inWorld = false;
end


local pendingScan = false;
function AutoBar:BAG_UPDATE()
	if (AutoBar.inWorld and arg1 < 5) then
		if (InCombatLockdown()) then
			pendingScan = true;
		else
			AutoBar_ScanBags(arg1);
		end
	end
end


function AutoBar:UPDATE_BINDINGS()
	if (not InCombatLockdown()) then
		AutoBar:ButtonsUpdate();
	end
end


function AutoBar:ZONE_CHANGED_NEW_AREA()
	if (not InCombatLockdown()) then
		AutoBar:ButtonsUpdate();
	end
end


function AutoBar:PLAYER_REGEN_ENABLED()
	AutoBar.inCombat = false;
	if (pendingScan) then
		AutoBar_ScanBags();
		pendingScan = false;
	else
		AutoBar:ButtonsUpdate();
	end
end


function AutoBar:PLAYER_REGEN_DISABLED()
	AutoBar.inCombat = true;
	AutoBar:ButtonsUpdate();
	if (AutoBarConfigFrame) then
		AutoBarConfigFrame:Hide();
	end
end


function AutoBar:UNIT_MANA()
	if (arg1 == "player") then
		if (not InCombatLockdown()) then
			AutoBar:ButtonsUpdate();
		end
	end
end


function AutoBar:UNIT_HEALTH()
	if (arg1 == "player") then
		if (not InCombatLockdown()) then
			AutoBar:ButtonsUpdate();
		end
	end
end


function AutoBar:PLAYER_ALIVE()
	if (not InCombatLockdown()) then
		AutoBar:ButtonsUpdate();
	end
end


function AutoBar:BAG_UPDATE_COOLDOWN()
	if (not InCombatLockdown()) then
		AutoBar:ButtonsUpdate();
	end
end


function AutoBar:UPDATE_BATTLEFIELD_STATUS()
	if (AutoBar.inWorld) then
		for i = 1, MAX_BATTLEFIELD_QUEUES do
			local status, mapName, instanceID = GetBattlefieldStatus(i);
			if (instanceID ~= 0) then
				AutoBar.inBG = true;
				return;
			else
				AutoBar.inBG = false;
			end
		end
	end
end


-- When dragging, contains { frameName, index }, otherwise nil
AutoBar.dragging = nil;
local draggingData = {};

function AutoBar.GetDraggingIndex(frameName)
	if (AutoBar.dragging and AutoBar.dragging.frameName == frameName) then
		return AutoBar.dragging.index;
	end
	return nil;
end


function AutoBar.SetDraggingIndex(frameName, index)
	draggingData.frameName = frameName;
	draggingData.index = index;
	AutoBar.dragging = draggingData;
end


function AutoBar.LinkDecode(link)
	if (link) then
		local _, _, id, _, _, _, name = string.find(link, "item:(%d+):(%d+):(%d+):(%d+).+%[(.+)%]");
		if (id and name) then
			return name, tonumber(id);
		end
	end
end


local function AutoBar_BuildItemList()
	local function AddItemInfo(identifier, buttonsIndex)
		if (AutoBar_Category_Info[identifier] and AutoBar_Category_Info[identifier].items) then
			local index, j;
			for index, j in pairs(AutoBar_Category_Info[identifier].items) do
				if (AutoBar_SearchedForItems[j]) then
					table.insert(AutoBar_SearchedForItems[j], buttonsIndex);
				else
					AutoBar_SearchedForItems[j] = { buttonsIndex, identifier, index };
				end
				table.insert(AutoBar_ButtonItemList[buttonsIndex], j);
			end
		else
			if (AutoBar_SearchedForItems[identifier]) then
				table.insert(AutoBar_SearchedForItems[identifier], buttonsIndex);
			else
				AutoBar_SearchedForItems[identifier] = { buttonsIndex, identifier, 0 };
			end
			table.insert(AutoBar_ButtonItemList[buttonsIndex], identifier);
		end
	end
	AutoBar_SearchedForItems = {};
	AutoBar_ButtonItemList_Reversed = {};
	local index;
	for index = 1, AUTOBAR_MAXBUTTONS, 1 do
		if (AutoBar.buttons[index]) then
			local i, j;
			AutoBar_ButtonItemList[index] = {};
			AutoBar_ButtonItemList_Reversed[index] = {};
			if (type(AutoBar.buttons[index]) == "table") then
				for i, j in pairs(AutoBar.buttons[index]) do
					AddItemInfo (j, index);
				end
			else
				AddItemInfo (AutoBar.buttons[index], index);
			end
			for i, j in pairs(AutoBar_ButtonItemList[index]) do
				AutoBar_ButtonItemList_Reversed[index][j] = i;
			end
		end
	end
end


function AutoBar_Button_GetDisplayItem(buttonsIndex)
	local index, bag, slot, rank, itemId, category, categoryIndex, acceptable, cooldowntime, itemMinLevel;
	local cooldownIndex, start, duration, enable, fallback;
	if (AutoBar_Buttons_CurrentItems[buttonsIndex]) then
		index = table.maxn(AutoBar_Buttons_CurrentItems[buttonsIndex]);
	else
		index = 0;
	end
--DEFAULT_CHAT_FRAME:AddMessage("DisplayItem " .. buttonsIndex .. " index " .. tostring(index) .. " " .. tostring(index));
	while (index > 0 and not acceptable) do
		bag = AutoBar_Buttons_CurrentItems[buttonsIndex][index].items[1][1];
		slot = AutoBar_Buttons_CurrentItems[buttonsIndex][index].items[1][2];
		rank = AutoBar_Buttons_CurrentItems[buttonsIndex][index].rank;
		itemId = AutoBar_ButtonItemList[buttonsIndex][rank];
		if (type(itemId) == "number") then
			_,_,_,_,itemMinLevel = GetItemInfo(itemId);
		else
			itemMinLevel = 0;
		end
		if (AutoBar_SearchedForItems[itemId]) then
			category = AutoBar_SearchedForItems[itemId][2];
			categoryIndex = AutoBar_SearchedForItems[itemId][3];
		else
			category = nil;
			categoryIndex = nil;
		end
		--
--		start, duration, enable = GetContainerItemCooldown(bag, slot);
--		start, duration, enable = GetItemCooldown(itemId);
--		if (start > 0 and duration > 0) then
--			local tmp = start - GetTime() + duration;
--			if (not cooldowntime or tmp < cooldowntime) then
--				cooldowntime = tmp;
--				cooldownIndex = index;
--			end
--			index = index - 1;
--		else
			if (itemMinLevel > UnitLevel("player")) then
			index = index - 1;
		elseif (AutoBar_Category_Info[category] and AutoBar_Category_Info[category].location and AutoBar_Category_Info[category].location ~= GetRealZoneText()) then
			index = index - 1;
		elseif (AutoBar_Category_Info[category] and AutoBar_Category_Info[category].battleground and not AutoBar.inBG) then
			index = index - 1;
		elseif (AutoBar_Category_Info[category]) then
			if (not fallback) then
				fallback = index;
			end
			if (AutoBar_Category_Info[category].noncombat and AutoBar.inCombat) then
				index = index - 1;
			elseif (AutoBar_Category_Info[category].limit) then
				local losthp = UnitHealthMax("player") - UnitHealth("player");
				local lostmana = UnitManaMax("player") - UnitMana("player");
				if (UnitPowerType("player") ~= 0 ) then
					--if (UnitClass("player") == "Druid") then
						-- Can't check mana in druid forms
					--	lostmana = 0;
					--else
						-- Class doesn't have mana, don't limit
						lostmana = 10000;
					--end
				end
				if (AutoBar_Category_Info[category].limit.downhp and AutoBar_Category_Info[category].limit.downhp[categoryIndex] > losthp) then
					index = index - 1
				elseif (AutoBar_Category_Info[category].limit.downmana and AutoBar_Category_Info[category].limit.downmana[categoryIndex] > lostmana) then
					index = index - 1
				else
					acceptable = true;
				end
			else
				acceptable = true;
			end
		else
			acceptable = true;
		end
	end
	if (not acceptable) then
		if (fallback) then
			index = fallback;
		elseif (cooldownIndex) then
			index = cooldownIndex;
		elseif (AutoBar_Buttons_CurrentItems[buttonsIndex]) then
			index = table.maxn(AutoBar_Buttons_CurrentItems[buttonsIndex]);
		else
			index = nil;
		end
	end
	--
	if (index) then
		bag = AutoBar_Buttons_CurrentItems[buttonsIndex][index].items[1][1];
		slot = AutoBar_Buttons_CurrentItems[buttonsIndex][index].items[1][2];
		rank = AutoBar_Buttons_CurrentItems[buttonsIndex][index].rank;
	else
		bag = nil; slot = nil; rank = nil;
	end
	if (AutoBar_ButtonItemList[buttonsIndex]) then
		itemId = AutoBar_ButtonItemList[buttonsIndex][rank];
		if (AutoBar_SearchedForItems[itemId]) then
			category = AutoBar_SearchedForItems[itemId][2];
			categoryIndex = AutoBar_SearchedForItems[itemId][3];
		else
			category = nil;
			categoryIndex = nil;
		end
	else
		itemId = nil; category = nil; categoryIndex = nil;
	end
	return bag, slot, rank, itemId, category, categoryIndex, index, acceptable, cooldowntime;
end


--
-- Button Update callback functions
--
function AutoBar_Button_SetTooltip()
	if ( GetCVar("UberTooltips") == "1" ) then
		GameTooltip_SetDefaultAnchor(GameTooltip, this);
	else
		GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
	end

	local type = this:GetAttribute("type"); -- Mmm is self a good substitute here for button?
	if (type == "item") then
		local bag = this:GetAttribute("bag");
		local slot = this:GetAttribute("slot");

		if (bag and slot) then
			GameTooltip:SetBagItem(bag, slot);
		elseif (slot) then
			GameTooltip:SetSlotItem(slot);
		end

		this.updateTooltip = TOOLTIP_UPDATE_TIME;
	else
		this.updateTooltip = nil;
	end
end


function AutoBar_Button_UpdateUsable()
	local icon = getglobal(this:GetName().."Icon");
	local normalTexture = getglobal(this:GetName().."NormalTexture");
	local itemId = this:GetAttribute("itemId");
--TODO:
local isUsable = true;
	if ( isUsable ) then
		icon:SetVertexColor(1.0, 1.0, 1.0);
		normalTexture:SetVertexColor(1.0, 1.0, 1.0);
	elseif ( notEnoughMana ) then
		icon:SetVertexColor(0.5, 0.5, 1.0);
		normalTexture:SetVertexColor(0.5, 0.5, 1.0);
	else
		icon:SetVertexColor(0.4, 0.4, 0.4);
		normalTexture:SetVertexColor(1.0, 1.0, 1.0);
	end
end


function AutoBar_Button_UpdateCount()
	local text = getglobal(this:GetName().."Count");
	local itemId = this:GetAttribute("itemId");
	local count = 0;
	if( itemId  ) then
		count = GetItemCount(tonumber(itemId));
	end
	
	if (count > 0) then
		text:SetText(count);
	else
		text:SetText("");
	end
end


function AutoBar_Button_UpdateCooldown()
	local cooldown = getglobal(this:GetName().."Cooldown");
	local bag = this:GetAttribute("bag");
	local slot = this:GetAttribute("slot");
	local start, duration, enable;

	if (bag and slot) then
		start, duration, enable = GetContainerItemCooldown(bag, slot);
	elseif (slot) then
		start, duration, enable = GetInventoryItemCooldown("player", slot);
	end
	CooldownFrame_SetTimer(cooldown, start, duration, enable);
end


function AutoBar_Button_Update()
	local icon = getglobal(this:GetName().."Icon");
	local cooldown = getglobal(this:GetName().."Cooldown");
	local bag = this:GetAttribute("bag");
	local slot = this:GetAttribute("slot");
	local itemId = this:GetAttribute("itemId");
	local count = 0;
	local texture;
	if (itemId) then
		count = GetItemCount(tonumber(itemId));
		itemName,_,_,_,_,_,_,_,_,texture = GetItemInfo(tonumber(itemId));
	end
	if ( texture ) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar_Button_Update " .. itemName .. "    " .. tostring(texture));
		icon:SetTexture(texture);
		icon:Show();
		this.rangeTimer = -1;
		this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
--		-- Save texture if the button is a bonus button, will be needed later
--		if ( this.isBonus ) then
--			this.texture = texture;
--		end
	else
		icon:Hide();
		cooldown:Hide();
		this.rangeTimer = nil;
		this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
		getglobal(this:GetName().."HotKey"):SetVertexColor(0.6, 0.6, 0.6);
	end
	AutoBar_Button_UpdateCount();
	if (count > 0) then
		this:RegisterEvent("ACTIONBAR_UPDATE_STATE");
		this:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
		this:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
		this:RegisterEvent("UPDATE_INVENTORY_ALERTS");
		this:RegisterEvent("PLAYER_AURAS_CHANGED");
		this:RegisterEvent("PLAYER_TARGET_CHANGED");
		this:RegisterEvent("UNIT_INVENTORY_CHANGED");
		this:RegisterEvent("CRAFT_SHOW");
		this:RegisterEvent("CRAFT_CLOSE");
		this:RegisterEvent("TRADE_SKILL_SHOW");
		this:RegisterEvent("TRADE_SKILL_CLOSE");
		this:RegisterEvent("PLAYER_ENTER_COMBAT");
		this:RegisterEvent("PLAYER_LEAVE_COMBAT");
		this:RegisterEvent("START_AUTOREPEAT_SPELL");
		this:RegisterEvent("STOP_AUTOREPEAT_SPELL");

--		if ( not this:GetAttribute("statehidden") ) then
--			this:Show();
--		end
		AutoBar_Button_UpdateUsable();
		AutoBar_Button_UpdateCooldown();
	else
		this:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
		this:UnregisterEvent("ACTIONBAR_UPDATE_USABLE");
		this:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
		this:UnregisterEvent("UPDATE_INVENTORY_ALERTS");
		this:UnregisterEvent("PLAYER_AURAS_CHANGED");
		this:UnregisterEvent("PLAYER_TARGET_CHANGED");
		this:UnregisterEvent("UNIT_INVENTORY_CHANGED");
		this:UnregisterEvent("CRAFT_SHOW");
		this:UnregisterEvent("CRAFT_CLOSE");
		this:UnregisterEvent("TRADE_SKILL_SHOW");
		this:UnregisterEvent("TRADE_SKILL_CLOSE");
		this:UnregisterEvent("PLAYER_ENTER_COMBAT");
		this:UnregisterEvent("PLAYER_LEAVE_COMBAT");
		this:UnregisterEvent("START_AUTOREPEAT_SPELL");
		this:UnregisterEvent("STOP_AUTOREPEAT_SPELL");

		cooldown:Hide();
	end

	-- Add a green border if button is an equipped item
	local border = getglobal(this:GetName().."Border");
	if (not bag and slot) then	-- TODO: upgrade to actually check.
		border:SetVertexColor(0, 1.0, 0, 0.35);
		border:Show();
	else
		border:Hide();
	end

	if ( GameTooltip:IsOwned(this) ) then
		AutoBar_Button_SetTooltip();
	else
		this.updateTooltip = nil;
	end

	-- Update Macro Text
--	local macroText = this:GetAttribute("macroText");
--	local macroName = getglobal(this:GetName().."Name");
--	macroName:SetText(macroText);
end


function AutoBar:SetButton(button, baseName, bag, slot, count, itemId, category, itemName, action)
	-- Handle targeted items
	button:SetAttribute("target-slot1", nil);
	button:SetAttribute("target-slot2", nil);
--button:SetAttribute("*helpbutton2", nil);
--button:SetAttribute("*unit-help2", nil);
--button:SetAttribute("*harmbutton2", nil);
--button:SetAttribute("*unit-harm2", nil);
	button:SetAttribute("*unit2", nil);
	button:SetAttribute("alt-unit*", nil);
	if (AutoBar_SearchedForItems[itemId]) then
		category = AutoBar_SearchedForItems[itemId][2];
		if (AutoBar_Category_Info[category]) then
			local targeted = AutoBar_Category_Info[category].targetted;
			if (targeted == "WEAPON") then
				button:SetAttribute("target-slot1", 16);
				button:SetAttribute("target-slot2", 17);
			elseif (targeted) then
				-- Support smart self targeting
--				if (AutoBar.display.autoSmartSelfCast) then
--					button:SetAttribute("*helpbutton1", "help1");
--					button:SetAttribute("*unit-help1", "player");
--					button:SetAttribute("*harmbutton1", "harm1");
--					button:SetAttribute("*unit-harm1", "player");
--				end

				-- Support selfcast-RightMouse
				button:SetAttribute("*unit2", "player");

				-- Support alt-selfcast
				button:SetAttribute("alt-unit*", "player");
			end
		end
	end

	if (bag or slot) then
		button:SetAttribute("type", "item");
		button:SetAttribute("bag", bag);
		button:SetAttribute("slot", slot);
		button:SetScript("OnAttributeChanged", AutoBar_Button_Update)
	elseif (itemName) then
		button:SetAttribute("type", "item");
		button:SetAttribute("item", itemName);
		button:SetScript("OnAttributeChanged", AutoBar_Button_Update)
	elseif (action) then
		button:SetAttribute("type", "action");
		button:SetAttribute("action", action);
		button:SetScript("OnAttributeChanged", ActionButton_Update)
	end
	button:SetAttribute("itemId", itemId);
	button:SetAttribute("category", category);

	local normalTexture = _G[baseName.."NormalTexture"];
	local countText = _G[baseName.."Count"];
	local cooldown = _G[baseName.."Cooldown"];
	local icon = _G[baseName.."Icon"];

	if (bag and slot) then
local t = GetContainerItemInfo(bag, slot);
--if (not string.find(baseName, "P")) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:SetButton " .. baseName .. "    " .. tostring(t));
--end
		if (AutoBar.display.plainButtons) then
			icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
		else
			icon:SetTexCoord(0, 1, 0, 1)
		end

		local start, duration, enable = GetContainerItemCooldown(bag, slot);

		if (enable) then
			icon:SetVertexColor(1, 1, 1);
			normalTexture:SetVertexColor(0, 0, 0);
		elseif (start > 0 and duration > 0) then
			icon:SetVertexColor(1, 1, 1);
			normalTexture:SetVertexColor(0, 0, 0);
		else
			icon:SetVertexColor(0.4, 0.4, 0.4);
			normalTexture:SetVertexColor(1, 1, 1);
		end

		if (count and count > 1) then
			countText:SetText(count);
		else
			countText:SetText("");
		end
	else
		local hotKey = _G[baseName.."HotKey"];

		CooldownFrame_SetTimer(cooldown, 0, 0, 0);
		if (AutoBar.display.showCategoryIcon and category) then
			-- Button is empty so show Category Icon
			icon:SetTexture(AutoBar_GetTexture(category));
			countText:SetText("--");
			hotKey:SetText("");
			icon:SetVertexColor(0.2, 0.2, 0.2);
			normalTexture:SetVertexColor(1, 1, 1);
		else
			-- Button is empty
			icon:SetTexture("");
			countText:SetText("");
			hotKey:SetText("");
		end
	end

end


AutoBar.clickBindings = {
  {"AUTOBAR_BUTTON1", "CLICK AutoBarSAB1:LeftButton"},
  {"AUTOBAR_BUTTON2", "CLICK AutoBarSAB2:LeftButton"},
  {"AUTOBAR_BUTTON3", "CLICK AutoBarSAB3:LeftButton"},
  {"AUTOBAR_BUTTON4", "CLICK AutoBarSAB4:LeftButton"},
  {"AUTOBAR_BUTTON5", "CLICK AutoBarSAB5:LeftButton"},
  {"AUTOBAR_BUTTON6", "CLICK AutoBarSAB6:LeftButton"},
  {"AUTOBAR_BUTTON7", "CLICK AutoBarSAB7:LeftButton"},
  {"AUTOBAR_BUTTON8", "CLICK AutoBarSAB8:LeftButton"},
  {"AUTOBAR_BUTTON9", "CLICK AutoBarSAB9:LeftButton"},
  {"AUTOBAR_BUTTON10", "CLICK AutoBarSAB10:LeftButton"},
  {"AUTOBAR_BUTTON11", "CLICK AutoBarSAB11:LeftButton"},
  {"AUTOBAR_BUTTON12", "CLICK AutoBarSAB12:LeftButton"},
  {"AUTOBAR_BUTTON13", "CLICK AutoBarSAB13:LeftButton"},
  {"AUTOBAR_BUTTON14", "CLICK AutoBarSAB14:LeftButton"},
  {"AUTOBAR_BUTTON15", "CLICK AutoBarSAB15:LeftButton"},
  {"AUTOBAR_BUTTON16", "CLICK AutoBarSAB16:LeftButton"},
  {"AUTOBAR_BUTTON17", "CLICK AutoBarSAB17:LeftButton"},
  {"AUTOBAR_BUTTON18", "CLICK AutoBarSAB18:LeftButton"},
  {"AUTOBAR_BUTTON19", "CLICK AutoBarSAB19:LeftButton"},
  {"AUTOBAR_BUTTON20", "CLICK AutoBarSAB20:LeftButton"},
  {"AUTOBAR_BUTTON21", "CLICK AutoBarSAB21:LeftButton"},
  {"AUTOBAR_BUTTON22", "CLICK AutoBarSAB22:LeftButton"},
  {"AUTOBAR_BUTTON23", "CLICK AutoBarSAB23:LeftButton"},
  {"AUTOBAR_BUTTON24", "CLICK AutoBarSAB24:LeftButton"},
}


-- Gello's workaround for the lame lack of binding support
-- moves a set of bindings from dummy to real, assuming a numerically-indexed table
-- with sub-arrays that contain two elements: dummy name (from Bindings.xml) and
-- full button binding name (ie "CLICK MySecureButton:LeftButton")
-- fromIndex and toIndex are either 1 or 2, index to sub-array "column"
-- or use fromIndex as "real" to set real bindings, "dummy" to set dummy bindings
function AutoBar.MoveBindings(fromIndex, toIndex)
	if InCombatLockdown() then
		return -- can't change bindings in combat lockdown
	end
--SetOverrideBindingClick(AutoBar.ssHeader, false, "NUMPAD".."7", "AutoBarSAB7")
--SetOverrideBindingClick(AutoBar.ssHeader, false, "5", "AutoBarSAB5")
	local bindings = AutoBar.clickBindings -- this is the table created above
	local from,to
	if fromIndex=="real" then
		fromIndex,toIndex = 1,2
	elseif fromIndex=="dummy" then
		fromIndex,toIndex = 2,1
	end
	for i=1, table.maxn(bindings) do
		from = bindings[i][fromIndex]
		to = bindings[i][toIndex]
		while GetBindingKey(to) do
			SetBinding(GetBindingKey(to)) -- cleanup destination binds
		end
		local key = GetBindingKey(from)
		if key and key~="" then
			local _,_,button,mouse = string.find(to,"CLICK (.+):(.+)")
			if button and mouse then
				SetBindingClick(key,button,mouse)
			else
				SetBinding(key,to)
			end
			while GetBindingKey(from) do
				SetBinding(GetBindingKey(from)) -- cleanup source binds
			end
		end
	end
end


function AutoBar:GetHotkeyDisplayText(keyText)
	if (keyText) then
		local displayText = string.gsub(keyText, "-CTRL", "C");
		displayText = string.gsub(displayText, "CTRL", "C");
		displayText = string.gsub(displayText, "-ALT", "A");
		displayText = string.gsub(displayText, "-SHIFT", "S");
		displayText = string.gsub(displayText, "-NUMPAD", "N");
		displayText = string.gsub(displayText, "-BUTTON", "B");
		displayText = string.gsub(displayText, "ALT", "A");
		displayText = string.gsub(displayText, "SHIFT", "S");
		displayText = string.gsub(displayText, "NUMPAD", "N");
		displayText = string.gsub(displayText, "BUTTON", "B");
		displayText = string.gsub(displayText, "MULTIPLY", "*");
		displayText = string.gsub(displayText, "DECIMAL", ".");
		displayText = string.gsub(displayText, "DIVIDE", "/");
		displayText = string.gsub(displayText, "MINUS", "-");
		displayText = string.gsub(displayText, "PLUS", "-");
		return displayText;
	else
		return "";
	end
end


-- Assign content to the buttons, set count & keybinding texts, visibility, etc.
function AutoBar:ButtonsUpdate()
	if (not AutoBar.inWorld) then
		return
	end
	local buttonsIndex, i, button, icon, countText, index, enabled, items, bag, slot, rank, itemId, popupItemId;
	local hotKey, count, keyText;
	local displayButton = 1;		-- On Screen button, ignores empty slots
	local keys = AutoBarProfile:GetKeys();
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonsUpdate start");
	for buttonsIndex = 1, AUTOBAR_MAXBUTTONS, 1 do
		local button = AutoBar.ssButtons[buttonsIndex];
		local showButton = button:GetAttribute("buttonsIndex");

		local popupButtons = AutoBar.ssPopupButtons[buttonsIndex];
		local popupButton;
		for popupButtonIndex = 1, AUTOBAR_MAXPOPUPBUTTONS, 1 do
			popupButton = popupButtons[popupButtonIndex];
			popupButton:SetAttribute("showstates", "!*");
		end

--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonsUpdate buttonsIndex " .. buttonsIndex);
		if (showButton) then
			bag, slot,_,_,_,_,index,enabled = AutoBar_Button_GetDisplayItem(buttonsIndex)
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonsUpdate buttonsIndex " .. buttonsIndex .. " bag, slot " .. tostring(bag) .. " " .. tostring(slot));
			if (bag and slot) then
				button:SetAttribute("showstates", "*");
				button.x = AutoBar.buttonLocations[displayButton].x;
				button.y = AutoBar.buttonLocations[displayButton].y;
				button:SetAttribute("ofsx", button.x);
				button:SetAttribute("ofsy", button.y);

				rank = AutoBar_Buttons_CurrentItems[buttonsIndex][index].rank;
				itemId = AutoBar_ButtonItemList[buttonsIndex][rank];
				count = GetItemCount(tonumber(itemId));

				self:SetButton(button, "AutoBarSAB"..buttonsIndex, bag, slot, count, itemId)

				-- The popup mostly displays the best to worst choice in order, mostly
				local popupButtonIndex, currentItems, buttonIndex, effectivePopup;
				local maxPopups = table.maxn(AutoBar_Buttons_CurrentItems[buttonsIndex]);
				local targetPopup = maxPopups;

				for popupButtonIndex = 1, maxPopups do
					if (popupButtonIndex > AUTOBAR_MAXPOPUPBUTTONS) then
						break;
					end
					currentItems = AutoBar_Buttons_CurrentItems[buttonsIndex][popupButtonIndex];
					rank = AutoBar_Buttons_CurrentItems[buttonsIndex][popupButtonIndex].rank;
					popupItemId = AutoBar_ButtonItemList[buttonsIndex][rank];
					count = GetItemCount(tonumber(popupItemId));

					if (itemId == popupItemId) then
						effectivePopup = 1;
					else
						effectivePopup = targetPopup;
						targetPopup = targetPopup - 1;
					end
--local name, _ = AutoBar.LinkDecode(GetContainerItemLink(currentItems.items[1][1], currentItems.items[1][2]));
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonsUpdate popupButtonIndex " .. tostring(popupButtonIndex) .. " effectivePopup " .. tostring(effectivePopup) .. " " .. tostring(name));
					popupButton = popupButtons[effectivePopup];
					self:SetButton(popupButton, "AutoBarSAB"..buttonsIndex.."P"..effectivePopup, currentItems.items[1][1], currentItems.items[1][2], count, popupItemId)
					popupButton:SetAttribute("buttonsIndex", buttonsIndex);
					popupButton:SetAttribute("popupButtonIndex", popupButtonIndex);

					if (AutoBar.display.popupOnShift) then
						if (effectivePopup == 1) then
							popupButton:SetAttribute("showstates", tostring(buttonsIndex)..";"..(tostring(buttonsIndex) + AUTOBAR_SHIFTSTATE));
						else
							popupButton:SetAttribute("showstates", (tostring(buttonsIndex) + AUTOBAR_SHIFTSTATE));
						end
					else
						popupButton:SetAttribute("showstates", tostring(buttonsIndex));
					end

					self:ButtonSetup("AutoBarSAB"..buttonsIndex.."P"..effectivePopup);
				end

				-- Adjust popup positions based on their buttons position
				local gapping = AutoBar.display.gapping;
				local buttonWidth = AutoBar.display.buttonWidth;
				local buttonHeight = AutoBar.display.buttonHeight;
				for popupButtonIndex = 1, AUTOBAR_MAXPOPUPBUTTONS do
					local popupButton = popupButtons[popupButtonIndex];
					local buttonDistance = popupButtonIndex - 1;	-- Zero based so first button is on top of its parent

					-- Set the popup direction
					if (AutoBar.display.popupToBottom) then
						popupButton:SetAttribute("ofsx", "*:"..button.x);
						popupButton:SetAttribute("ofsy", "*:"..(button.y - buttonDistance * (buttonHeight + gapping)));
					elseif (AutoBar.display.popupToLeft) then
						popupButton:SetAttribute("ofsx", "*:"..button.x - buttonDistance * (buttonWidth + gapping));
						popupButton:SetAttribute("ofsy", "*:"..(button.y));
					elseif (AutoBar.display.popupToRight) then
						popupButton:SetAttribute("ofsx", "*:"..button.x + buttonDistance * (buttonWidth + gapping));
						popupButton:SetAttribute("ofsy", "*:"..(button.y));
					else
						popupButton:SetAttribute("ofsx", "*:"..button.x);
						popupButton:SetAttribute("ofsy", "*:"..(button.y + buttonDistance * (buttonHeight + gapping)));
					end
				end

				displayButton = displayButton + 1;
			else
				if (AutoBar.display.showCategoryIcon and AutoBar.buttons[buttonsIndex]) then
					button:SetAttribute("showstates", "*");
					button.x = AutoBar.buttonLocations[displayButton].x;
					button.y = AutoBar.buttonLocations[displayButton].y;
					button:SetAttribute("ofsx", button.x);
					button:SetAttribute("ofsy", button.y);
				    -- Button is empty so show Category Icon
					local buttonInfo = AutoBar.buttons[buttonsIndex];
					if (buttonInfo and buttonInfo[1]) then
						local category = buttonInfo[table.maxn(buttonInfo)];
						self:SetButton(button, "AutoBarSAB"..buttonsIndex, nil, nil, 0, nil, category)
						displayButton = displayButton + 1;
					else
						if (AutoBar.display.showEmptyButtons) then
							button:SetAttribute("showstates", "!*");
							displayButton = displayButton + 1;
						end
					end
				else
					button:SetAttribute("showstates", "!*");
				end
			end
		else
			button:SetAttribute("showstates", "!*");
		end
	end
--	AutoBar.ssHeader:SetAttribute("state", "0");
	SecureStateHeader_Refresh(AutoBar.ssHeader);
end


-- Assign display buttons to active slots and return the number of displayed buttons
function AutoBar:AssignButtons(maxButtons)
	local displayedButtons = 1;

	if (AutoBar.ssButtons) then
		local buttonsIndex, buttonInfo, rankIndex, items;
		for buttonsIndex = 1, AUTOBAR_MAXBUTTONS do
			local button = AutoBar.ssButtons[buttonsIndex];
			if (maxButtons and displayedButtons > maxButtons) then
				button:SetAttribute("buttonsIndex", nil);
			elseif (AutoBar.display.showEmptyButtons or AutoBar_Buttons_CurrentItems[buttonsIndex]) then
				button:SetAttribute("buttonsIndex", buttonsIndex);
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:AssignButtons CurrentItems -> "..buttonsIndex);
				displayedButtons = displayedButtons + 1;
			elseif (AutoBar.display.showCategoryIcon and AutoBar.buttons[buttonsIndex]) then
				button:SetAttribute("buttonsIndex", buttonsIndex);
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:AssignButtons showCategoryIcon");
				displayedButtons = displayedButtons + 1;
			else
				button:SetAttribute("buttonsIndex", nil);
			end
		end
	end
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:AssignButtons maxButtons " .. maxButtons .. " displayedButtons " .. (displayedButtons - 1));

	return displayedButtons - 1;
end


local function AutoBar_UpdateCategoryNameToID(name,id)
	local buttonsIndex, index;
	for buttonsIndex = 1, AUTOBAR_MAXBUTTONS, 1 do
		if (AutoBar.buttons[buttonsIndex]) then
			if (type(AutoBar.buttons[buttonsIndex]) == "table") then
				for index in pairs(AutoBar.buttons[buttonsIndex]) do
					if (AutoBar.buttons[buttonsIndex][index] == name) then
						AutoBar.buttons[buttonsIndex][index] = id;
						AutoBar_Msg(string.format(AUTOBAR_CHAT_MESSAGE2, buttonsIndex, idx));
					end
				end
			elseif (AutoBar.buttons[buttonsIndex] == name) then
				AutoBar.buttons[buttonsIndex] = id;
				AutoBar_Msg(string.format(AUTOBAR_CHAT_MESSAGE3, buttonsIndex));
			end
		end
	end
end


function AutoBar_ScanBags(specificbag)
	local function ClearOutBag(bag)
		local buttonsIndex, index, i, bagSlot, newitemlist, newranks;
		for buttonsIndex = 1, AUTOBAR_MAXBUTTONS, 1 do
			if (AutoBar_Buttons_CurrentItems[buttonsIndex]) then
				newranks = {};
				for index in pairs(AutoBar_Buttons_CurrentItems[buttonsIndex]) do
					newitemlist = {};
					for i, bagSlot in pairs(AutoBar_Buttons_CurrentItems[buttonsIndex][index].items) do
						if (bag ~= bagSlot[1]) then
							table.insert(newitemlist,bagSlot);
						end
					end
					if (table.maxn(newitemlist) > 0) then
						AutoBar_Buttons_CurrentItems[buttonsIndex][index].items = newitemlist;
						table.insert(newranks,AutoBar_Buttons_CurrentItems[buttonsIndex][index]);
					end
				end
				if (table.maxn(newranks) == 0) then
					AutoBar_Buttons_CurrentItems[buttonsIndex] = nil;
				else
					AutoBar_Buttons_CurrentItems[buttonsIndex] = newranks;
				end
			end
		end
	end
	local function AddItem(buttonsIndex, rank, bag, slot)
		if (AutoBar_Buttons_CurrentItems[buttonsIndex]) then
			local index, rec, findRank;
			for index, rec in pairs(AutoBar_Buttons_CurrentItems[buttonsIndex]) do
				if (rec.rank == rank) then
					findRank = index;
				end
			end
			if (findRank) then
				table.insert(AutoBar_Buttons_CurrentItems[buttonsIndex][findRank].items, { bag, slot } );
			else
				table.insert(AutoBar_Buttons_CurrentItems[buttonsIndex],
					{
				 		["rank"] = rank,
				 		["items"] = { { bag, slot } }
					}
				);
			end
		else
			AutoBar_Buttons_CurrentItems[buttonsIndex] = {
				[1] = {
					["rank"] = rank,
					["items"] = { { bag, slot } }
				},
			};
		end
	end
	local function SortByRank(a,b)
		if (a and b and a.rank and b.rank) then
			return a.rank < b.rank;
		else
			return true;
		end
	end

	local bag, slot, name, id, i;
	local minbag,maxbag = 0, 4;
	if (specificbag) then
		minbag = specificbag;
		maxbag = specificbag;
		ClearOutBag(specificbag);
	else
		AutoBar_Buttons_CurrentItems = {};
	end
	-- AutoBar_Buttons_CurrentItems = {
	--	buttonsIndex = {
	--		index = {
	--			"rank" = ranknum,
	--			"items" = { {bag,slot}, {bag,slot}, {bag, slot} }
	--		},
	--	},
	--};
	for bag = minbag, maxbag, 1 do
		for slot = 1, GetContainerNumSlots(bag), 1 do
			name, id = AutoBar.LinkDecode(GetContainerItemLink(bag,slot));
--DEFAULT_CHAT_FRAME:AddMessage("name, id " .. tostring(name) .. "  " .. tostring(id));
-- TODO: is this the last vestige of by name items?
--			if (name and AutoBar_SearchedForItems[name] and id) then
--DEFAULT_CHAT_FRAME:AddMessage("name: " .. tostring(name) .. "  " .. tostring(id));
--				if (not AutoBar_SearchedForItems[id]) then
--					AutoBar_SearchedForItems[id] = { AutoBar_SearchedForItems[name][1], AutoBar_SearchedForItems[name][2], AutoBar_SearchedForItems[name][3] };
--				end
--				AutoBar_UpdateCategoryNameToID(name,id);
--				AutoBar_SearchedForItems[name] = nil;
--			end
			if (id and AutoBar_SearchedForItems[id]) then
				local button = AutoBar_SearchedForItems[id][1];
				local rank = AutoBar_ButtonItemList_Reversed[button][id];
				AddItem(button, rank, bag, slot)
				if (AutoBar_SearchedForItems[id][4]) then
					for i = 4, table.maxn(AutoBar_SearchedForItems[id]), 1 do
						button = AutoBar_SearchedForItems[id][i];
						rank = AutoBar_ButtonItemList_Reversed[button][id];
--DEFAULT_CHAT_FRAME:AddMessage("id: " .. tostring(name) .. "  " .. tostring(id) .. " -> button " .. tostring(button));
						AddItem(button, rank, bag, slot)
					end
				end
			end
		end
	end
	local buttonsIndex;
	for buttonsIndex = 1, AUTOBAR_MAXBUTTONS, 1 do
	 	if (AutoBar_Buttons_CurrentItems[buttonsIndex]) then
			table.sort(AutoBar_Buttons_CurrentItems[buttonsIndex], SortByRank);
	 	end
	end
	AutoBar:AssignButtons(AutoBar.display.rows * AutoBar.display.columns);
	AutoBar:ButtonsUpdate();
end


-- Add tooltip info about the other categories in a slot to the current GameTooltip
function AutoBar_ButtonSetTooltipCategories(currentItems, categoryIndex)
	local count = 0;
	local itemCount;
	for index, bagSlot in pairs(currentItems.items) do
		_, itemCount = GetContainerItemInfo(bagSlot[1], bagSlot[2]);
		if (not itemCount) then
			itemCount = 0;
		end
		count = count + itemCount;
	end
	local name, itemId = AutoBar.LinkDecode(GetContainerItemLink(currentItems.items[1][1], currentItems.items[1][2]));
	if (not itemId) then
		return;
	end
	local category = AutoBar_SearchedForItems[itemId][2];
	local start, duration, enable = GetContainerItemCooldown(currentItems.items[1][1], currentItems.items[1][2]);
	local msg = name..AUTOBAR_TOOLTIP1..count..")";
	if (AutoBar_Debug) then
		msg = msg.." ["..currentItems.items[1][1]..","..currentItems.items[1][2].."]";
		if (rank) then
			msg = msg.." rank="..currentItems.rank;
		end
		if (cat) then
			msg = msg.." cat="..category;
		end
	end
	if (category == itemId and categoryIndex == 0) then
		msg = msg..AUTOBAR_TOOLTIP2
	end
	if (AutoBar_Category_Info[category]) then
		if (AutoBar_Category_Info[category].battleground) then
			msg=msg..AUTOBAR_TOOLTIP4;
		end
		if (AutoBar_Category_Info[category].noncombat) then
			msg=msg..AUTOBAR_TOOLTIP5;
		end
		if (AutoBar_Category_Info[category].limit) then
			msg=msg..AUTOBAR_TOOLTIP6;
		end
	end
	if (start > 0 and duration > 0) then
		msg = msg..AUTOBAR_TOOLTIP7;
	end
	GameTooltip:AddLine(msg);
	if (category and AutoBar_Category_Info[category] and AutoBar_Category_Info[category].targetted == "WEAPON") then
		GameTooltip:AddLine(AUTOBAR_TOOLTIP8);
	end
end


-- Set the tooltip for a Button or PopupButton
function AutoBar:ButtonSetTooltip(button, elapsed)
	if (AutoBar.display.hideTooltips) then
		return;
	end
	if (not button) then
		button = this;
	end
	if (button:GetParent().updateTooltip and elapsed) then
		button.updateTooltip = button.updateTooltip - elapsed;
		if (button.updateTooltip > 0) then return; end
	end

	local bag = button:GetAttribute("bag");
	local slot = button:GetAttribute("slot");

	local effectiveButton;
	if (bag and slot) then
		if (GetCVar("UberTooltips") == "1") then
			GameTooltip_SetDefaultAnchor(GameTooltip, button);
		else
			GameTooltip:SetOwner(button, "ANCHOR_RIGHT");
		end
		GameTooltip:SetBagItem(bag, slot);
--		button.updateTooltip = nil;
--
--		local bag, slot, rank, itemId, category, categoryIndex;
--		if (button.bagSlot) then
--			bag = button.bagSlot[1];
--			slot = button.bagSlot[2];
--			category = button.category;
--			effectiveButton = button:GetParent().popupButton;
--		elseif (button.effectiveButton) then
--			effectiveButton = button.effectiveButton;
--			bag, slot, rank, itemId, category, categoryIndex = AutoBar_Button_GetDisplayItem(button.effectiveButton)
--		else
--			return;
--		end
--		if (bag and slot) then
--			GameTooltip:SetBagItem(bag, slot);
--			if (AutoBar_Debug) then
--				if (rank) then
--					GameTooltip:AddLine("DISPLAYED RANK: "..rank);
--				end
--				if (itemId) then
--					GameTooltip:AddLine("DISPLAYED ITEMID: "..itemId);
--				end
--				if (category) then
--					GameTooltip:AddLine("DISPLAYED CATEGORY: "..category);
--				end
--				if (categoryIndex) then
--					GameTooltip:AddLine("DISPLAYED CATEGORY INDEX: "..categoryIndex);
--				end
--			end
--
--			local start, duration, enable = GetContainerItemCooldown(bag, slot);
--			if (start > 0 and duration > 0) then
--				button.updateTooltip = TOOLTIP_UPDATE_TIME;
--			end
--
--			GameTooltip:AddLine("");
--			local rankIndex, index, currentItems, bagSlot, count, itemCount, name, itemId, msg;
--			for rankIndex, currentItems in pairs(AutoBar_Buttons_CurrentItems[effectiveButton]) do
--				-- Display all possible items for base button or just the specific item for popup
--				if (button.effectiveButton or button.popupButtonIndex == rankIndex) then
--					AutoBar_ButtonSetTooltipCategories(currentItems, categoryIndex);
--				end
--			end
			GameTooltip:Show();
--		end
	else
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonSetTooltip unhandled button");
	end
end

--	local numReagents = GetTradeSkillNumReagents(id);
--	local totalReagents = 0;
--	for i=1, numReagents, 1 do
--		local reagentName, reagentTexture, reagentCount, playerReagentCount = GetTradeSkillReagentInfo(id, i);
--		totalReagents = totalReagents + reagentCount;
--	end;

--local numReagents = GetTradeSkillNumReagents(id);
--for i=1, numReagents, 1 do
--	local reagentName, reagentTexture, reagentCount, playerReagentCount = GetTradeSkillReagentInfo(id, i);
--	SetItemButtonTexture(reagent, reagentTexture);
--	name:SetText(reagentName);
--	-- Grayout items
--	if ( playerReagentCount < reagentCount ) then
--		SetItemButtonTextureVertexColor(reagent, 0.5, 0.5, 0.5);
--		name:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
--		creatable = nil;
--	end;
--end;

-- Return the display texture of the object
function AutoBar_GetTexture(id)
	if (not id) then
		return "";
	end

	-- Last item has priority so use its icon
	if (type(id) == "table" and id[1]) then
		id = id[table.maxn(id)];
	end

	if (id and AutoBar_Category_Info[id]) then
		if (AutoBar_Category_Info[id].texture) then
			return "Interface\\Icons\\"..AutoBar_Category_Info[id].texture;
		else
			id = AutoBar_Category_Info[id].items[table.maxn(AutoBar_Category_Info[id].items)];
		end
	end
	if (type(id)=="number" and id > 0) then
		local _,_,_,_,_,_,_,_,_,texture = GetItemInfo(tonumber(id));

		if (texture) then return texture; end
	end
	return "Interface\\Icons\\INV_Misc_Gift_01";
end


function AutoBar_Msg(...)
	local message = "";
	for i = 1, arg.n, 1 do
		if (type(arg[i]) == "string" or type(arg[i]) == "number") then
			message = message..arg[i];
		else
			message = message..string.upper(type(arg[i]));
		end
	end
	ChatFrame1:AddMessage(L["AUTOBAR"] .. ": " .. message);
end


function AutoBar.ConfigChanged()
	AutoBar_BuildItemList();
	AutoBar_ScanBags();
	AutoBar:LayoutUpdate();
end


AutoBar.dockingFrames = {
	["NONE"] = {
		text = L["AUTOBAR_CONFIG_DOCKTONONE"],
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPLEFT" },
	},
	["BT3Bar1"] = {
		text = L["AUTOBAR_CONFIG_BT3BAR"]..1,
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPLEFT" },
	},
	["BT3Bar2"] = {
		text = L["AUTOBAR_CONFIG_BT3BAR"]..2,
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPLEFT" },
	},
	["BT3Bar3"] = {
		text = L["AUTOBAR_CONFIG_BT3BAR"]..3,
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPLEFT" },
	},
	["BT3Bar4"] = {
		text = L["AUTOBAR_CONFIG_BT3BAR"]..4,
		offset = { x = 0, y = 0, point = "CENTER", relative = "BOTTOMLEFT" },
	},
	["BT3Bar10"] = {
		text = L["AUTOBAR_CONFIG_BT3BAR"]..10,
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPLEFT" },
	},
	["MainMenuBarArtFrame"] = {
		text = L["AUTOBAR_CONFIG_DOCKTOMAIN"],
		offset = { x = 0, y = 0, point = "CENTER", relative = "TOPRIGHT" },
	},
	["ChatFrame1"] = {
		text = L["AUTOBAR_CONFIG_DOCKTOCHATFRAME"],
		offset = { x = 0, y = 25, point = "CENTER", relative = "TOPLEFT" },
	},
	["ChatFrameMenuButton"] = {
		text = L["AUTOBAR_CONFIG_DOCKTOCHATFRAMEMENU"],
		offset = { x = 0, y = 25, point = "CENTER", relative = "TOPLEFT" },
	},
	["MainMenuBar"] = {
		text = L["AUTOBAR_CONFIG_DOCKTOACTIONBAR"],
		offset = { x = 7, y = 40, point = "CENTER", relative = "TOPLEFT" },
	},
	["CharacterMicroButton"] = {
		text = L["AUTOBAR_CONFIG_DOCKTOMENUBUTTONS"],
		offset = { x = 0, y = 0, point = "CENTER", relative = "BOTTOMLEFT" },
	},
};


function AutoBar:Test()
	DEFAULT_CHAT_FRAME:AddMessage(    "header state " .. tostring(_G["AutoBarSSHeaderFrame"]:GetAttribute("state")));
	for i = 1, AUTOBAR_MAXBUTTONS, 1 do
		button = AutoBar.ssButtons[i];
		s = AutoBar.ssPopupHeaders[i];
		DEFAULT_CHAT_FRAME:AddMessage("      button ".. i .. tostring(button:GetAttribute("state")).." s " .. tostring(s:GetAttribute("state")));

		local popupButtons = AutoBar.ssPopupButtons[i];
		local popupButton;
		local msg = ""
		for popupButtonIndex = 1, AUTOBAR_MAXPOPUPBUTTONS, 1 do
			popupButton = popupButtons[popupButtonIndex];--AutoBar.ssPopupButtons
			if (popupButton:GetAttribute("showstates") ~= "!*") then
				msg = msg .. tostring(popupButton:GetAttribute("state")).." ";
			end
		end
		DEFAULT_CHAT_FRAME:AddMessage(msg);
	end
end


function AutoBar:StateChanged(newState)
	DEFAULT_CHAT_FRAME:AddMessage(self:GetName().. ": " .. tostring(self:GetAttribute("state")));
end

-- Create the buttons and popups
function AutoBar:LayoutInitialize()
	local gapping = AutoBar.display.gapping;
	local buttonWidth = AutoBar.display.buttonWidth;
	local buttonHeight = AutoBar.display.buttonHeight;

--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:LayoutInitialize gapping " .. tostring(gapping) .. " / " .. tostring(buttonWidth) .. " / " .. tostring(buttonHeight), 1, 0.5, 0);

	-- The main driver.  It's draghandle child allows repositioning
	local p = _G["AutoBarSSHeaderFrame"];
	-- State 0 shows the slot buttons but no popups
	p:SetAttribute("statemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":$input");
	p:SetAttribute("delaystatemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":0");
	p:SetAttribute("delaytimemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":0.2");
	p:SetAttribute("delayhovermap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":true");
	p:SetAttribute("state-popup", "0");
	p:SetAttribute("statemap-popup", "*:0");

--p.StateChanged = AutoBar.StateChanged;
	AutoBar.ssHeader = p;

	-- Hook up AutoBarFrame components so we can do docking
	AutoBarFrame:SetAttribute("addchild", AutoBarSSHeaderFrame);
	AutoBarFrame:SetAttribute("addchild", AutoBarAnchorFrameHandle);
	AutoBarAnchorFrameHandle:SetAttribute("ofspoint", "*:CENTER");
	AutoBarAnchorFrameHandle:SetAttribute("ofsrelpoint", "*:CENTER");
	AutoBarAnchorFrameHandle:SetAttribute("ofsx", 0);
	AutoBarAnchorFrameHandle:SetAttribute("ofsy", 0);
	AutoBarSSHeaderFrame:SetAttribute("ofspoint", "*:CENTER");
	AutoBarSSHeaderFrame:SetAttribute("ofsrelpoint", "*:CENTER");
	AutoBarSSHeaderFrame:SetAttribute("ofsx", 0);
	AutoBarSSHeaderFrame:SetAttribute("ofsy", 0);

	-- Create the slot buttons
	AutoBar.ssButtons = {};
	for i = 1, AUTOBAR_MAXBUTTONS do
		local button = CreateFrame("CheckButton", "AutoBarSAB" .. i, p, "AutoBarSAButtonTemplate, SecureAnchorEnterTemplate");
		AutoBar.ssButtons[i] = button;

		button:SetAttribute("newstate","0:"..i..";1-"..AUTOBAR_MAXBUTTONS + AUTOBAR_SHIFTSTATE..":0")
		-- Set 0 second delay before returning to state 0 so keybindings dont open the popup
		button:SetAttribute("delaystate", "0:0")
		button:SetAttribute("delaytime", "0:0.1")
		button:SetAttribute("childraise", true);
		button:RegisterForClicks("LeftButtonUp", "RightButtonUp");
--button:RegisterForDrag("LeftButton", "RightButton")
		p:SetAttribute("addchild", button);
	end

	-- Create the popup buttons and slave headers to control them
	AutoBar.ssPopupHeaders = {};
	AutoBar.ssPopupButtons = {};
	for i = 1, AUTOBAR_MAXBUTTONS do
		local s = CreateFrame("Frame", "AutoBarSSPopupHeaderFrame"..i, p, "SecureStateHeaderTemplate");
		AutoBar.ssPopupHeaders[i] = s;
		s:SetAttribute("statemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":$input");
		s:SetAttribute("delaystatemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":0");
		s:SetAttribute("delaytimemap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":0.2");
		s:SetAttribute("delayhovermap-anchor", "0-"..AUTOBAR_MAXBUTTONS..":true");

		s:SetAttribute("state-parent", 0);
		s:SetAttribute("statemap-parent", "*:"..tostring(i));
		s:SetAttribute("exportstate", "popup");

--s.StateChanged = AutoBar.StateChanged;
		p:SetAttribute("addchild", s);

		s:SetAttribute("ofspoint", "*:CENTER");
		s:SetAttribute("ofsrelpoint", "*:CENTER");
		s:SetAttribute("ofsx", 0);
		s:SetAttribute("ofsy", 0);
		s:SetAttribute("state", 0);
		s:SetAttribute("showstates", tostring(i));
		AutoBar.ssButtons[i]:SetAttribute("anchorchild", s);

		AutoBar.ssPopupButtons[i] = {};
		local popupButtons = AutoBar.ssPopupButtons[i];
		for popupButtonIndex = 1, AUTOBAR_MAXPOPUPBUTTONS do
			local popupButton = CreateFrame("CheckButton", "AutoBarSAB" .. i .. "P" .. popupButtonIndex, AutoBar.ssButtons[i], "AutoBarSAPopupButtonTemplate");
			popupButtons[popupButtonIndex] = popupButton;

			popupButton:SetAttribute("newstate", 0);
			popupButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
			s:SetAttribute("addchild", popupButton);
		end
	end

	AutoBar.buttonLocations = {};
	for i = 1, AUTOBAR_MAXBUTTONS do
		AutoBar.buttonLocations[i] = {};
	end

--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:LayoutInitialize ssButtons " .. tostring(AutoBar.ssButtons) .. " / " .. tostring(AutoBar.ssButtons[1]));
end


-- Arrange the buttons using the various settings and alignment options
function AutoBar:LayoutUpdate()
	local rows = AutoBar.display.rows;
	local columns = AutoBar.display.columns;
	local gapping = AutoBar.display.gapping;
	local buttonWidth = AutoBar.display.buttonWidth;
	local buttonHeight = AutoBar.display.buttonHeight;
	local centerShiftX = 0;
	local centerShiftY = 0;
	local point = "BOTTOMLEFT";
	local x = buttonWidth + gapping;
	local y = buttonHeight + gapping;

	local displayedButtons = AutoBar:AssignButtons(rows * columns);
	local displayedColumns = math.min(displayedButtons, columns);
	local displayedRows = math.floor((displayedButtons - 1) / columns) + 1;
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:LayoutUpdate buttons " .. displayedButtons .. " columns " .. tostring(displayedColumns) .. " Rows " .. tostring(displayedRows));

	if (AutoBar.display.alignButtons == 1) then
		point = "BOTTOMLEFT";
	elseif (AutoBar.display.alignButtons == 2) then
		centerShiftX = -0.5 * displayedColumns * (buttonWidth + gapping) + gapping / 2;
		point = "BOTTOMLEFT";
	elseif (AutoBar.display.alignButtons == 3) then
		x = x * -1;
		point = "BOTTOMRIGHT";
	elseif (AutoBar.display.alignButtons == 4) then
		x = x * -1;
		point = "BOTTOMRIGHT";
		centerShiftY = -0.5 * displayedRows * (buttonHeight + gapping) + gapping / 2;
	elseif (AutoBar.display.alignButtons == 5) then
		point = "BOTTOMLEFT";
		centerShiftX = -0.5 * displayedColumns * (buttonWidth + gapping) + gapping / 2;
		centerShiftY = -0.5 * displayedRows * (buttonHeight + gapping) + gapping / 2;
	elseif (AutoBar.display.alignButtons == 6) then
		point = "BOTTOMLEFT";
		centerShiftY = -0.5 * displayedRows * (buttonHeight + gapping) + gapping / 2;
	elseif (AutoBar.display.alignButtons == 7) then
		x = x * -1;
		y = y * -1;
		point = "TOPRIGHT";
	elseif (AutoBar.display.alignButtons == 8) then
		y = y * -1;
		point = "TOPLEFT";
		centerShiftX = -0.5 * displayedColumns * (buttonWidth + gapping) + gapping / 2;
	elseif (AutoBar.display.alignButtons == 9) then
		y = y * -1;
		point = "TOPLEFT";
	end

	local i, button, effectiveButton, popupHeader;
	local displayButton = 1;
	local keys = AutoBarProfile:GetKeys();
	for i = 1, AUTOBAR_MAXBUTTONS, 1 do
		button = AutoBar.ssButtons[i];

		AutoBar:ButtonSetup("AutoBarSAB"..i, keys[i]);
		AutoBar.ssPopupHeaders[i]:SetFrameStrata("DIALOG");

		-- Set the relative positions of the buttons
		AutoBar.buttonLocations[i].x = (math.fmod(i - 1, columns) * x + centerShiftX);
		AutoBar.buttonLocations[i].y = math.floor((i - 1) / columns) * y + centerShiftY;
		button:SetAttribute("ofspoint", "*:"..point);
		button:SetAttribute("ofsrelpoint", "*:".."CENTER");

		popupHeader = AutoBar.ssPopupHeaders[i];
		if (AutoBar.display.popupOnShift) then
			button:SetAttribute("childstate", "^" .. tostring(i));
			button:SetAttribute("shift-childstate", "^" .. tostring(i) + AUTOBAR_SHIFTSTATE);
			popupHeader:SetAttribute("statemap-shift-1", tostring(i)..":"..(tostring(i) + AUTOBAR_SHIFTSTATE));
			popupHeader:SetAttribute("statemap-shift-0", (tostring(i) + AUTOBAR_SHIFTSTATE)..":"..tostring(i));
		else
			button:SetAttribute("childstate", "^" .. tostring(i));
			popupHeader:SetAttribute("statemap-shift-1", nil);
			popupHeader:SetAttribute("statemap-shift-0", nil);
		end

		local popupButtons = AutoBar.ssPopupButtons[i];
		for popupButtonIndex = 1, AUTOBAR_MAXPOPUPBUTTONS do
			local popupButton = popupButtons[popupButtonIndex];

			popupButton:SetAttribute("ofspoint", "*:"..point);
			popupButton:SetAttribute("ofsrelpoint", "*:".."CENTER");
		end
	end

	AutoBar:ButtonsUpdate();
	AutoBar:UpdateAnchor(displayedButtons);
	AutoBar.ssHeader:SetAttribute("state", "0");
end


-- Handle anchor docking / positioning
function AutoBar:UpdateAnchor(displayedButtons)
	local rows = AutoBar.display.rows;
	local columns = AutoBar.display.columns;
	local gapping = AutoBar.display.gapping;
	local buttonWidth = AutoBar.display.buttonWidth;
	local buttonHeight = AutoBar.display.buttonHeight;
	local displayedColumns = math.min(displayedButtons, columns);
	local displayedRows = math.floor((displayedButtons - 1) / columns) + 1;
	local autoBarAnchorFrameHandle = _G["AutoBarAnchorFrameHandle"];

	autoBarAnchorFrameHandle:SetChecked(AutoBar.display.frameLocked);

	local dockShiftX = AutoBar.display.dockShiftX;
	local dockShiftY = AutoBar.display.dockShiftY;

	if (AutoBar.display.docking == "CharacterMicroButton") then
		AutoBarSSHeaderFrame:SetFrameStrata("HIGH");
		autoBarAnchorFrameHandle:SetFrameStrata("DIALOG");
	else
		AutoBarSSHeaderFrame:SetFrameStrata("LOW");
		autoBarAnchorFrameHandle:SetFrameStrata("MEDIUM");
	end

	if (AutoBar.display.docking and _G[AutoBar.display.docking]) then
		local offset = AutoBar.dockingFrames[AutoBar.display.docking].offset;
		AutoBarFrame:SetAttribute("headofspoint", "*:"..offset.point);
		AutoBarFrame:SetAttribute("headofsrelpoint", "*:"..offset.relative);
		AutoBarFrame:SetAttribute("headofsx", dockShiftX + offset.x);
		AutoBarFrame:SetAttribute("headofsy", dockShiftY + offset.y);
		AutoBarFrame:SetParent(_G[AutoBar.display.docking]);
	elseif (AutoBar.display.position) then
		AutoBarFrame:SetAttribute("headofspoint", "*:CENTER");
		AutoBarFrame:SetAttribute("headofsrelpoint", "*:screen");
		AutoBarFrame:SetAttribute("headofsx", AutoBar.display.position.x);
		AutoBarFrame:SetAttribute("headofsy", AutoBar.display.position.y);
		AutoBarFrame:SetParent("UIParent");
	else
		AutoBarFrame:SetAttribute("headofspoint", "*:CENTER");
		AutoBarFrame:SetAttribute("headofsrelpoint", "*:screen");
		AutoBarFrame:SetAttribute("headofsx", 300);
		AutoBarFrame:SetAttribute("headofsy", 300);
		AutoBarFrame:SetParent("UIParent");
	end
	AutoBarFrame:Show();
	AutoBarFrame:SetAttribute("state", 0);

	if (AutoBar.display.hideDragHandle) then
		autoBarAnchorFrameHandle:SetAttribute("showstates", "!*");
		autoBarAnchorFrameHandle:Hide();
	else
		autoBarAnchorFrameHandle:SetAttribute("showstates", "*");
		autoBarAnchorFrameHandle:Show();
	end
end


-- Set the visual look and feel for the button
function AutoBar:ButtonSetup(baseName, keyBindings)
	local button = _G[baseName];
	local buttonWidth = AutoBar.display.buttonWidth;
	local buttonHeight = AutoBar.display.buttonHeight;
	local fontScale = buttonWidth / 36;
	local alpha = AutoBar.display.alpha / 10;

	local normalTexture = _G[baseName.."NormalTexture"];
	local countText = _G[baseName.."Count"];
	local hotKey = _G[baseName.."HotKey"];
	local cooldown = _G[baseName.."Cooldown"];
	local icon = _G[baseName.."Icon"];

	button:SetAlpha(alpha);
	normalTexture:SetAlpha(alpha);
	button:SetWidth(buttonWidth);
	button:SetHeight(buttonHeight);
	button:SetScale(fontScale);

	if (AutoBar.display.plainButtons) then
		button:SetNormalTexture("");
		icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
	else
		button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
		icon:SetTexCoord(0,1,0,1)
		normalTexture:SetWidth(buttonWidth * 1.833);	-- Mmm what is this magical scaling factor?
		normalTexture:SetHeight(buttonHeight * 1.833);
	end

	local fonttext, fontsize, fontoptions;
	if (AutoBar.display.hideKeyText) then
		hotKey:Hide();
	else
		fonttext, fontsize, fontoptions = hotKey:GetFont();
--		hotKey:SetFont(fonttext, 12 * fontScale, fontoptions);
		hotKey:SetJustifyH("LEFT");
		hotKey:SetJustifyV("TOP");
		hotKey:SetPoint("TOPLEFT", baseName, "TOPLEFT", 2, -2);
		if (keyBindings) then
			if (keyBindings[2]) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonSetup text RightButton "..baseName..":"..tostring(keyBindings[2]));
				hotKey:SetText(AutoBar:GetHotkeyDisplayText(keyBindings[2]));
			end
			if (keyBindings[1]) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonSetup text LeftButton "..baseName..":"..tostring(keyBindings[1]));
				hotKey:SetText(AutoBar:GetHotkeyDisplayText(keyBindings[1]));
			end
		end
		hotKey:Show();
	end
	if (keyBindings) then
		if (keyBindings[2]) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonSetup RightButton "..baseName..":"..tostring(keyBindings[2]));
			SetOverrideBindingClick(AutoBar.ssHeader, false, keyBindings[2], baseName, "RightButton")
			hotKey:SetText(AutoBar:GetHotkeyDisplayText(keyBindings[2]));
		end
		if (keyBindings[1]) then
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:ButtonSetup LeftButton "..baseName..":"..tostring(keyBindings[1]));
			SetOverrideBindingClick(AutoBar.ssHeader, false, keyBindings[1], baseName, "LeftButton")
			hotKey:SetText(AutoBar:GetHotkeyDisplayText(keyBindings[1]));
		end
	end
	if (AutoBar.display.hideCount) then
		countText:Hide();
	else
		countText:Show();
		fonttext, fontsize, fontoptions = countText:GetFont();
		countText:SetFont(fonttext, 14 * fontScale, fontoptions);
	end

	cooldown:SetScale(math.max(buttonWidth-1, buttonHeight-1) / 36);
end


-- Handle a click on a button
function AutoBar:ButtonPostClick(mousebutton)
	local button = this;
	button:SetChecked(false);
end


--
-- Popup Buttons
--

-- Handle a click on a popped up button
function AutoBar:PopupButtonPostClick(mousebutton)
	local popupButton = this;
	local buttonsIndex = popupButton:GetAttribute("buttonsIndex");
	local buttonInfo = AutoBar.buttons[buttonsIndex];

	popupButton:SetChecked(false);
--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:PopupButtonPostClick buttonsIndex " .. buttonsIndex);
	if (buttonInfo.arrangeOnUse and not InCombatLockdown()) then
		local popupButtonIndex = popupButton:GetAttribute("popupButtonIndex");
		local currentItems = AutoBar_Buttons_CurrentItems[buttonsIndex][popupButtonIndex];
		local index;
		local _, itemId = AutoBar.LinkDecode(GetContainerItemLink(currentItems.items[1][1], currentItems.items[1][2]));
		local category = popupButton:GetAttribute("category");
		for index = 1, AUTOBAR_MAXSLOTCATEGORIES, 1 do
			if (buttonInfo[index] == category) then
				-- First arrange the slot categories
				local targetIndex = table.maxn(buttonInfo);
				local temp = buttonInfo[index];
				buttonInfo[index] = buttonInfo[targetIndex];
				buttonInfo[targetIndex] = temp;

--DEFAULT_CHAT_FRAME:AddMessage("arrangeOnUse start " .. category .. " / " .. itemId);
				-- Arrange the category if allowed
				if (AutoBar_Category_Info[category] and AutoBar_Category_Info[category].arrangeOnUse) then
					local categoryList = AutoBar_Category_Info[category].items;
					for i, categoryItemId in ipairs(categoryList) do
--DEFAULT_CHAT_FRAME:AddMessage("arrangeOnUse ".. i .. " / " .. categoryItemId);
						if (categoryItemId == itemId) then
							local temp = categoryList[i];
--DEFAULT_CHAT_FRAME:AddMessage("arrangeOnUse ".. temp);
							table.remove(categoryList, i);
							table.insert(categoryList, temp);
							break;
						end
					end
				end
				AutoBar.ConfigChanged();
				break;
			end
		end
	end
end


--
-- Drag Handle
--

-- Lock & Unlock the frame on left click, and toggle config dialog with right click
function AutoBar:ClickHandle(button)
	local function RelockActionBars()
		self.display.frameLocked = true;
		if (AutoBar.display.lockActionBars) then
			LOCK_ACTIONBAR = "1";
		end
		_G["AutoBarAnchorFrameHandle"]:SetChecked(true);
	end

	if (button == "RightButton") then
		AutoBarConfig_Toggle();
		this:SetChecked(AutoBar.display.frameLocked);
	elseif (button == "LeftButton") then
		AutoBar.display.frameLocked = not AutoBar.display.frameLocked;
		if (AutoBar.display.frameLocked) then
			if (AutoBar.display.lockActionBars) then
				LOCK_ACTIONBAR = "1";
			end
		else
			if (AutoBar.display.lockActionBars) then
				LOCK_ACTIONBAR = "0";
			end
			self:ScheduleEvent("AutoBarTemporaryUnlock", RelockActionBars, 30);
		end
		this:SetChecked(AutoBar.display.frameLocked);
	end
end


-- Start dragging if not locked
function AutoBar:DragStart()
	if (not AutoBar.display.frameLocked) then
		_G["AutoBarFrame"]:StartMoving();
	end
end


-- End dragging
function AutoBar:DragStop()
	_G["AutoBarFrame"]:StopMovingOrSizing();
	AutoBar.display.position = {};
	AutoBar.display.position.x,
	AutoBar.display.position.y = _G["AutoBarAnchorFrameHandle"]:GetCenter();
	AutoBar.display.docking = nil;

--	AutoBar:LayoutUpdate();
end

--DEFAULT_CHAT_FRAME:AddMessage("AutoBar:DragStop" .. frame:GetName() .. "x/y " .. tostring(AutoBar.display.position.x).. "/" ..tostring(AutoBar.display.position.y), 1, 0.5, 0);
