local addonName, addon = ...
_G[addonName] = addon

--[[-----------------------------------------------------------------------------
Event handling - Use one frame to process multiple individual OnEvent needs
-------------------------------------------------------------------------------]]
do
	local frame, select, next, events = CreateFrame('Frame'), select, pairs({ })
	local register, unregister = frame.RegisterEvent, frame.UnregisterEvent
	frame:Hide()

	frame:SetScript('OnEvent', function(self, event, ...)
		for reference, func in next, events[event], nil do
			func(reference, event, ...)
		end
	end)

	function addon.RegisterEvent(reference, event, func, ...)
		if not events[event] then
			events[event] = { }
			register(frame, event)
		end
		events[event][reference] = func
	end

	function addon.RegisterEvents(reference, func, ...)
		local event
		for index = 1, select('#', ...) do
			event = select(index, ...)
			if not events[event] then
				events[event] = { }
				register(frame, event)
			end
			events[event][reference] = func
		end
	end

	function addon.UnregisterEvent(reference, event)
		if events[event] then
			events[event][reference] = nil
			if not next(events[event]) then
				events[event] = nil
				unregister(frame, event)
			end
		end
	end

	function addon.UnregisterAllEvents(reference)
		for event, registry in next, events, nil do
			registry[reference] = nil
			if not next(registry) then
				events[event] = nil
				unregister(frame, event)
			end
		end
	end
end

--[[-----------------------------------------------------------------------------
SafeCall - Queue a method of addon to run once combat ends if needed
-------------------------------------------------------------------------------]]
do
	local combatLockdown, queue = InCombatLockdown(), { }
	addon.RegisterEvent("Core-SafeCall-EnterCombat", 'PLAYER_REGEN_DISABLED', function(self)
		combatLockdown = true
	end)
	addon.RegisterEvent("Core-SafeCall-LeaveCombat", 'PLAYER_REGEN_ENABLED', function(self)
		combatLockdown = nil
		for method, arg in pairs(queue) do
			addon[method](addon, arg)
			queue[method] = nil
		end
	end)
	function addon:SafeCall(method, arg)
		if combatLockdown then
			queue[method] = arg or false
		else
			addon[method](addon, arg)
		end
	end
end

--[[-----------------------------------------------------------------------------
Localized class name to file class name look up table
-------------------------------------------------------------------------------]]
local CLASS = { }
for fileName, localName in pairs(LOCALIZED_CLASS_NAMES_MALE) do
	CLASS[localName] = fileName
end
for fileName, localName in pairs(LOCALIZED_CLASS_NAMES_FEMALE) do
	CLASS[localName] = fileName
end
addon.CLASS = CLASS

--[[-----------------------------------------------------------------------------
MoneyToString - Get formatted text from an ammount of copper
-------------------------------------------------------------------------------]]
function addon:MoneyToString(ammount, forceIcons)
	if type(ammount) ~= 'number' then
		ammount = 0
	end
	local cu = ammount % 100
	ammount = floor(ammount / 100)
	local ag, au = ammount % 100, floor(ammount / 100)
	local cuInd, agInd, auInd
	if GetCVarBool('showChatIcons') or forceIcons then
		cuInd = [[|TInterface\MoneyFrame\UI-CopperIcon:0|t]]
		agInd = [[|TInterface\MoneyFrame\UI-SilverIcon:0|t ]]
		auInd = [[|TInterface\MoneyFrame\UI-GoldIcon:0|t ]]
	else
		cuInd = "|cffeda55fc|r"
		agInd = "|cffc7c7cfs|r "
		auInd = "|cffffd700g|r "
	end
	local string = ""
	if au > 0 then
		string = au .. auInd .. ag .. agInd
	elseif ag > 0 then
		string = ag .. agInd
	end
	return string .. cu .. cuInd
end

--[[-----------------------------------------------------------------------------
DoNothing - A simple dummie/do nothing function
-------------------------------------------------------------------------------]]
local function DoNothing()
end
addon.DoNothing = DoNothing

--[[-----------------------------------------------------------------------------
SetUIScale - Set UI Scale to its smallest size.
-------------------------------------------------------------------------------]]
function addon:SetUIScale()
	SetCVar("useUiScale", 1)
	SetCVar( "uiScale", 0.63999998569489);
end

--[[-----------------------------------------------------------------------------
HideTooltip - Hide GameTooltip (several frames use this)
-------------------------------------------------------------------------------]]
function addon:HideTooltip()
	GameTooltip:Hide()
	self.tooltip = nil
end

--[[-----------------------------------------------------------------------------
HideFrame - Hide a frame, prevents it from being reshown
-------------------------------------------------------------------------------]]
function addon:HideFrame(reference)
	local frame = type(reference) == 'string' and _G[reference] or reference
	if type(frame) ~= 'table' then return end
	frame.Show = DoNothing
	frame:Hide()
end

--[[-----------------------------------------------------------------------------
ShowFrame - Show a frame, undoing :HideFrame behavior
-------------------------------------------------------------------------------]]
function addon:ShowFrame(reference)
	local frame = type(reference) == 'string' and _G[reference] or reference
	if type(frame) ~= 'table' then return end
	frame.Show = nil
	frame:Show()
end

--[[-----------------------------------------------------------------------------
LockFrame - Lock a frame, prevents SetPoint and ClearAllPoints from working
-------------------------------------------------------------------------------]]
function addon:LockFrame(reference)
	local frame = type(reference) == 'string' and _G[reference] or reference
	if type(frame) ~= 'table' then return end
	frame.SetPoint = DoNothing
	frame.ClearAllPoints = DoNothing
end

--[[-----------------------------------------------------------------------------
UnlockFrame - Undo :LockFrame
-------------------------------------------------------------------------------]]
function addon:UnlockFrame(reference)
	local frame = type(reference) == 'string' and _G[reference] or reference
	if type(frame) ~= 'table' then return end
	frame.SetPoint = nil
	frame.ClearAllPoints = nil
end

--[[-----------------------------------------------------------------------------
RunSlashCmd - This no longer functions correctly as of patch 4.3
-------------------------------------------------------------------------------]]
local _G = _G
function addon:RunSlashCmd(cmd)
	local slash, rest = cmd:match("^(%S+)%s*(.-)$")
	for name, func in pairs(SlashCmdList) do
		local i, slashCmd = 1
		repeat
		slashCmd, i = _G["SLASH_"..name..i], i + 1
			if slashCmd == slash then
				return true, func(rest)
			end
		until not slashCmd
	end
	-- Okay, so it's not a slash command. It may also be an emote.
	local i = 1
	while _G["EMOTE" .. i .. "_TOKEN"] do
		local j, cn = 2, _G["EMOTE" .. i .. "_CMD1"]
		while cn do
			if cn == slash then
				return true, DoEmote(_G["EMOTE" .. i .. "_TOKEN"], rest);
			end
			j, cn = j+1, _G["EMOTE" .. i .. "_CMD" .. j]
		end
		i = i + 1
	end
end 

--[[-----------------------------------------------------------------------------
GetSlashFunc - returns a slash command function on success or an informative error function on failure.
-------------------------------------------------------------------------------]]
function addon:GetSlashFunc(cmd)
	if not cmd then
		return function(cmd) print("You must supply a command.") end
	end
	if cmd:sub(1, 1) ~= "/" then
		cmd = "/" .. cmd
	end
	for id, val in pairs(_G) do
		if id:sub(1, 5) == "SLASH" and val == cmd then
			local slashID = id:match("SLASH_(%a*)%d*")
			return SlashCmdList[slashID]
		end
	end
	-- Didn't find one?
	return function(cmd) print(cmd, "doesn't exist.") end
end

--[[-----------------------------------------------------------------------------
Decimal Removal Function
-------------------------------------------------------------------------------]]
function addon:truncate(number, decimals)
    return number - (number % (0.1 ^ decimals))
end

--[[-----------------------------------------------------------------------------
Class/Reaction type Coloring
-------------------------------------------------------------------------------]]
do 
	local format = string.format
	GCHex = function(color)
		return format('|cff%02x%02x%02x', color.r * 255, color.g * 255, color.b * 255)
	end
end
function addon:unitColor(unit)
	local color = { r=1, g=1, b=1 }
	if UnitIsPlayer(unit) then
		local _, class = UnitClass(unit)
		color = RAID_CLASS_COLORS[class]
		return color
	else
		local reaction = UnitReaction(unit, "player")
		if reaction then
			color = FACTION_BAR_COLORS[reaction]
			return color
		end
	end
	return color
end

--[[-----------------------------------------------------------------------------
Durability % Coloring
-------------------------------------------------------------------------------]]
function addon:DurColor(percent)
	local tmpString = ""
	if percent >= 80 then
		tmpString = "|cff00FF00"
	elseif percent >= 60 then
		tmpString = "|cff99FF00"
	elseif percent >= 40 then
		tmpString = "|cffFFFF00"
	elseif percent >= 20 then
		tmpString = "|cffFF9900"
	elseif percent >= 0 then
		tmpString = "|cffFF2000"
	end
	return tmpString;
end

--[[-----------------------------------------------------------------------------
Delay a function
-------------------------------------------------------------------------------]]
local waitTable = {};
local waitFrame = nil;
function addon:FuncDelay(delay, func, ...)
  if(type(delay)~="number" or type(func)~="function") then
    return false;
  end
  if(waitFrame == nil) then
    waitFrame = CreateFrame("Frame","WaitFrame", UIParent);
    waitFrame:SetScript("onUpdate",function (self,elapse)
      local count = #waitTable;
      local i = 1;
      while(i<=count) do
        local waitRecord = tremove(waitTable,i);
        local d = tremove(waitRecord,1);
        local f = tremove(waitRecord,1);
        local p = tremove(waitRecord,1);
        if(d>elapse) then
          tinsert(waitTable,i,{d-elapse,f,p});
          i = i + 1;
        else
          count = count - 1;
          f(unpack(p));
        end
      end
    end);
  end
  tinsert(waitTable,{delay,func,{...}});
  return true;
end

--[[-----------------------------------------------------------------------------
Blizzard Build comparison for ptr/beta/live compatible versions
-------------------------------------------------------------------------------]]
function addon:CompareBuild(comver, combuild, comref, lowcomref, highcomref)
	local version, build, bdate, toc = GetBuildInfo()
	if version > comver and build > combuild then
		addon[highcomref]()
	elseif version < comver and build < combuild then
		addon[lowcomref]()
	elseif version == comver and build == combuild then
		addon[comref]()
	end
end

--[[-----------------------------------------------------------------------------
Basic Button Creation
-------------------------------------------------------------------------------]]
function addon:GUI_BasicButtonCreate(framename, frameparent, buttontext)
	local frame = CreateFrame("Button", framename, frameparent, "UIPanelButtonTemplate")
	frame:SetSize(115, 35)
	frame:RegisterForClicks("AnyUp")
	frame:SetText(buttontext)
end

--[[-----------------------------------------------------------------------------
Reload Frame
-------------------------------------------------------------------------------]]
-- reloadtype 1 = normal reload -- reloadtype = 2 quit game entirely.
function addon:OpenReloadFrame(myfunc, reloadtype)
	local reloadFrame
	if (reloadFrame) then return reloadFrame:Show() end
	reloadFrame = CreateFrame("Frame", nil, UIParent)
	reloadFrame:SetSize(350, 160)
	reloadFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 200)
	reloadFrame:SetBackdrop{
		bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
		edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
		tile = true,
		tileSize = 32,
		edgeSize = 32,
		insets = {
			left = 11,
			right = 12,
			top = 12,
			bottom = 11
		}
	}
	local text = reloadFrame:CreateFontString(nil, "ARTWORK", "GameFontNormalHuge")
	text:SetPoint("TOP", 0, -20);
	local text2 = reloadFrame:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
	text2:SetPoint("TOP", 0, -60)
	addon:GUI_BasicButtonCreate("button1", reloadFrame, "Okay")
	button1:SetPoint("BOTTOMLEFT", 15, 15)
	button1:SetScript("OnClick", myfunc)
	addon:GUI_BasicButtonCreate("button2", reloadFrame, "Cancel")
	button2:SetPoint("BOTTOMRIGHT", -15, 15)
	button2:SetScript("OnClick", function() reloadFrame:Hide() end)
	if reloadtype == 2 then
		text:SetText("GrimUI: Restart Game")
		text2:SetText("GrimUI requires the game be\n restarted to finish its configuration.\n Click Okay to Logout and restart the game.")
	else
		text:SetText("GrimUI: ReloadUI")
		text2:SetText("GrimUI requires the UI be\n reloaded to finish its configuration.\n Click Okay to Reload the UI.")
	end
end

--[[-----------------------------------------------------------------------------
Ace Lib Hooks
-------------------------------------------------------------------------------]]
-- LibSharedMedia support
local LSM = LibStub('LibSharedMedia-3.0')
LSM:Register('background', addonName, [[Interface\Addons\]] .. addonName .. [[\Media\MainBG]])
LSM:Register('font', "Franklin Gothing Medium", [[Interface\Addons\]] .. addonName .. [[\Media\Font1.ttf]])
LSM:Register('font', "Comic Sans MS", [[Interface\Addons\]] .. addonName .. [[\Media\Font3.ttf]])