--[[ $Id: Bartender3_ButtonClass.lua 20368 2006-12-13 14:37:22Z nevcairiel $ ]]
local AceOO = AceLibrary("AceOO-2.0")

if not Bartender3.Class then Bartender3.Class = {} end
Bartender3.Class.Button	= AceOO.Class("AceEvent-2.0")

local L = AceLibrary("AceLocale-2.2"):new("Bartender3")

local function ShortenKeyBinding(text)
	text = string.gsub(text, "CTRL--", "|c00FF9966C|r")
	text = string.gsub(text, "STRG--", "|c00CCCC00S|r")
	text = string.gsub(text, "ALT--", "|c009966CCA|r")
	text = string.gsub(text, "SHIFT--", "|c00CCCC00S|r")
	text = string.gsub(text, "Num Pad ", "NP")
	text = string.gsub(text, "Mouse Button ", "M")
	text = string.gsub(text, "Middle Mouse", "MM")
	text = string.gsub(text, "Backspace", "Bs")
	text = string.gsub(text, "Spacebar", "Sp")
	text = string.gsub(text, "Delete", "De")
	text = string.gsub(text, "Home", "Ho")
	text = string.gsub(text, "End", "En")
	text = string.gsub(text, "Arrow", "")
	text = string.gsub(text, "Insert", "Ins")
	text = string.gsub(text, "Page Up", "Pu")
	text = string.gsub(text, "Page Down", "Pd")
	text = string.gsub(text, "Down ", "D")
	text = string.gsub(text, "Up ", "U")
	text = string.gsub(text, "Left ", "L")
	text = string.gsub(text, "Right ", "R")
	
	return text
end

--returns the formatted time - from OmniCC
function BT3FormatTime(secs)
	--Bartender3:Print(secs)
	if secs > 86400 then
		return floor(secs / 86400 + 0.5) .. "d", mod(secs, 86400), 0.75
	elseif secs > 3600 then
		return floor(secs / 3600 + 0.5) .. "h", mod(secs, 3600), 0.75
	elseif secs > 60 then
		return floor(secs / 60 + 0.5) .. "m", mod(secs, 60), 0.75
	end
	return floor(secs + 0.5), secs - floor(secs), 1
end

function Bartender3.Class.Button.prototype:init(parent, id)
	Bartender3.Class.Button.super.prototype.init(self)
	self.parent = parent
	self.id = id
	self.rid = self.id - ( self.parent.id - 1 ) * 12
	
	self.showgrid = 0
	self.flashing = 0
	self.flashtime = 0
	self.outOfRange = false
	self.elapsed = 0
	
	self:CreateButtonFrame()
end

-- CreateButtonFrame will NOT anchor the button, you HAVE to do that.
function Bartender3.Class.Button.prototype:CreateButtonFrame()
	local name = "BT3Button"..self.id
	self.frame = CreateFrame("CheckButton", name, self.parent.frame, "SecureActionButtonTemplate, ActionButtonTemplate")
	local frame = self.frame
	frame.class = self
	frame:RegisterForClicks("AnyUp")
	frame:RegisterForDrag("LeftButton", "RightButton")
	
	frame:SetScript("OnUpdate", function(bself, elapsed) 
		self.elapsed = self.elapsed + elapsed
		if self.elapsed > 0.5 then
			self:OnUpdate(self.elapsed)
			self.elapsed = 0
		end
	end )
	--self:ScheduleRepeatingEvent(name.."Update", self.OnUpdate, 0.2, self, 0.2)
	
	--frame:SetScript("PostClick", function() if ( IsShiftKeyDown() ) then PickupAction(self:PagedID()) end self:UpdateState() end)
	frame:SetScript("OnEnter", function() if not Bartender3.db.profile.HideTooltip then self:SetTooltip() end end)
	frame:SetScript("OnLeave", function() if not Bartender3.db.profile.HideTooltip then this.updateTooltip = nil; GameTooltip:Hide(); end end)
	if self.parent.statebar then
		frame:SetScript("OnAttributeChanged", function() self.cached_id = nil; self:UpdateButton() end)
	end
	
	frame:SetScript("OnDragStart", function()
		if ( not Bartender3.db.profile.ButtonLock or IsShiftKeyDown()) then
			PickupAction(self:PagedID())
			self:UpdateHotkeys()
			self:UpdateState()
			self:UpdateFlash()
		end
	end)
	
	frame.icon = getglobal(name.."Icon")
	frame.border = getglobal(name.."Border")
	frame.cooldown = getglobal(name.."Cooldown")
	frame.macroName = getglobal(name.."Name")
	frame.hotkey = getglobal(name.."HotKey")
	frame.count = getglobal(name.."Count")
	frame.normalTexture = getglobal(name.."NormalTexture")
	frame.flash = getglobal(name.."Flash")
	frame.flash:Hide()
	
	frame.cooldownText = frame:CreateFontString(nil, "OVERLAY")
	frame.cooldownText:SetPoint("CENTER", frame, "CENTER", 0, 1)
	frame.cooldownText:SetFont(STANDARD_TEXT_FONT, 20, "OUTLINE")
	frame.cooldownText:SetTextColor(1, 1, 0.2)
	frame.cooldownText:Show()
	frame.cooldown:SetFrameLevel(frame.cooldown:GetFrameLevel()-1)
	
	self.parent.frame:SetAttribute("addchild", frame)
	frame:SetAttribute("type", "action")
	frame:SetAttribute("action", self.id)
	frame:SetAttribute("useparent-unit", true)
	frame:SetAttribute("useparent-statebutton", true)
	
	
	self:SetStateAction(0, self.id)
	
	self:UpdateHotkeys()
	self:UpdateButton()
	
	self:RegisterBarEvents()
end

function Bartender3.Class.Button.prototype:SetStateAction(state, action)
	for i=1,2 do
		self.frame:SetAttribute("*action-S" .. state .. i, action)
	end
end

function Bartender3.Class.Button.prototype:PagedID()
	if not self.cached_id then
		self.cached_id = SecureButton_GetModifiedAttribute(self.frame, "action", SecureStateChild_GetEffectiveButton(self.frame)) or 1
	end
	return self.cached_id
end

function Bartender3.Class.Button.prototype:UpdateIcon()
	local frame = self.frame
	local texture = GetActionTexture(self:PagedID())
	if ( texture ) then
		frame.icon:SetTexture(texture)
		frame.icon:Show()
		frame:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
		frame.normalTexture:SetTexCoord(0,0,0,0)
	else
		frame.icon:Hide()
		frame.cooldown:Hide()
		frame:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
		frame.hotkey:SetVertexColor(0.6, 0.6, 0.6)
		frame.normalTexture:SetTexCoord(-0.1,1.1,-0.1,1.12)
	end
end

function Bartender3.Class.Button.prototype:UpdateButton()
	local frame = self.frame
	
	self:UpdateIcon()
	self:UpdateCount()
	Bartender3:RefreshStyle(self.frame, self.parent)
	if ( HasAction(self:PagedID()) ) then
		self:RegisterButtonEvents()
		self:UpdateState()
		self:UpdateUsable()
		self:UpdateCooldown()
		self:UpdateFlash()
		
		frame:SetAlpha(self.parent.config.Alpha)
	else
		frame.cooldownText:SetText("")
		self:UnregisterButtonEvents()
		
		if ( self.showgrid == 0 ) then
			if ( self.parent.config.ShowGrid == true ) then
				frame:SetAlpha(self.parent.config.Alpha / 2)
				frame.cooldown:Hide()
			else
				frame:SetAlpha(0)
			end
		else
			frame.cooldown:Hide()
		end
	end
	
	if ( IsEquippedAction(self:PagedID()) ) then
		frame.border:SetVertexColor(0, 1.0, 0, 0.75)
		frame.border:Show()
	else
		frame.border:Hide()
	end
	
	if ( GameTooltip:IsOwned(self.frame) ) then
		self:SetTooltip()
	else
		self.updateTooltip = nil
	end
	
	frame.macroName:SetText(GetActionText(self:PagedID()));
end

function Bartender3.Class.Button.prototype:UpdateHotkeys()
	local hotkey = self.frame.hotkey
	local button = self:PagedID()
	local key = nil
	local bar = self.parent.id
	if bar == 1 then
		key = GetBindingKey("ACTIONBUTTON"..self.rid) or nil
	elseif (bar >= 3 and bar <= 6) then
		local k
		if bar == 6 then k = 1
		elseif bar == 5 then k = 2
		else k = bar end
		key = GetBindingKey("MULTIACTIONBAR"..k.."BUTTON"..self.rid) or nil
	else
		key = GetBindingKey("BT3BAR"..(bar==10 and 0 or bar).."BUTTON"..self.rid) or nil
	end
	key = key or GetBindingKey("CLICK "..self.frame:GetName()..":LeftButton")
	if ( GetBindingText(key, "KEY_", 1) == "" or self.parent.config.HideHotkey ) then
		hotkey:SetText("")
	else
		hotkey:SetText(ShortenKeyBinding(GetBindingText(key, "KEY_", 1)))
	end
end

function Bartender3.Class.Button.prototype:UpdateCount()
	if ( IsConsumableAction(self:PagedID()) ) then
		self.frame.count:SetText(GetActionCount(self:PagedID()))
	else
		self.frame.count:SetText("")
	end
end

function Bartender3.Class.Button.prototype:UpdateState()
	local actionID = self:PagedID()
	if ( IsCurrentAction(actionID) or IsAutoRepeatAction(actionID) ) then
		self.frame:SetChecked(1)
	else
		self.frame:SetChecked(0)
	end
end

function Bartender3.Class.Button.prototype:UpdateUsable()
	local id = self:PagedID()
	local isUsable, notEnoughMana = IsUsableAction(id)
	if ( isUsable and not self.outOfRange) then
		self.frame.icon:SetVertexColor(1.0, 1.0, 1.0)
	elseif ( self.outOfRange ) then
		self.frame.icon:SetVertexColor(0.8, 0.1, 0.1)
	elseif ( notEnoughMana ) then
		self.frame.icon:SetVertexColor(0.1, 0.3, 1.0)
	else
		self.frame.icon:SetVertexColor(0.4, 0.4, 0.4)
	end
end

function Bartender3.Class.Button.prototype:UpdateCooldown()
	local start, duration, enable = GetActionCooldown(self:PagedID())
	CooldownFrame_SetTimer(self.frame.cooldown, start, duration, enable)
	self.parent:StartButtonCooldown(self.frame, start, duration, enable)
end

function Bartender3.Class.Button.prototype:UpdateFlash()
	local pagedID = self:PagedID()
	if ( (IsAttackAction(pagedID) and IsCurrentAction(pagedID)) or IsAutoRepeatAction(pagedID) ) then
		self:StartFlash()
	else
		self:StopFlash()
	end
end

function Bartender3.Class.Button.prototype:OnUpdate(elapsed)
	if not self.parent.config.Enabled or self.parent.config.Hide then return end
	
	self:UpdateState()
	self:UpdateIcon()
	
	self.parent:UpdateButtonCooldown(self.frame, elapsed)
	
	if ( self.flashing == 1 ) then
		self.flashtime = self.flashtime - elapsed;
		if ( self.flashtime <= 0 ) then
			local overtime = -self.flashtime;
			if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then
				overtime = 0;
			end
			self.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;

			local flashTexture = self.frame.flash
			if ( flashTexture:IsVisible() ) then
				flashTexture:Hide()
			else
				flashTexture:Show()
			end
		end
	end
	
	if (self.outOfRange ~= ( IsActionInRange( self:PagedID() ) == 0)) then
		self.outOfRange = not self.outOfRange
		self:UpdateUsable()
	end

	if ( not self.updateTooltip ) then
		return
	end

	self.updateTooltip = self.updateTooltip - elapsed
	if ( self.updateTooltip > 0 ) then
		return
	end

	if ( GameTooltip:IsOwned(self.frame) ) then
		self:SetTooltip()
	else
		self.updateTooltip = nil
	end
end

function Bartender3.Class.Button.prototype:SetTooltip()
	local frame = self.frame
	if ( GetCVar("UberTooltips") == "1" ) then
		GameTooltip_SetDefaultAnchor(GameTooltip, self.frame)
	else
		GameTooltip:SetOwner(frame, "ANCHOR_RIGHT")
	end
	
	if ( GameTooltip:SetAction(self:PagedID()) ) then
		self.updateTooltip = TOOLTIP_UPDATE_TIME
	else
		self.updateTooltip = nil
	end
end

function Bartender3.Class.Button.prototype:StartFlash()
	self.flashing = 1
	self.flashtime = 0
	self:UpdateState()
end

function Bartender3.Class.Button.prototype:StopFlash()
	self.flashing = 0;
	self.frame.flash:Hide()
	self:UpdateState()
end

function Bartender3.Class.Button.prototype:ShowGrid()
	local button = self.frame
	self.showgrid = self.showgrid+1
	
	button:SetAlpha(self.parent.config.Alpha)
end

function Bartender3.Class.Button.prototype:HideGrid()
	local button = self.frame
	self.showgrid = self.showgrid-1;
	if ( self.showgrid == 0 and not HasAction(self:PagedID()) ) then
		if ( self.parent.config.ShowGrid == true ) then
			button:SetAlpha(self.parent.config.Alpha / 2)
		else
			button:SetAlpha(0)
		end
	end
end

function Bartender3.Class.Button.prototype:ReleaseButton()
	local bt3button = Bartender3.actionbuttons[self.id]
	bt3button.state = "free"
	self.frame:Hide()
	self.frame:SetParent(UIParent)
end

function Bartender3.Class.Button.prototype:AssignButton(parent, id)
	self.frame:SetParent(parent.frame)
	parent.frame:SetAttribute("addchild", self.frame)
	self.parent = parent
	self.id = id
	self.frame:SetAttribute("action", id)
	self:SetStateAction(0, self.id)
	self.frame:Show()
end

function Bartender3.Class.Button.prototype:RegisterBarEvents()
	self:RegisterEvent("PLAYER_ENTERING_WORLD", "BaseEventHandler")
	self:RegisterEvent("ACTIONBAR_PAGE_CHANGED", "BaseEventHandler")
	self:RegisterEvent("ACTIONBAR_SLOT_CHANGED", "BaseEventHandler")
	self:RegisterEvent("UPDATE_BINDINGS", "BaseEventHandler")
	self:RegisterEvent("ACTIONBAR_SHOWGRID", "BaseEventHandler")
	self:RegisterEvent("ACTIONBAR_HIDEGRID", "BaseEventHandler")
end

function Bartender3.Class.Button.prototype:RegisterButtonEvents()
	if self.eventsregistered then return end
	self.eventsregistered = true
	self:RegisterEvent("ACTIONBAR_UPDATE_STATE", "ButtonEventHandler")
	self:RegisterEvent("ACTIONBAR_UPDATE_USABLE", "ButtonEventHandler")
	self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "ButtonEventHandler")
	self:RegisterEvent("UPDATE_INVENTORY_ALERTS", "ButtonEventHandler")
	self:RegisterEvent("CRAFT_SHOW", "ButtonEventHandler")
	self:RegisterEvent("CRAFT_CLOSE", "ButtonEventHandler")
	self:RegisterEvent("TRADE_SKILL_SHOW", "ButtonEventHandler")
	self:RegisterEvent("TRADE_SKILL_CLOSE", "ButtonEventHandler")
	self:RegisterEvent("PLAYER_ENTER_COMBAT", "ButtonEventHandler")
	self:RegisterEvent("PLAYER_LEAVE_COMBAT", "ButtonEventHandler")
	self:RegisterEvent("START_AUTOREPEAT_SPELL", "ButtonEventHandler")
	self:RegisterEvent("STOP_AUTOREPEAT_SPELL", "ButtonEventHandler")
end

function Bartender3.Class.Button.prototype:UnregisterButtonEvents()
	if not self.eventsregistered then return end
	self.eventsregistered = nil
	self:UnregisterEvent("ACTIONBAR_UPDATE_STATE")
	self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE")
	self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN")
	self:UnregisterEvent("UPDATE_INVENTORY_ALERTS")
	self:UnregisterEvent("CRAFT_SHOW")
	self:UnregisterEvent("CRAFT_CLOSE")
	self:UnregisterEvent("TRADE_SKILL_SHOW")
	self:UnregisterEvent("TRADE_SKILL_CLOSE")
	self:UnregisterEvent("PLAYER_ENTER_COMBAT")
	self:UnregisterEvent("PLAYER_LEAVE_COMBAT")
	self:UnregisterEvent("START_AUTOREPEAT_SPELL")
	self:UnregisterEvent("STOP_AUTOREPEAT_SPELL")
end

--[[
	Following Events are always set and will always be called - i call them the BAR EVENTS
]]
function Bartender3.Class.Button.prototype:BaseEventHandler()
	if not self.parent.config.Enabled then return end
	local e = event
	
	if ( e == "PLAYER_ENTERING_WORLD" or e == "ACTIONBAR_PAGE_CHANGED") then
		self:UpdateButton()
	elseif ( e == "ACTIONBAR_SLOT_CHANGED" ) then
		local button = arg1
		if ( button == 0 or button == self:PagedID() ) then
			self:UpdateButton()
		end
	elseif ( e == "UPDATE_BINDINGS" ) then
		self:UpdateHotkeys()
	elseif ( e == "ACTIONBAR_SHOWGRID" ) then
		self:ShowGrid()
	elseif ( e == "ACTIONBAR_HIDEGRID" ) then
		self:HideGrid()
	end
end

--[[
	Following Events are only set when the Button in question has a valid action - i call them the button events
]]
function Bartender3.Class.Button.prototype:ButtonEventHandler()
	if not self.parent.config.Enabled then return end
	local e = event
	
	if ( e == "ACTIONBAR_UPDATE_STATE" ) then
		self:UpdateState()
	elseif ( event == "ACTIONBAR_UPDATE_USABLE" or event == "UPDATE_INVENTORY_ALERTS" or event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
		self:UpdateUsable()
		self:UpdateCooldown()
	elseif ( event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then
		self:UpdateState()
	elseif ( event == "PLAYER_ENTER_COMBAT" ) then
		if ( IsAttackAction(self:PagedID()) ) then
			self:StartFlash()
		end
	elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
		if ( IsAttackAction(self:PagedID()) ) then
			self:StopFlash()
		end
	elseif ( event == "START_AUTOREPEAT_SPELL" ) then
		if ( IsAutoRepeatAction(self:PagedID()) ) then
			self:StartFlash()
		end
	elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then
		if ( self.flashing == 1 and not IsAttackAction(self:PagedID()) ) then
			self:StopFlash()
		end
	end
end


