local E = select(2, ...) -- Engine
local AB,CO,L = E:LoadModules("Actionbars", "Config", "Locale")

local _, Masque, MasqueGroup
local StanceBarReady		= false
local db = {}

local LAB10 = LibStub("LibActionButton-1.0")

AB.ActionBars				= {}
AB.ActionButtons 			= {}
AB.ActionBarHandles			= {}
AB.SkipCreatingActionBar	= {7,9,10} -- To prevent creation of uneccesary bars (stance bars). We will switch them to bar 1 already
AB.ActionBarsSkipped		= 0
AB.CurrentActionSlotHovered = 0

AB.ACTIONBUTTON_SIZE 						= 40 -- X and Y size
AB.ACTIONBUTTON_GAP 						= 5 -- X gap
AB.ACTIONBAR_NUM							= 10 -- Everything above bar 7 is already reserved by shapeshift buttons. Use with caution
AB.ACTIONBAR_NUM_BUTTONS					= 12

AB.ACTIONBUTTON_TEXTURE_BACKDROP			= [[Interface\AddOns\CUI\Textures\buttons\ActionButton1Backdrop]]
AB.ACTIONBUTTON_TEXTURE_HIGHLIGHT			= [[Interface\AddOns\CUI\Textures\buttons\ActionButton1Highlight]]
AB.ACTIONBUTTON_TEXTURE_PUSHED				= [[Interface\AddOns\CUI\Textures\buttons\ActionButton1Pushed]]
AB.ACTIONBUTTON_TEXTURE_BORDER				= [[Interface\AddOns\CUI\Textures\buttons\ActionButton1Border]]



AB.E = CreateFrame("Frame")
AB.E.rangeTimer = 0

E:RegisterEvents(AB.E, "CVAR_UPDATE","TRADE_SKILL_CLOSE", "ACTIONBAR_UPDATE_USABLE", "PLAYER_MOUNT_DISPLAY_CHANGED", "UPDATE_BONUS_ACTIONBAR", "UPDATE_VEHICLE_ACTIONBAR", "UPDATE_OVERRIDE_ACTIONBAR", "ACTIONBAR_PAGE_CHANGED", "UPDATE_MACROS", "ADDON_LOADED", "PLAYER_TARGET_CHANGED", "PLAYER_ENTERING_WORLD", "ACTIONBAR_SLOT_CHANGED", "UPDATE_SHAPESHIFT_FORM", "ACTIONBAR_UPDATE_COOLDOWN", "SPELL_UPDATE_COOLDOWN", "LOSS_OF_CONTROL_ADDED", "LOSS_OF_CONTROL_UPDATE")

-- Template example
--[[
NoTemplate = CreateFrame
CreateFrame = function(arg1,arg2,arg3,arg4,...)
if arg4 == "MyCloseButtonTemplate" then
	local x = NoTemplate(arg1,arg2,arg3,nil,...) 
	x:SetScript("OnClick", function(self) self:GetParent():Hide() end)
	x:SetNormalTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Up")
	x:SetPushedTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Down")
	x:SetHighlightTexture("Interface\\Buttons\\UI-Panel-MinimizeButton-Highlight")
	x:SetSize(32,32)
	x:SetFrameLevel(50);
	return x
else
return NoTemplate(arg1,arg2,arg3,arg4,...)
end
end]]--


AB.Bindings = {
	[1] = {
		["binding"] = "ACTIONBUTTON",
		["page"] = 1,
	},
	[2] = {
		["binding"] = "MULTIACTIONBAR2BUTTON",
		["page"] = 5,
	},
	[3] = {
		["binding"] = "MULTIACTIONBAR1BUTTON",
		["page"] = 6,
	},
	[4] = {
		["binding"] = "MULTIACTIONBAR4BUTTON",
		["page"] = 4,
	},
	[5] = {
		["binding"] = "MULTIACTIONBAR3BUTTON",
		["page"] = 3,
	},
	[6] = {
		["binding"] = "EXTRABAR6BUTTON",
		["page"] = 2,
	},
	[7] = {
		["binding"] = "EXTRABAR7BUTTON",
		["page"] = 8,
	},
	[8] = {
		["binding"] = "EXTRABAR8BUTTON",
		["page"] = 7,
	},
	[9] = {
		["binding"] = "EXTRABAR9BUTTON",
		["page"] = 9,
	},
	[10] = {
		["binding"] = "EXTRABAR10BUTTON",
		["page"] = 10,
	},
}

-- @TODO:
-- Add the other blizzard actionbars
AB.BlizzToABBars = {
	["MultiBarBottomRight"] = 4,
	["MultiBarBottomLeft"] = 5,
	["MultiBarRight"] = 2,
	["MultiBarLeft"] = 3,
	
}

function AB:CreatePetActionBar()
	local Button, ButtonName
	local BarName = "CUI_PetActionbar"
	local Bar = CreateFrame("Frame", BarName, E.Parent, "SecureHandlerStateTemplate")
	
	AB.ActionBars[BarName] = Bar
	
	Bar:SetPoint("CENTER", E.Parent, "CENTER")
	Bar:SetSize((32 + 3) * NUM_PET_ACTION_SLOTS, 32)
	
	for i=1, NUM_PET_ACTION_SLOTS do
		Button = _G["PetActionButton" .. i]
		Bar[string.format("Button%s", i)] = Button
		
		AB.ActionButtons["PetActionButton" .. i] = Button
		-------------------------------------------

		Button.isPetButton = true
		
		Button:SetSize(32, 32)
		Button:ClearAllPoints()
		Button:SetParent(Bar)
		Button:SetPoint("LEFT", Bar, "LEFT", (32 + 3) * (i - 1), 0)
		
		Button:Show()
	end
	
	Bar:SetAttribute("_onstate-visible", [[
		if newstate == 1 then
			self:Show();
		else
			self:Hide();
		end
	]]);
	
	-- Bar:Hide()
	-- /dump _G["PetActionButton1"]:GetParent():IsVisible()
	
	E:CreateMover(Bar, "Pet Actionbar")
end

function AB:UpdateActionButtonStyle(Button)
	local Update, ClassColor, db
	ClassColor = E:GetUnitClassColor("player")
	
	db = CO.db.profile.actionbar["global"]
	
	Update = function(Button)
		
		local HighlightTexture, NormalTexture, PushedTexture, CheckedTexture, ButtonName, _
		
		HighlightTexture = Button:GetHighlightTexture()
		NormalTexture = Button:GetNormalTexture()
		PushedTexture = Button:GetPushedTexture()
		CheckedTexture = Button:GetCheckedTexture()
		ButtonName = E:GetFullFrameName(Button)
	
		-- Button border is included within the icons themselves (WHY, BLIZZARD?!)
		Button.icon:SetTexCoord(0.06,0.94,0.06,0.94)
		Button:SetNormalTexture(AB.ACTIONBUTTON_TEXTURE_BACKDROP)
		Button:SetHighlightTexture(AB.ACTIONBUTTON_TEXTURE_HIGHLIGHT)
		Button:SetPushedTexture(AB.ACTIONBUTTON_TEXTURE_PUSHED)
		Button:SetCheckedTexture(AB.ACTIONBUTTON_TEXTURE_PUSHED)
		Button.Border:SetTexture(AB.ACTIONBUTTON_TEXTURE_BORDER)
		Button.Border:SetTexCoord(0,1,0,1)
		HighlightTexture:SetTexCoord(0,1,0,1)
		PushedTexture:SetTexCoord(0,1,0,1)
		CheckedTexture:SetTexCoord(0,1,0,1)
		
		if E:DoesStringPartExist(ButtonName, "Stance") then
			NormalTexture:SetTexCoord(1,2,1,2) -- Alternate Tex Coord for smaller buttons
		else
			NormalTexture:SetTexCoord(0,1,0,1)
		end
		
		Button.icon:SetDrawLayer("ARTWORK", 0)
		
		PushedTexture:SetDrawLayer("BACKGROUND", 0)
		Button.Border:ClearAllPoints()
		Button.Border:SetPoint("CENTER", Button, "CENTER", 0, 0)
		
		NormalTexture:ClearAllPoints()
		NormalTexture:SetPoint("CENTER", Button, "CENTER", 0, 0)
		NormalTexture:SetDrawLayer("BACKGROUND", 0)
		
		PushedTexture:SetDrawLayer("OVERLAY", 0)
		
		
		Button.Border:SetSize(Button:GetWidth()+6,Button:GetHeight()+6)
		NormalTexture:SetSize(Button:GetWidth()+6,Button:GetHeight()+6)
		HighlightTexture:SetSize(Button:GetWidth()+6,Button:GetHeight()+6)
		PushedTexture:SetSize(Button:GetWidth()+6,Button:GetHeight()+6)
		CheckedTexture:SetSize(Button:GetWidth()+6,Button:GetHeight()+6)
		
		NormalTexture:SetBlendMode(db["normalTextureBlendMode"]) -- DISABLE for fully opaque background. ADD for transparent but a little too light background
		Button.Border:SetBlendMode(db["borderTextureBlendMode"])
		HighlightTexture:SetBlendMode(db["highlightTextureBlendMode"])
		PushedTexture:SetBlendMode(db["pushedTextureBlendMode"])
		CheckedTexture:SetBlendMode(db["pushedTextureBlendMode"])
		
		NormalTexture:SetVertexColor(db["normalTextureColor"].r, db["normalTextureColor"].g, db["normalTextureColor"].b, db["normalTextureColor"].a)
		Button.Border:SetVertexColor(db["borderTextureColor"].r, db["borderTextureColor"].g, db["borderTextureColor"].b, db["borderTextureColor"].a)
		HighlightTexture:SetVertexColor(db["highlightTextureColor"].r, db["highlightTextureColor"].g, db["highlightTextureColor"].b, db["highlightTextureColor"].a)
		PushedTexture:SetVertexColor(db["pushedTextureColor"].r, db["pushedTextureColor"].g, db["pushedTextureColor"].b, db["pushedTextureColor"].a)
		CheckedTexture:SetVertexColor(db["pushedTextureColor"].r, db["pushedTextureColor"].g, db["pushedTextureColor"].b, db["pushedTextureColor"].a)
		
		--Button.Border:SetVertexColor(ClassColor[1], ClassColor[2], ClassColor[3], 0.75)
		--NormalTexture:SetVertexColor(ClassColor[1], ClassColor[2], ClassColor[3], 0.75)
		---HighlightTexture:SetVertexColor(ClassColor[1], ClassColor[2], ClassColor[3], 1)
		
		Button.Border:Show()
	end
	
	if not (CO.db.profile.actionbar.useMasque == true and Masque) then
		if Button then			
				Update(Button)
		else
			for _, Button in pairs(AB.ActionButtons) do
				Update(Button)
			end
		end
	end
end

function AB:ReassignBindings()
	for _, Bar in pairs(AB.ActionBars) do
		AB:UpdateConfig(Bar)
	end
end

function AB:CreateBarHandles()
	local Frame, RawName, Name, BarNum, Backdrop, Font, BarProfile

	for _, BarFrame in pairs(AB.ActionBars) do
		RawName, BarNum = E:ExtractDigits(E:GetFullFrameName(BarFrame))
		Name = "BarHandle" .. BarNum
		Frame = CreateFrame("Frame", Name, BarFrame)
		AB.ActionBarHandles[Name] = Frame
		
		Frame:ClearAllPoints()
		Frame:SetPoint("CENTER", BarFrame, "CENTER")
		Frame:EnableMouse(true)
		Frame:SetMovable(true)
		Frame:RegisterForDrag("LeftButton")
		
		Frame:SetScript("OnDragStart", function(self)
			local parent = self:GetParent()
			parent:SetMovable(true)
			self:SetClampedToScreen(false)
			parent:SetClampedToScreen(true)
			parent:StartMoving()
		end)
		Frame:SetScript("OnDragStop", function(self)
			local Parent = self:GetParent()
			local Name, BarNum = E:ExtractDigits(E:GetFullFrameName(Parent))
			
			-- Support for StanceBar
			if not E:DoesStringPartExist(Name, "Stance") then
				BarProfile = CO.db.profile.actionbar["bar" .. BarNum]
			else
				BarProfile = CO.db.profile.actionbar["stancebar"]
			end
			
			Parent:SetMovable(false)
			Parent:StopMovingOrSizing()
			
			local point, relativeTo, relativePoint, xOfs, yOfs = Parent:GetPoint()
			BarProfile["point"] = point	
			BarProfile["relativePoint"] = relativePoint
			BarProfile["xOffset"] = xOfs
			BarProfile["yOffset"] = yOfs
		end)
		
		Frame:SetWidth(BarFrame:GetWidth())
		Frame:SetHeight(BarFrame:GetHeight())
		
		Frame:SetBackdrop({bgFile = "Interface/Tooltips/UI-Tooltip-Background", 
                                            edgeFile = "", 
                                            tile = true, tileSize = 16, edgeSize = 16});
		Frame:SetBackdropColor(0,0.75,1,1);
		Frame:SetFrameLevel(100)
		
		Frame.Name = Frame:CreateFontString(nil, "ARTWORK")
		E:InitializeFontFrame(Frame.Name, "ARTWORK", "FRIZQT__.TTF", 14, {1,1,1}, 1, {0,0}, "", 100, 20, Frame, "CENTER", {1,1})
		Frame.Name:ClearAllPoints()
		Frame.Name:SetPoint("CENTER", Frame, 'CENTER', 5, -5)
		
		if BarNum and BarNum ~= "" then
			Frame.Name:SetText("Bar " .. BarNum)
		else
			Frame.Name:SetText(RawName)
		end
	end
end

function AB:UpdateBarHandles(state)
	local Frame, Name, BarNum, Backdrop, Font, Parent
	
	for _, Frame in pairs(AB.ActionBarHandles) do
		
		if state == "disable" then Frame:Hide() else
				
			Frame:Show()
			
			Parent = Frame:GetParent()
			
			Frame:ClearAllPoints()
			Frame:SetPoint("CENTER", Parent, "CENTER")
			Frame:EnableMouse(true)
			
			Frame:SetWidth(Parent:GetWidth() + 5)
			Frame:SetHeight(Parent:GetHeight() + 5)
			
			Frame:SetFrameLevel(100)
		end
	end
end


--[[
	Expected settings:
	
	- Enable / Disable
	- A scale multiplier (This also has to move the hotkey and macro texts)
	- Setting the actual gap
	- Initial anchor move handler
	- Buttons per row
	- Total Buttons
	
	Optional: 
	
	- Movable individual buttons
]]--
function AB:UpdateActionbar(bar)
	local index, self, name, moverName, profileName, kids, size, currentRow, currentColumn, profileData, profileMoverData, addSubtract, numDisabled, maxRow, maxColumn
	
	-- Support for StanceBar
	if bar ~= "stancebar" and bar ~= "petbar" then
		name = "CUI_ActionBar" .. bar
		profileName = "bar" .. bar
		
		moverName = name .. "Mover"
		
		self = AB.ActionBars[name]
	elseif bar == "stancebar" then
		name = "CUI_StanceBar"
		profileName = "stancebar"
		
		moverName = name .. "Mover"
		
		self = AB.ActionBars["CUI_StanceBar"] -- Direct use of Blizzard Stancebar
	elseif bar == "petbar" then
		profileName = "petbar"
		
		moverName = "CUI_PetActionbarMover"
		
		self = AB.ActionBars["CUI_PetActionbar"]
	end
	
	if not self or not CO.db.profile.actionbar[profileName] then return end
	-- At this point, the settings for this bar definetely exist
	profileData = CO.db.profile.actionbar[profileName]
	profileMoverData = CO.db.profile.movers[moverName]
	size = AB.ACTIONBUTTON_SIZE * profileData["buttonSizeMultiplier"]
	
	if not profileData["enable"] then self:Hide(); return else self:Show() end
	RegisterStateDriver(self, "visible", profileData.visibilityCondition)
	
	if tonumber(bar) then
		if bar > 1 then
			RegisterStateDriver(self, "page", AB.Bindings[bar].page)
		else
			RegisterStateDriver(self, "page", "[possessbar] 12; [overridebar] 14; [shapeshift] 13; [form, noform] 0; [bar:3] 3; [bar:4] 4; [bar:5] 5; [bar:6] 6; [bonusbar:1, nostealth] 7; [bonusbar:1,stealth] 7; [bonusbar:3] 9; [bonusbar:4] 10; 1")
		end
		
		self:SetAttribute("page", AB.Bindings[bar].page)
		
		AB:UpdateConfig(self)
	end
	
	numDisabled = 0
	currentRow = 0
	maxRow = 0
	currentColumn = 0
	maxColumn = 0
	
	kids = { self:GetChildren() };
	index = 1
	for _,child in pairs(kids) do
		--------------------------------------------------------------------
		
		if string.match(E:GetFullFrameName(child), "Button") then
			if GetNumShapeshiftForms() > 0 and profileName == "stancebar" then
				
				numDisabled = 12 - GetNumShapeshiftForms()
				
			elseif profileName ~= "stancebar" and profileName ~= "petbar" then
			
				if index > profileData["buttonNum"] then
					child:Hide(); child:SetAttribute("enable", false)
					numDisabled = numDisabled + 1
				else
					child:Show()
					child:SetAttribute("enable", true)
				end
			end
			
			child:SetSize(size,size)
			
			child:ClearAllPoints()
			
			if profileData["buttonsPerRow"] < 0 then
				addSubtract = -1
				child:SetPoint("TOPLEFT", self, "TOPLEFT")
			else
				addSubtract = 1
				child:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT")
			end
			
			-- We have to use the previous column and row values to make it work properly
			local xOffset = (size*(currentColumn)) + (profileData["buttonGap"] * currentColumn)
			local yOffset = ((size*(currentRow)) + (profileData["buttonGap"] * currentRow)) * addSubtract
			
			if numDisabled == 0 or profileName == "stancebar" then
				if currentRow > maxRow then maxRow = currentRow end
				if currentColumn > maxColumn then maxColumn = currentColumn end
			end
			
			-- If the current button should be in next row
			if index % profileData["buttonsPerRow"] == 0 then
				currentRow = currentRow + 1
				currentColumn = 0
			else
				currentColumn = currentColumn + 1
			end
			
			E:MoveFrame(child, xOffset, yOffset)
			
			--------------------------------------------------------------------
			index = index + 1
		end
	end
	
	self:SetWidth((size + profileData["buttonGap"]) * (maxColumn + 1) - profileData["buttonGap"])
	self:SetHeight((size + profileData["buttonGap"]) * (maxRow + 1) - profileData["buttonGap"])
	
	
	
	--self:ClearAllPoints()
	--self:SetPoint(profileMoverData["point"], AB.Parent, profileMoverData["point"], profileMoverData["xOffset"], profileMoverData["yOffset"])
	if E:GetMover(self) then
		if profileMoverData then
			E:RepositionMover(E:GetMover(self), profileMoverData["point"], profileMoverData["xOffset"], profileMoverData["yOffset"])
			E:UpdateMoverDimensions(self)
		else
			assert("No mover data found for " .. moverName)
		end
	end
end

function AB:MoveActionbutton(frame, xOffset, yOffset, xGap, yGap, index)
	if not index then index = 1 else index = index - 1 end
	E:MoveFrame(frame, (xOffset*index) + (xGap*index), (yOffset*index) + (yGap*index))
end

local function UpdateButtonState(self)
	if self.isPetButton then return end
	if IsCurrentAction(self.action) then
		self:SetChecked(true)
	else
		self:SetChecked(false)
	end
end

local function UpdateActionCount(self)
	if self.isPetButton then return end
	
	local text = self.Count
    local action = self.action
	
	if action then
		if ( IsConsumableAction(action) or IsStackableAction(action) or (not IsItemAction(action) and GetActionCount(action) > 0) ) then
			local count = GetActionCount(action);
			if ( count > (self.maxDisplayCount or 9999 ) ) then
				text:SetText("*");
			else
				text:SetText(count);
			end
		else
			local charges, maxCharges, chargeStart, chargeDuration = GetActionCharges(action);
			if (maxCharges > 1) then
				text:SetText(charges);
			else
				text:SetText("");
			end
		end
	end
end

local function ActionButtonDown(id)
	if CheckPetActionButtonEvent(id, true) then
		return;
	end

	local button = GetActionButtonForID(id);
	if button then
		if button:GetButtonState() == "NORMAL" then
			button:SetButtonState("PUSHED");
		end

		CheckUseActionButton(button, true);
	end
end

local function ActionButtonUp(id)
	if CheckPetActionButtonEvent(id, false) then
		return;
	end

	local button = GetActionButtonForID(id);
	if button then
		if ( button:GetButtonState() == "PUSHED" ) then
			button:SetButtonState("NORMAL");
			CheckUseActionButton(button, false);
		end
	end
end

function AB:CreateActionBars()

	local actionBar, buttonName, buttonData, actionButton, dragStart, dragStop, hotkey, multiBarOffset, key, text
	local currentButtonIndex = 1
	

	for b=1, AB.ACTIONBAR_NUM do
		
		--if not E:tableContainsValue(AB.SkipCreatingActionBar, b) then
		
			-- type, name, strata, sizeX, sizeY, point, parent, enablemouse, enablemousewheel, enablekeyboard
			--local actionBar = E:NewFrame("Frame", "CUI_ActionBar" .. b, "MEDIUM", (AB.ACTIONBUTTON_SIZE + 5)*(12), AB.ACTIONBUTTON_SIZE, _, AB.Parent)
			actionBar = CreateFrame("Frame", "CUI_ActionBar" .. b, E.Parent, 'SecureHandlerStateTemplate')
			actionBar:SetFrameRef("MainMenuBarArtFrame", MainMenuBarArtFrame)
			actionBar:SetWidth((AB.ACTIONBUTTON_SIZE + AB.ACTIONBUTTON_GAP)*(12) - 24)
			actionBar:SetHeight(AB.ACTIONBUTTON_SIZE)
			
			actionBar.buttons = {}
			actionBar.bindButtons = AB.Bindings[b].binding
			AB.ActionBars["CUI_ActionBar" .. b] = actionBar
	
			-- StateDriver is registered in the config
			actionBar:SetAttribute("_onstate-visible", [[
				if newstate == 1 then
					self:Show();
				else
					self:Hide();
				end
			]]);
			actionBar:SetAttribute("_onstate-page", [[
				self:SetAttribute("state", newstate)
				control:ChildUpdate("state", newstate)
			]])

			actionBar:SetPoint("CENTER", E.Parent, "CENTER", 0, (AB.ACTIONBUTTON_SIZE * (b - AB.ActionBarsSkipped) - 40) + (5*b))
			
			E:CreateMover(actionBar, L["actionbarFrame"] .. " " .. b)
		
			-- Create AB.ACTIONBAR_NUM_BUTTONS (12) buttons per bar
			for i=1, AB.ACTIONBAR_NUM_BUTTONS do
				
				buttonName = string.format("CUI_ActionBar%sButton%s", b, i)
				
				multiBarOffset = 0
				if b > 1 then multiBarOffset = 1 end
				
				--key = GetBindingKey("ACTIONBUTTON" .. currentButtonIndex) or GetBindingKey("MULTIACTIONBAR" .. AB.BarBindings[b - multiBarOffset] .. "BUTTON" .. i) or
				--GetBindingKey("CLICK " .. actionButton:GetName() .. ":LeftButton");
				
				actionButton = LAB10:CreateButton(i, buttonName, actionBar)
				AB.ActionButtons[buttonName] = actionButton
				
				for k = 1,14 do
					actionButton:SetState(k, "action", (k - 1) * 12 + i)
				end
				actionButton:SetState(0, "action", i)
				actionButton:SetAttribute("buttonlock", GetCVarBool('lockActionBars'))
				
				actionButton.index = i
				
				hooksecurefunc(actionButton.cooldown, "SetCooldown", AB.OnSetCooldown)
				actionButton.cooldown:SetScript("OnUpdate", AB.ActionButton_UpdateCooldownText)
				actionButton.cooldown:SetHideCountdownNumbers(true)
				
				actionButton.cooldown:Hide()
				
				UpdateActionCount(actionButton)
				if CO.db.profile.actionbar.useMasque == true and Masque then
					buttonData = {
						Icon = actionButton.icon,
						Cooldown = actionButton.cooldown,
						Normal = actionButton:GetNormalTexture(),
						Pushed  = actionButton:GetPushedTexture(),
						Border = actionButton.Border
					}
				
					MasqueGroup:AddButton(actionButton, buttonData)
				end
				
				function actionButton:SetKey(key)
					local BindButton = self:GetParent().bindButtons
					local ButtonIndex = self.index
					
					SetBinding(key, BindButton .. ButtonIndex)
					
					AB:ReassignBindings()
				end
				function actionButton:ClearBindings()
					local Key = string.format("%s%s", self:GetParent().bindButtons, self.index)
					
					
					SetBinding(GetBindingKey(Key), nil)
					
					AB:ReassignBindings()
				end
				
				actionBar.buttons[i] = actionButton
				
				currentButtonIndex = currentButtonIndex + 1
			end
			
			AB:UpdateConfig(actionBar)
		--else
		--	AB.ActionBarsSkipped = AB.ActionBarsSkipped + 1
		--	currentButtonIndex = currentButtonIndex + 12
		--end
	end
end

function AB:UpdateConfig(Bar)
	local Button, Binding, ButtonBinding, BarNum, BarProfile
	
	if self.keyRebind then return end
	
	if Bar.buttons then
		
		_, BarNum = E:ExtractDigits(Bar:GetName())
		BarProfile = CO.db.profile.actionbar[string.format("bar%s", BarNum)]
		
		if not Bar.buttonConfig then Bar.buttonConfig = {} end
		
		Bar.buttonConfig.outOfRangeColoring = "button"
		Bar.buttonConfig.tooltip = "enabled"
		Bar.buttonConfig.showGrid = BarProfile.showGrid
		Bar.buttonConfig.colors = { range = { 0.8, 0.1, 0.1 }, mana = { 0.5, 0.5, 1.0 } }
		Bar.buttonConfig.hideElements = { macro = false, hotkey = false, equipped = false }
		-- Bar.buttonConfig.keyBoundTarget = false
		Bar.buttonConfig.clickOnDown = false
		Bar.buttonConfig.flyoutDirection = "UP"
		
		ClearOverrideBindings(Bar)
		
		for i=1, NUM_ACTIONBAR_BUTTONS do
			Button = Bar.buttons[i]
			ButtonBinding = string.format("%s%s", Bar.bindButtons, i)
			Binding = GetBindingKey(ButtonBinding)
			
			if Binding then
				SetOverrideBindingClick(Bar, false, Binding, Button:GetName())
			end
			
			Bar.buttonConfig.keyBoundTarget = Binding
			
			Button:UpdateConfig(Bar.buttonConfig)
		end
	end
end

function AB:OnSetCooldown(start, duration)
	if start > 0 then
		self:Show()
	else
		self:Hide()
	end
end

local CDTextUpdate = 0.05
function AB:ActionButton_UpdateCooldownText(elapsed)

	-- if not self.CDEnable or not self.CDDuration then return end
	-- if not (self.duration and self.duration > 0) or not self.CDEnable or self.enable == 0 then return end
	--if not self.update then self.update = 0 end
	
	AB:CreateCooldownText(self)
	
	--self.update = self.update + elapsed
	--if self.update >= CDTextUpdate then
		self.durationRemaining = self.duration + (self.start - GetTime())
		
		if self.durationRemaining <= 0 then
			self.cooldownText:SetText('')
			
			return
		end
		if self.duration > 1.5 then
			self.timeRemaining = 0
			if self.durationRemaining > 10 then self.timeRemaining = E:FormatTime(self.durationRemaining); else self.timeRemaining = E:FormatTime(self.durationRemaining, 1); end
			self.cooldownText:SetText(self.timeRemaining)
		else
			self.cooldownText:SetText('')
		end
end

function AB:CreateCooldownText(self)
	--if self:GetParent().isPetButton then return end

	--[[local start, duration, enable, modRate
	local type, id, subType, spellID
	if self.action then
		type, id, subType, spellID = GetActionInfo(self.action)
	end
	
	if id then
		start, duration, enable, modRate = GetActionCooldown(self.action)
		
		if duration >= 5 then
			self.cooldown:SetDrawBling(true)
			self.cooldown:SetDrawEdge(true)
		else
			self.cooldown:SetDrawBling(false)
			self.cooldown:SetDrawEdge(false)
		end
		-- CooldownFrame_Set(self.cooldown, start, duration, enable, false, modRate)
		self.cooldown:SetCooldown(start, duration, modRate)
	end]]--
	
	--[[
	local locStart, locDuration
	local start, duration, enable, charges, maxCharges, chargeStart, chargeDuration
	local modRate = 1.0
	local chargeModRate = 1.0
	
	if (self.spellID) then
		locStart, locDuration = GetSpellLossOfControlCooldown(self.spellID)
		start, duration, enable, modRate = GetSpellCooldown(self.spellID)
		charges, maxCharges, chargeStart, chargeDuration, chargeModRate = GetSpellCharges(self.spellID)
	else
		if self.action then
			locStart, locDuration = GetActionLossOfControlCooldown(self.action)
			start, duration, enable, modRate = GetActionCooldown(self.action)
			charges, maxCharges, chargeStart, chargeDuration, chargeModRate = GetActionCharges(self.action)
		end
	end

	if locStart and ( (locStart + locDuration) > (start + duration) ) then
		if ( self.cooldown.currentCooldownType ~= COOLDOWN_TYPE_LOSS_OF_CONTROL ) then
			self.cooldown:SetEdgeTexture("Interface\\Cooldown\\edge-LoC");
			self.cooldown:SetSwipeColor(0.17, 0, 0);
			self.cooldown:SetHideCountdownNumbers(true);
			self.cooldown.currentCooldownType = COOLDOWN_TYPE_LOSS_OF_CONTROL;
		end

		CooldownFrame_Set(self.cooldown, locStart, locDuration, true, true, modRate);
		ClearChargeCooldown(self);
	else
		if ( self.cooldown.currentCooldownType ~= COOLDOWN_TYPE_NORMAL ) then
			self.cooldown:SetEdgeTexture("Interface\\Cooldown\\edge");
			self.cooldown:SetSwipeColor(0, 0, 0);
			self.cooldown:SetHideCountdownNumbers(false);
			self.cooldown.currentCooldownType = COOLDOWN_TYPE_NORMAL;
		end

		if locStart and ( locStart > 0 ) then
			self.cooldown:SetScript("OnCooldownDone", ActionButton_OnCooldownDone );
		end

		if ( charges and maxCharges and maxCharges > 1 and charges < maxCharges ) then
			StartChargeCooldown(self, chargeStart, chargeDuration, chargeModRate);
		else
			ClearChargeCooldown(self);
		end
		
		self.cooldown.enabled = enable
		self.cooldown.duration = duration
		self.cooldown.start = start
		
		CooldownFrame_Set(self.cooldown, start, duration, enable, false, modRate);
	end
	
	UpdateActionCount(self)]]
	
	if not self.cooldownText then
		self.cooldownText = self:CreateFontString(nil, "OVERLAY")
		E:InitializeFontFrame(self.cooldownText, "OVERLAY", "FRIZQT__.TTF", 12, {0.933, 0.886, 0.125}, 1, {0,0}, "", 100, 20, self, "CENTER", {1,1})
		E:SetFontInfo(self.cooldownText, nil, "THICKOUTLINE", nil, nil)
		E:UpdateFont(self.cooldownText)
		self.cooldownText:SetAllPoints(self)
		self.cooldownText:SetJustifyH("CENTER")
	end
end

local UsableIsUsable, UsableNotEnoughPower
local function ActionButton_UpdateUsable(self)
	UsableIsUsable, UsableNotEnoughPower = IsUsableAction(self.action);
	
	if ( UsableIsUsable ) then
		self.icon:SetVertexColor(1.0, 1.0, 1.0);
		-- normalTexture:SetVertexColor(1.0, 1.0, 1.0);
	elseif ( UsableNotEnoughPower ) then
		self.icon:SetVertexColor(0.5, 0.5, 1.0);
		-- normalTexture:SetVertexColor(0.5, 0.5, 1.0);
	else
		self.icon:SetVertexColor(0.4, 0.4, 0.4);
		-- normalTexture:SetVertexColor(1.0, 1.0, 1.0);
	end
end

local function ActionButton_OnCooldownDone(self)
	self:SetScript("OnCooldownDone", nil);
	ActionButton_UpdateCooldown(self:GetParent());
end

local function SetHotKeyColor(button, r,g,b)
	button.HotKey:SetVertexColor(r,g,b)
end

-- /dump CUI:GetModule("Actionbars"):UpdateActionButtonState()

-- Use a wrapper to make use more convenient
local StateButton, StateID, StateActionType
function AB:UpdateActionButtonState()
	StateButton, StateID, StateActionType = nil, nil, nil
	for object in pairs(AB.ActionButtons) do
		StateButton = AB.ActionButtons[object]
		
		if not StateButton.isPetButton then
		
			if StateButton:GetAttribute("enable") == true then
				StateActionType, StateID = GetActionInfo(StateButton.action)
				if StateID then
					if StateActionType == "spell" then					
						if UnitExists("target") and IsActionInRange(StateButton.action, "target") == false then
							SetHotKeyColor(StateButton, 1,0,0)
							StateButton.icon:SetVertexColor(0.5,0.5,0.5)
						else
							SetHotKeyColor(StateButton, 1,1,1)
							StateButton.icon:SetVertexColor(1,1,1)
						end
					end
				end
				
				if StateButton.action then
					ActionButton_UpdateUsable(StateButton)
				end
				-- AB:UpdateActionButtonStyle(StateButton) -- Causes memory to go up to the sky atm - NEED FIX
			end
		end
	end
end
 -- /run AB:UpdateButtonIcons()
-- Updates all buttons if limit is not specified
function AB:UpdateButtonIcons(limit)

	local button, texture, actionpage, buttonNum
	
	for k,v in pairs(AB.ActionButtons) do
		if limit then k = "CUI_ActionButton" .. limit end
		
		-- /run print(GetActionTexture(_G["CUI_ActionButton1"].action))
		
		if not string.match(k, "Stance") then
			
			button = AB.ActionButtons[k]
			_, buttonNum = E:ExtractDigits(k)
			buttonNum = tonumber(buttonNum)
			actionpage = button:GetParent():GetAttribute("actionpage")
			
			--[[
				Button action defines the action executed when CLICKING the button.
				Hotkeys simply execute their assigned slot. Our actionbars are merely for actually SEEING what we are about to use!
				The clou: We simply have to update the MainMenuBarArtFrame actionpage . . .
			]]
			if actionpage and HasBonusActionBar() then
				button.action = (12 * (6 + GetBonusBarOffset()) - 12) + buttonNum
			elseif buttonNum < 12 and UnitHasVehicleUI("player") then
				button.action = (12 * (GetVehicleBarIndex()) - 12) + buttonNum
			elseif actionpage then
				button.action = (12 * (actionpage) - 12) + buttonNum
			else
				button.action = buttonNum
			end
			
			--if button.action then texture = GetActionTexture(button.action); button:SetAttribute("action", button.action); button:SetAttribute("buttonIndex", button.action) end
			if button.action then texture = GetActionTexture(button.action);  end

			
			if button:GetAttribute("enable") == true then
				if not InCombatLockdown() then
					button:Show()
				end
				
				if texture then
					button.icon:SetTexture(texture)
					button.icon:Show()
					button.cooldown:Show()
					-- button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
					-- button.NormalTexture:SetTexCoord(0, 0, 0, 0)
				else
					button.icon:Hide()
					button.cooldown:Hide()
					-- button:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
					-- button.NormalTexture:SetTexCoord(0, 1, 0, 1)
					if button.HotKey:GetText() == RANGE_INDICATOR then
						button.HotKey:Hide()
					else
						button.HotKey:SetVertexColor(0.75, 0.75, 0.75)
					end
				end
				
				-- AB:UpdateActionButtonStyle(button)
			end
			
			if limit then return end
		end
	end
	
	AB:UpdateStanceBar()
end


local function ActionButton_CalculateAction(self, button)

	local page

	if ( not button ) then
		button = SecureButton_GetEffectiveButton(self);
	end
	if ( self:GetID() > 0 ) then
		page = SecureButton_GetModifiedAttribute(self, "actionpage", button);
		if ( not page ) then
			page = GetActionBarPage();
			if ( self.isExtra ) then
				page = GetExtraBarIndex();
			elseif ( self.buttonType == "MULTICASTACTIONBUTTON" ) then
				page = GetMultiCastBarIndex();
			end
		end
		return (self:GetID() + ((page - 1) * NUM_ACTIONBAR_BUTTONS));
	else
		return SecureButton_GetModifiedAttribute(self, "action", button) or 1;
	end
end

-- Do we even need this?
--[[
local function ActionButton_UpdateAction(self, force)

	if self:GetAttribute("enable") == false then return end

	local action = ActionButton_CalculateAction(self);
	
	if ( action ~= self.action or force ) then
		self.action = action
		
		SetActionUIButton(self, action, self.cooldown);
		AB:UpdateActionButtonStyle(self)
	end
end


local function ActionBarController_ResetToDefault(force)
	AB.ActionBars["CUI_ActionBar1"]:SetAttribute("actionpage", GetActionBarPage());
	for k, frame in pairs(AB.ActionButtons) do
		ActionButton_UpdateAction(frame, force);
	end
end]]

function AB:UpdateExtraBar()
	if not InCombatLockdown() then
		RegisterStateDriver(AB.ActionBars["CUI_ActionBar1"], "overrideBar", "[overridebar] 14;[vehicleui] 12;[possessbar] 13;[form:1] 1; [form:2] 2; [form:3] 3; [form:4] 4;[shapeshift] shapeshift; noform;")
	end
end

local function InitActionBarChange()
	--[[
		Here, it is ESSENTIAL to do the THREE following things withing the attribute function:
			- self:SetAttribute("state", PAGENUM)
			- self:ChildUpdate("state", PAGENUM)
			- self:GetFrameRef("MainMenuBarArtFrame"):SetAttribute("actionpage", PAGENUM)
			
		If we are missing just ONE of those things, the bar will NOT respond to the change (correctly)
		TL;DR: This was a pain in the beep to find out
	]]
	
	AB.ActionBars["CUI_ActionBar1"]:SetAttribute("_onstate-overrideBar", [[
		local changeTo = GetActionBarPage()
		
		-- print("newstate:", newstate)
		if newstate == 12 or newstate == 13 then
				changeTo = 12
		elseif newstate == 14 then
			if HasOverrideActionBar() then
				changeTo = GetOverrideBarIndex()
			end
		else
			if (newstate == "noform" or newstate == "shapeshift") then
				if HasTempShapeshiftActionBar() then
					changeTo = GetTempShapeshiftBarIndex()
				elseif HasOverrideActionBar() then
					changeTo = GetOverrideBarIndex()
				else
					changeTo = GetActionBarPage()
				end
            else
				if HasBonusActionBar() then
					changeTo = GetBonusBarIndex()
				else
					changeTo = GetActionBarPage()
				end
			end
		end
		
		-- print("changeTo:", changeTo)
		self:SetAttribute("state", changeTo)
		self:ChildUpdate("state", changeTo)
		self:GetFrameRef("MainMenuBarArtFrame"):SetAttribute("actionpage", changeTo)
	]]);
	
	
	-- /dump HasTempShapeshiftActionBar(), GetTempShapeshiftBarIndex(), HasOverrideActionBar(), GetOverrideBarIndex()
	-- local condition = "[form:0] noform; [form:0] noform; [form:1] 1; [form:2] 2; [form:4] 4; noform"
	-- SecureCmdOptionParse(condition)
	-- /run print(SecureCmdOptionParse("[form:0] noform; [form:0] noform; [form:1] 1; [form:2] 2; [form:4] 4; noform"))
	-- /dump SecureCmdOptionParse("[overridebar] 14;[vehicleui] 12;[possessbar] 12;[form:1] 1; [form:2] 2; [form:4] 4; noform;")
	-- /dump SecureCmdOptionParse("[shapeshift] shape; noform;")
	-- /dump SecureCmdOptionParse("[bonusbar:1] 1;[bonusbar:2] 2; [bonusbar:3] 3; [bonusbar:4] 4; [bonusbar:5] 5; [bonusbar:6] 6; noform;")
	-- /dump CUI:GetModule("Actionbars").ActionBars["CUI_ActionBar1"]:GetAttribute("state")
	-- /dump MainMenuBarArtFrame:GetAttribute("actionpage")
end

local function UpdateMacroTexts()
	
	local button, action, actionName
	
	for k,v in pairs(AB.ActionButtons) do
		
		button 			= AB.ActionButtons[k]
		action 			= button.action;
		actionName 		= button.Name;
		
		if actionName and action then
			if ( not IsConsumableAction(action) and not IsStackableAction(action) and (IsItemAction(action) or GetActionCount(action) == 0) ) then
				actionName:SetText(GetActionText(action));
			else
				actionName:SetText("");
			end
		end
	end
end

function AB:InitStanceBar()
	local Button
	local NumForms = GetNumShapeshiftForms()
	
	if NumForms > 0 then
		local Bar = CreateFrame("Frame", "CUI_StanceBar", E.Parent)
		Bar:SetPoint("CENTER", E.Parent, "CENTER")
		Bar:SetSize(200, 200)
		AB.ActionBars["CUI_StanceBar"] = Bar
		
		for i=1, NumForms do
			Button = _G["StanceButton" .. i]
			
			if Button then
				Button:SetParent(Bar)
				Button:ClearAllPoints()
				Button:SetPoint("LEFT", Bar, "LEFT", (32 + 5) * (i - 1), 0)
				
				Button:Show()
			end
		end
		
		StanceBarFrame:UnregisterAllEvents()
		StanceBarFrame:Hide()
		
		E:CreateMover(Bar, L["stanceBarFrame"])
		
		StanceBarReady = true
		AB:UpdateStanceBar()
		AB:UpdateActionbar("stancebar")
		
	end
end

-- /run print(AB.ActionButtons["AB_StanceButton1"].action)

function AB:UpdateStanceBar()
	if not StanceBarReady then return end
	
	local db = CO.db.profile.actionbar["stancebar"]
	
	-- StanceBarFrame:SetPoint("TOPLEFT", E.Parent, "TOPLEFT", db.xOffset, db.yOffset)
	-- /run CUI:GetModule("Actionbars"):UpdateActionButtonStyle()
	
	for i=1,GetNumShapeshiftForms() do
		AB:UpdateActionButtonStyle(_G["StanceButton" .. i])
	end
	
	if not InCombatLockdown() then
		AB:UpdateActionbar("stancebar")
	end
end

function AB:InitExtraActionButton()
	ExtraActionBarFrame.ignoreFramePositionManager = true
	E:CreateMover(ExtraActionBarFrame, "Extra Button")
	
	AB:UpdateExtraActionButton()
end

function AB:UpdateExtraActionButton()
	local db = CO.db.profile.actionbar["extrabar"]
	
	E:LoadMoverPositions(ExtraActionBarFrame)
	ExtraActionButton1:SetScale(db.buttonSizeMultiplier)
end

function AB:InitZoneActionButton()
	E:CreateMover(ZoneAbilityFrame, "Zone Button")
	ZoneAbilityFrame.ignoreFramePositionManager = true
	
	AB:UpdateZoneActionButton()
end

function AB:UpdateZoneActionButton()
	local db = CO.db.profile.actionbar["zonebar"]
	
	E:LoadMoverPositions(ZoneAbilityFrame)
	ZoneAbilityFrame:SetScale(db.buttonSizeMultiplier)
end

local MicroButtons = {"CharacterMicroButton", "SpellbookMicroButton", "TalentMicroButton", "AchievementMicroButton", "QuestLogMicroButton", "GuildMicroButton", "LFDMicroButton", "CollectionsMicroButton", "EJMicroButton", "StoreMicroButton", "MainMenuMicroButton"}
function AB:InitMicroMenu()
	local mover = CreateFrame("Frame", "MicroMenu", E.Parent)
	AB.MicroMenu = mover
	mover:SetSize(310, 36)
	local index = 0
	
	for _, v in pairs(MicroButtons) do
		_G[v]:ClearAllPoints()
		_G[v]:SetParent(mover)
		_G[v]:SetPoint("BOTTOMLEFT", mover, "BOTTOMLEFT", _G[v]:GetWidth() * index, 0)
		
		index = index + 1
	end
	
	E:CreateMover(mover, L["micromenu"])
	AB:UpdateMicroMenu()
end

function AB:UpdateMicroMenu()
	local db = CO.db.profile.actionbar["micromenu"]
	
	if db.enable ~= true then AB.MicroMenu:Hide() return end
	if not AB.MicroMenu:IsVisible() then AB.MicroMenu:Show() end
	
	E:MainMenuMicroButton_RepositionAlerts()
	E:LoadMoverPositions("MicroMenu")
	AB.MicroMenu:SetScale(db.buttonSizeMultiplier)
end

function AB:BindUpdate(button, type)
	if not self.keyRebind or InCombatLockdown() then return; end
	
	
end

function AB:SetKeybinder(state)
	if state == true then
		AB.E:RegisterEvent("REGEN_DISABLED")
		AB.E:SetScript("OnEvent", function(self) AB:SetKeybinder(false) end)
		
		self.keyRebind = true
		CO:ShowNotification("KEYREBIND_ACTIVE")
		
		for _, button in pairs(AB.ActionButtons) do
			--button:SetAttribute("action", 0)
			button:HookScript("OnEnter", function(self) AB:BindUpdate(self); end);
		end
	else
		AB.E:UnregisterEvent("REGEN_DISABLED")
		self.keyRebind = false
		
		
	end
end

function AB:SetupActionbars()
	AB:CreateActionBars()
	AB:CreatePetActionBar()
	-- AB:UpdateActionButtonState()
	InitActionBarChange()
	AB:UpdateExtraBar()
	AB:InitStanceBar()
	AB:InitExtraActionButton()
	AB:InitZoneActionButton()
	AB:InitMicroMenu()
	
	for i=1,12 do AB:UpdateActionbar(i) end
	AB:UpdateActionbar("stancebar")
	AB:UpdateActionbar("petbar")
	
	AB:UpdateActionButtonStyle()
	-- /dump CUI:GetModule("Actionbars").ActionButtons["CUI_ActionButton1"].HotKey:GetText()
end

function AB:Init()
	CO = E:LoadModules("Config")
	
	Masque = LibStub("Masque", true)
	if Masque then
		MasqueGroup = Masque:Group("CUI")
	else
		if CO.db.profile.actionbar.useMasque == true then
			E:print("Masque not installed, but still enabled :c")
		end
	end
	
	AB:SetupActionbars()
	
	AB.E:RegisterEvent("UPDATE_BINDINGS")
	AB.E.PageWarningShown = nil
	
	AB.E:SetScript("OnEvent", function(self, event, ...)
		if event == "UPDATE_SHAPESHIFT_FORM" then
			AB:UpdateExtraBar()
		end
		if event == "UPDATE_BONUS_ACTIONBAR" 
			or event == "UPDATE_VEHICLE_ACTIONBAR" 
			or event == "UPDATE_OVERRIDE_ACTIONBAR"
			or event == "ACTIONBAR_PAGE_CHANGED" then
				if event == "ACTIONBAR_PAGE_CHANGED" and not AB.E.PageWarningShown then
					E:print("Warning: You changed the actionbar page. If this was not intentional, it is advised to remove the binding for this action.")
					AB.E.PageWarningShown = true
				end
			AB:UpdateExtraBar()
		end
		if event == "UPDATE_BINDINGS" then
			AB:ReassignBindings()
		end
		if event == "CVAR_UPDATE" and select(1, ...) == "LOCK_ACTIONBAR_TEXT" then
			local val = GetCVarBool('lockActionBars')
			for _, button in pairs(AB.ActionButtons) do
				button:SetAttribute("buttonlock", val)
			end
		end
	end)
	--[[AB.E:SetScript("OnUpdate", function(self, elapsed)
		
		local rangeTimer = self.rangeTimer;
		
		if ( rangeTimer ) then
			rangeTimer = rangeTimer - elapsed;

			if ( rangeTimer <= 0 ) then
				for k, v in pairs(AB.ActionButtons) do
					if v.cooldown.enable and v.cooldown.enable == 1 then
						--AB:ActionButton_UpdateCooldownText(v)
					end
				end
				rangeTimer = 0.02;
			end

			self.rangeTimer = rangeTimer;
		end
	end)]]
end

E:AddModule("Actionbars", AB)