
--[[
Visit: https://github.com/BigWigsMods/BigWigs/wiki/Custom-Bar-Styles
for in-depth information on how to register new bar styles from 3rd party addons.
]]

--------------------------------------------------------------------------------
-- Module Declaration
--

local plugin = BigWigs:NewPlugin("Bars")
if not plugin then return end

--------------------------------------------------------------------------------
-- Locals
--

local colorize = nil
do
	local r, g, b
	colorize = setmetatable({}, { __index =
		function(self, key)
			if not r then r, g, b = GameFontNormal:GetTextColor() end
			self[key] = "|cff" .. ("%02x%02x%02x"):format(r * 255, g * 255, b * 255) .. key .. "|r"
			return self[key]
		end
	})
end

local L = BigWigsAPI:GetLocale("BigWigs: Plugins")
plugin.displayName = L.bars

local startBreak -- Break timer function

local colors = nil
local candy = LibStub("LibCandyBar-3.0")
local media = LibStub("LibSharedMedia-3.0")
local FONT = media.MediaType and media.MediaType.FONT or "font"
local STATUSBAR = media.MediaType and media.MediaType.STATUSBAR or "statusbar"
local next = next
local tremove = tremove
local db = nil
local normalAnchor, emphasizeAnchor = nil, nil
local nameplateBars = {}
local empUpdate = nil -- emphasize updater frame
local rearrangeBars
local rearrangeNameplateBars
local GetNamePlateForUnit = C_NamePlate.GetNamePlateForUnit

local clickHandlers = {}

local findUnitByGUID = nil
do
	local unitTable = {
		"nameplate1", "nameplate2", "nameplate3", "nameplate4", "nameplate5", "nameplate6", "nameplate7", "nameplate8", "nameplate9", "nameplate10",
		"nameplate11", "nameplate12", "nameplate13", "nameplate14", "nameplate15", "nameplate16", "nameplate17", "nameplate18", "nameplate19", "nameplate20",
		"nameplate21", "nameplate22", "nameplate23", "nameplate24", "nameplate25", "nameplate26", "nameplate27", "nameplate28", "nameplate29", "nameplate30",
		"nameplate31", "nameplate32", "nameplate33", "nameplate34", "nameplate35", "nameplate36", "nameplate37", "nameplate38", "nameplate39", "nameplate40",
	}
	local unitTableCount = #unitTable
	findUnitByGUID = function(id)
		for i = 1, unitTableCount do
			local unit = unitTable[i]
			local guid = plugin:UnitGUID(unit)
			if guid == id then
				return unit
			end
		end
	end
end

--------------------------------------------------------------------------------
-- Bar styles setup
--

local currentBarStyler = nil
local SetBarStyle

BigWigsAPI:RegisterBarStyle("Default", {
	apiVersion = 1,
	version = 1,
	--barSpacing = 1,
	--barHeight = 16,
	--fontSizeNormal = 10,
	--fontSizeEmphasized = 13,
	--fontOutline = "NONE",
	--GetSpacing = function(bar) end,
	--ApplyStyle = function(bar) end,
	--BarStopped = function(bar) end,
	GetStyleName = function()
		return L.bigWigsBarStyleName_Default
	end,
})

do
	-- !Beautycase styling, based on !Beatycase by Neal "Neave" @ WowI, texture made by Game92 "Aftermathh" @ WowI

	local textureNormal = "Interface\\AddOns\\BigWigs\\Media\\Textures\\beautycase"

	local backdropbc = {
		bgFile = "Interface\\Buttons\\WHITE8x8",
		insets = {top = 1, left = 1, bottom = 1, right = 1},
	}

	local function createBorder(self)
		local border = UIParent:CreateTexture(nil, "OVERLAY")
		border:SetParent(self)
		border:SetTexture(textureNormal)
		border:SetWidth(12)
		border:SetHeight(12)
		border:SetVertexColor(1, 1, 1)
		return border
	end

	local freeBorderSets = {}

	local function freeStyle(bar)
		local borders = bar:Get("bigwigs:beautycase:borders")
		if borders then
			for i, border in next, borders do
				border:SetParent(UIParent)
				border:Hide()
			end
			freeBorderSets[#freeBorderSets + 1] = borders
		end
	end

	local function styleBar(bar)
		local bd = bar.candyBarBackdrop

		bd:SetBackdrop(backdropbc)
		bd:SetBackdropColor(.1, .1, .1, 1)

		bd:ClearAllPoints()
		bd:SetPoint("TOPLEFT", bar, "TOPLEFT", -1, 1)
		bd:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 1, -1)
		bd:Show()

		local borders = nil
		if #freeBorderSets > 0 then
			borders = tremove(freeBorderSets)
			for i, border in next, borders do
				border:SetParent(bar.candyBarBar)
				border:ClearAllPoints()
				border:Show()
			end
		else
			borders = {}
			for i = 1, 8 do
				borders[i] = createBorder(bar.candyBarBar)
			end
		end
		for i = 1, #borders do
			local border = borders[i]
			if i == 1 then
				border:SetTexCoord(0, 1/3, 0, 1/3)
				border:SetPoint("TOPLEFT", bar, "TOPLEFT", -4, 4)
			elseif i == 2 then
				border:SetTexCoord(2/3, 1, 0, 1/3)
				border:SetPoint("TOPRIGHT", bar, "TOPRIGHT", 4, 4)
			elseif i == 3 then
				border:SetTexCoord(0, 1/3, 2/3, 1)
				border:SetPoint("BOTTOMLEFT", bar, "BOTTOMLEFT", -4, -3)
			elseif i == 4 then
				border:SetTexCoord(2/3, 1, 2/3, 1)
				border:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 4, -3)
			elseif i == 5 then
				border:SetTexCoord(1/3, 2/3, 0, 1/3)
				border:SetPoint("TOPLEFT", borders[1], "TOPRIGHT")
				border:SetPoint("TOPRIGHT", borders[2], "TOPLEFT")
			elseif i == 6 then
				border:SetTexCoord(1/3, 2/3, 2/3, 1)
				border:SetPoint("BOTTOMLEFT", borders[3], "BOTTOMRIGHT")
				border:SetPoint("BOTTOMRIGHT", borders[4], "BOTTOMLEFT")
			elseif i == 7 then
				border:SetTexCoord(0, 1/3, 1/3, 2/3)
				border:SetPoint("TOPLEFT", borders[1], "BOTTOMLEFT")
				border:SetPoint("BOTTOMLEFT", borders[3], "TOPLEFT")
			elseif i == 8 then
				border:SetTexCoord(2/3, 1, 1/3, 2/3)
				border:SetPoint("TOPRIGHT", borders[2], "BOTTOMRIGHT")
				border:SetPoint("BOTTOMRIGHT", borders[4], "TOPRIGHT")
			end
		end

		bar:Set("bigwigs:beautycase:borders", borders)
	end

	BigWigsAPI:RegisterBarStyle("BeautyCase", {
		apiVersion = 1,
		version = 10,
		barSpacing = 8,
		ApplyStyle = styleBar,
		BarStopped = freeStyle,
		GetStyleName = function() return "!Beautycase" end,
	})
end

do
	-- MonoUI
	local backdropBorder = {
		bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
		edgeFile = "Interface\\ChatFrame\\ChatFrameBackground",
		tile = false, tileSize = 0, edgeSize = 1,
		insets = {left = 0, right = 0, top = 0, bottom = 0}
	}

	local function removeStyle(bar)
		bar.candyBarBackdrop:Hide()
		local height = bar:Get("bigwigs:restoreheight")
		if height then
			bar:SetHeight(height)
		end

		local tex = bar:Get("bigwigs:restoreicon")
		if tex then
			bar:SetIcon(tex)
			bar:Set("bigwigs:restoreicon", nil)

			bar.candyBarIconFrameBackdrop:Hide()
		end

		bar.candyBarDuration:ClearAllPoints()
		bar.candyBarDuration:SetPoint("TOPLEFT", bar.candyBarBar, "TOPLEFT", 2, 0)
		bar.candyBarDuration:SetPoint("BOTTOMRIGHT", bar.candyBarBar, "BOTTOMRIGHT", -2, 0)

		bar.candyBarLabel:ClearAllPoints()
		bar.candyBarLabel:SetPoint("TOPLEFT", bar.candyBarBar, "TOPLEFT", 2, 0)
		bar.candyBarLabel:SetPoint("BOTTOMRIGHT", bar.candyBarBar, "BOTTOMRIGHT", -2, 0)
	end

	local function styleBar(bar)
		local height = bar:GetHeight()
		bar:Set("bigwigs:restoreheight", height)
		bar:SetHeight(height/2)

		local bd = bar.candyBarBackdrop

		bd:SetBackdrop(backdropBorder)
		bd:SetBackdropColor(.1,.1,.1,1)
		bd:SetBackdropBorderColor(0,0,0,1)

		bd:ClearAllPoints()
		bd:SetPoint("TOPLEFT", bar, "TOPLEFT", -2, 2)
		bd:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 2, -2)
		bd:Show()

		local tex = bar:GetIcon()
		if tex then
			local icon = bar.candyBarIconFrame
			bar:SetIcon(nil)
			icon:SetTexture(tex)
			icon:Show()
			if bar.iconPosition == "RIGHT" then
				icon:SetPoint("BOTTOMLEFT", bar, "BOTTOMRIGHT", 5, 0)
			else
				icon:SetPoint("BOTTOMRIGHT", bar, "BOTTOMLEFT", -5, 0)
			end
			icon:SetSize(height, height)
			bar:Set("bigwigs:restoreicon", tex)

			local iconBd = bar.candyBarIconFrameBackdrop
			iconBd:SetBackdrop(backdropBorder)
			iconBd:SetBackdropColor(.1,.1,.1,1)
			iconBd:SetBackdropBorderColor(0,0,0,1)

			iconBd:ClearAllPoints()
			iconBd:SetPoint("TOPLEFT", icon, "TOPLEFT", -2, 2)
			iconBd:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", 2, -2)
			iconBd:Show()
		end

		bar.candyBarLabel:ClearAllPoints()
		bar.candyBarLabel:SetPoint("BOTTOMLEFT", bar.candyBarBar, "TOPLEFT", 2, 2)

		bar.candyBarDuration:ClearAllPoints()
		bar.candyBarDuration:SetPoint("BOTTOMRIGHT", bar.candyBarBar, "TOPRIGHT", -2, 2)
	end

	BigWigsAPI:RegisterBarStyle("MonoUI", {
		apiVersion = 1,
		version = 10,
		barHeight = 20,
		fontSizeNormal = 10,
		fontSizeEmphasized = 11,
		GetSpacing = function(bar) return bar:GetHeight()+6 end,
		ApplyStyle = styleBar,
		BarStopped = removeStyle,
		GetStyleName = function() return "MonoUI" end,
	})
end

do
	-- Tukui
	local C = Tukui and Tukui[2]
	local backdrop = {
		bgFile = "Interface\\Buttons\\WHITE8X8",
		edgeFile = "Interface\\Buttons\\WHITE8X8",
		tile = false, tileSize = 0, edgeSize = 1,
	}
	local borderBackdrop = {
		edgeFile = "Interface\\Buttons\\WHITE8X8",
		edgeSize = 1,
		insets = { left = 1, right = 1, top = 1, bottom = 1 }
	}

	local function removeStyle(bar)
		local bd = bar.candyBarBackdrop
		bd:Hide()
		if bd.tukiborder then
			bd.tukiborder:Hide()
			bd.tukoborder:Hide()
		end
	end

	local function styleBar(bar)
		local bd = bar.candyBarBackdrop
		bd:SetBackdrop(backdrop)

		if C then
			bd:SetBackdropColor(unpack(C.Medias.BackdropColor))
			bd:SetBackdropBorderColor(unpack(C.Medias.BorderColor))
			bd:SetOutside(bar)
		else
			bd:SetBackdropColor(0.1,0.1,0.1)
			bd:SetBackdropBorderColor(0.5,0.5,0.5)
			bd:ClearAllPoints()
			bd:SetPoint("TOPLEFT", bar, "TOPLEFT", -2, 2)
			bd:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 2, -2)
		end

		if not bd.tukiborder then
			local border = CreateFrame("Frame", nil, bd, BackdropTemplateMixin and "BackdropTemplate")
			if C then
				border:SetInside(bd, 1, 1)
			else
				border:SetPoint("TOPLEFT", bd, "TOPLEFT", 1, -1)
				border:SetPoint("BOTTOMRIGHT", bd, "BOTTOMRIGHT", -1, 1)
			end
			border:SetFrameLevel(3)
			border:SetBackdrop(borderBackdrop)
			border:SetBackdropBorderColor(0, 0, 0)
			bd.tukiborder = border
		else
			bd.tukiborder:Show()
		end

		if not bd.tukoborder then
			local border = CreateFrame("Frame", nil, bd, BackdropTemplateMixin and "BackdropTemplate")
			if C then
				border:SetOutside(bd, 1, 1)
			else
				border:SetPoint("TOPLEFT", bd, "TOPLEFT", -1, 1)
				border:SetPoint("BOTTOMRIGHT", bd, "BOTTOMRIGHT", 1, -1)
			end
			border:SetFrameLevel(3)
			border:SetBackdrop(borderBackdrop)
			border:SetBackdropBorderColor(0, 0, 0)
			bd.tukoborder = border
		else
			bd.tukoborder:Show()
		end

		bd:Show()
	end

	BigWigsAPI:RegisterBarStyle("TukUI", {
		apiVersion = 1,
		version = 10,
		barSpacing = 7,
		ApplyStyle = styleBar,
		BarStopped = removeStyle,
		GetStyleName = function() return "TukUI" end,
	})
end

do
	-- ElvUI
	local E = ElvUI and ElvUI[1]
	local backdropBorder = {
		bgFile = "Interface\\Buttons\\WHITE8X8",
		edgeFile = "Interface\\Buttons\\WHITE8X8",
		tile = false, tileSize = 0, edgeSize = 1,
		insets = {left = 0, right = 0, top = 0, bottom = 0}
	}

	local function removeStyle(bar)
		local bd = bar.candyBarBackdrop
		bd:Hide()
		if bd.iborder then
			bd.iborder:Hide()
			bd.oborder:Hide()
		end

		local tex = bar:Get("bigwigs:restoreicon")
		if tex then
			bar:SetIcon(tex)
			bar:Set("bigwigs:restoreicon", nil)

			local iconBd = bar.candyBarIconFrameBackdrop
			iconBd:Hide()
			if iconBd.iborder then
				iconBd.iborder:Hide()
				iconBd.oborder:Hide()
			end
		end
	end

	local function styleBar(bar)
		local bd = bar.candyBarBackdrop

		if E then
			bd:SetTemplate("Transparent")
			bd:SetOutside(bar)
			if not E.PixelMode and bd.iborder then
				bd.iborder:Show()
				bd.oborder:Show()
			end
		else
			bd:SetBackdrop(backdropBorder)
			bd:SetBackdropColor(0.06, 0.06, 0.06, 0.8)
			bd:SetBackdropBorderColor(0, 0, 0)

			bd:ClearAllPoints()
			bd:SetPoint("TOPLEFT", bar, "TOPLEFT", -1, 1)
			bd:SetPoint("BOTTOMRIGHT", bar, "BOTTOMRIGHT", 1, -1)
		end

		local tex = bar:GetIcon()
		if tex then
			local icon = bar.candyBarIconFrame
			bar:SetIcon(nil)
			icon:SetTexture(tex)
			icon:Show()
			if bar.iconPosition == "RIGHT" then
				icon:SetPoint("BOTTOMLEFT", bar, "BOTTOMRIGHT", E and (E.PixelMode and 1 or 5) or 1, 0)
			else
				icon:SetPoint("BOTTOMRIGHT", bar, "BOTTOMLEFT", E and (E.PixelMode and -1 or -5) or -1, 0)
			end
			icon:SetSize(bar:GetHeight(), bar:GetHeight())
			bar:Set("bigwigs:restoreicon", tex)

			local iconBd = bar.candyBarIconFrameBackdrop

			if E then
				iconBd:SetTemplate("Transparent")
				iconBd:SetOutside(bar.candyBarIconFrame)
				if not E.PixelMode and iconBd.iborder then
					iconBd.iborder:Show()
					iconBd.oborder:Show()
				end
			else
				iconBd:SetBackdrop(backdropBorder)
				iconBd:SetBackdropColor(0.06, 0.06, 0.06, 0.8)
				iconBd:SetBackdropBorderColor(0, 0, 0)

				iconBd:ClearAllPoints()
				iconBd:SetPoint("TOPLEFT", icon, "TOPLEFT", -1, 1)
				iconBd:SetPoint("BOTTOMRIGHT", icon, "BOTTOMRIGHT", 1, -1)
			end
			iconBd:Show()
		end

		bd:Show()
	end

	BigWigsAPI:RegisterBarStyle("ElvUI", {
		apiVersion = 1,
		version = 10,
		barSpacing = E and (E.PixelMode and 4 or 8) or 4,
		barHeight = 20,
		ApplyStyle = styleBar,
		BarStopped = removeStyle,
		GetStyleName = function() return "ElvUI" end,
	})
end

--------------------------------------------------------------------------------
-- Options
--

plugin.defaultDB = {
	fontName = plugin:GetDefaultFont(),
	fontSize = 10,
	fontSizeEmph = 13,
	fontSizeNameplate = 7,
	texture = "BantoBar",
	font = nil,
	monochrome = false,
	outline = "NONE",
	growup = false,
	text = true,
	time = true,
	alignText = "LEFT",
	alignTime = "RIGHT",
	icon = true,
	iconPosition = "LEFT",
	fill = false,
	barStyle = "Default",
	emphasize = true,
	emphasizeMove = true,
	emphasizeGrowup = false,
	emphasizeRestart = true,
	emphasizeTime = 11,
	emphasizeMultiplier = 1.1,
	BigWigsAnchor_width = 220,
	BigWigsAnchor_height = 16,
	BigWigsEmphasizeAnchor_width = 320,
	BigWigsEmphasizeAnchor_height = 22,
	nameplateWidth = 100,
	nameplateAutoWidth = true,
	nameplateHeight = 12,
	nameplateAlpha = 0.7,
	nameplateOffsetY = 30,
	nameplateGrowUp = true,
	spacing = 1,
	visibleBarLimit = 100,
	visibleBarLimitEmph = 100,
	interceptMouse = false,
	onlyInterceptOnKeypress = true,
	interceptKey = "CTRL",
	LeftButton = "report",
	MiddleButton = "remove",
	RightButton = "countdown",
}

do
	local function shouldDisable() return not plugin.db.profile.interceptMouse end
	local clickOptions = {
		countdown = {
			type = "toggle",
			name = colorize[L.countdown],
			desc = L.temporaryCountdownDesc,
			descStyle = "inline",
			order = 1,
			width = "full",
			disabled = shouldDisable,
		},
		report = {
			type = "toggle",
			name = colorize[L.report],
			desc = L.reportDesc,
			descStyle = "inline",
			order = 2,
			width = "full",
			disabled = shouldDisable,
		},
		remove = {
			type = "toggle",
			name = colorize[L.remove],
			desc = L.removeBarDesc,
			descStyle = "inline",
			order = 3,
			width = "full",
			disabled = shouldDisable,
		},
		removeOther = {
			type = "toggle",
			name = colorize[L.removeOther],
			desc = L.removeOtherBarDesc,
			descStyle = "inline",
			order = 4,
			width = "full",
			disabled = shouldDisable,
		},
	}

	local function updateFont(info, value)
		if info then
			local key = info[#info]
			if key == "fontName" then
				local list = media:List(FONT)
				db[key] = list[value]
			else
				db[key] = value
			end
		end

		local flags = nil
		if db.monochrome and db.outline ~= "NONE" then
			flags = "MONOCHROME," .. db.outline
		elseif db.monochrome then
			flags = "MONOCHROME"
		elseif db.outline ~= "NONE" then
			flags = db.outline
		end
		local f = media:Fetch(FONT, db.fontName)
		for bar in next, normalAnchor.bars do
			bar.candyBarLabel:SetFont(f, db.fontSize, flags)
			bar.candyBarDuration:SetFont(f, db.fontSize, flags)
		end
		for bar in next, emphasizeAnchor.bars do
			bar.candyBarLabel:SetFont(f, db.fontSizeEmph, flags)
			bar.candyBarDuration:SetFont(f, db.fontSizeEmph, flags)
		end
	end

	local function sortBars(info, value)
		db[info[#info]] = value
		rearrangeBars(normalAnchor)
		rearrangeBars(emphasizeAnchor)
	end

	plugin.pluginOptions = {
		type = "group",
		name = "|TInterface\\AddOns\\BigWigs\\Media\\Icons\\Menus\\Bars:20|t ".. L.bars,
		childGroups = "tab",
		get = function(info)
			return db[info[#info]]
		end,
		set = function(info, value)
			db[info[#info]] = value
			if BigWigsAnchor then
				BigWigsAnchor:RefixPosition()
				BigWigsEmphasizeAnchor:RefixPosition()
			end
		end,
		order = 1,
		args = {
			anchorsButton = {
				type = "execute",
				name = function()
					local BL = BigWigsAPI:GetLocale("BigWigs")
					if BigWigsOptions:InConfigureMode() then
						return BL.toggleAnchorsBtnHide
					else
						return BL.toggleAnchorsBtnShow
					end
				end,
				desc = function()
					local BL = BigWigsAPI:GetLocale("BigWigs")
					if BigWigsOptions:InConfigureMode() then
						return BL.toggleAnchorsBtnHide_desc
					else
						return BL.toggleAnchorsBtnShow_desc
					end
				end,
				func = function() 
					if not BigWigs:IsEnabled() then BigWigs:Enable() end
					if BigWigsOptions:InConfigureMode() then
						plugin:SendMessage("BigWigs_StopConfigureMode")
					else
						plugin:SendMessage("BigWigs_StartConfigureMode")
					end
				end,
				width = 1.5,
				order = 0.2,
			},
			testButton = {
				type = "execute",
				name = BigWigsAPI:GetLocale("BigWigs").testBarsBtn,
				desc = BigWigsAPI:GetLocale("BigWigs").testBarsBtn_desc,
				func = function() 
					BigWigs:Test()
				end,
				width = 1.5,
				order = 0.4,
			},
			custom = {
				type = "group",
				name = L.general,
				order = 1,
				args = {
					fontName = {
						type = "select",
						name = L.font,
						order = 1,
						values = media:List(FONT),
						itemControl = "DDI-Font",
						get = function(info)
							for i, v in next, media:List(FONT) do
								if v == db.fontName then return i end
							end
						end,
						set = updateFont,
					},
					outline = {
						type = "select",
						name = L.outline,
						order = 2,
						values = {
							NONE = L.none,
							OUTLINE = L.thin,
							THICKOUTLINE = L.thick,
						},
						set = updateFont,
					},
					monochrome = {
						type = "toggle",
						name = L.monochrome,
						desc = L.monochromeDesc,
						order = 3,
						set = updateFont,
					},
					header1 = {
						type = "header",
						name = "",
						order = 4,
					},
					barStyle = {
						type = "select",
						name = L.style,
						order = 5,
						values = function() return BigWigsAPI:GetBarStyleList() end,
						set = function(info, value)
							db[info[#info]] = value
							SetBarStyle(value)
							local style = BigWigsAPI:GetBarStyle(value)
							if style then
								if type(style.barSpacing) == "number" and style.barSpacing > 0 and style.barSpacing < 101 then
									db.spacing = style.barSpacing
								else
									db.spacing = plugin.defaultDB.spacing
								end
								rearrangeBars(normalAnchor)
								rearrangeBars(emphasizeAnchor)

								if type(style.barHeight) == "number" and style.barHeight > 0 and style.barHeight < 201 then
									db.BigWigsAnchor_height = style.barHeight
									db.BigWigsEmphasizeAnchor_height = style.barHeight * 1.1
								else
									db.BigWigsAnchor_height = plugin.defaultDB.BigWigsAnchor_height
									db.BigWigsEmphasizeAnchor_height = plugin.defaultDB.BigWigsEmphasizeAnchor_height
								end
								if type(style.fontSizeNormal) == "number" and style.fontSizeNormal > 0 and style.fontSizeNormal < 201 then
									db.fontSize = style.fontSizeNormal
								else
									db.fontSize = plugin.defaultDB.fontSize
								end
								if type(style.fontSizeEmphasized) == "number" and style.fontSizeEmphasized > 0 and style.fontSizeEmphasized < 201 then
									db.fontSizeEmph = style.fontSizeEmphasized
								else
									db.fontSizeEmph = plugin.defaultDB.fontSizeEmph
								end
								if type(style.fontOutline) == "string" and (style.fontOutline == "NONE" or style.fontOutline == "OUTLINE" or style.fontOutline == "THICKOUTLINE") then
									db.outline = style.fontOutline
								else
									db.outline = plugin.defaultDB.outline
								end
								updateFont()

								for bar in next, normalAnchor.bars do
									currentBarStyler.BarStopped(bar)
									bar:SetHeight(db.BigWigsAnchor_height)
									currentBarStyler.ApplyStyle(bar)
								end
								for bar in next, emphasizeAnchor.bars do
									currentBarStyler.BarStopped(bar)
									bar:SetHeight(db.BigWigsEmphasizeAnchor_height)
									currentBarStyler.ApplyStyle(bar)
								end

								BigWigsAnchor:RefixPosition()
								BigWigsEmphasizeAnchor:RefixPosition()
								plugin:UpdateGUI()
							end
						end,
					},
					spacing = {
						type = "range",
						name = L.spacing,
						desc = L.spacingDesc,
						order = 6,
						softMax = 30,
						min = 0,
						max = 100,
						step = 1,
						width = 2,
						set = sortBars,
						disabled = function()
							-- Just throw in a random frame (normalAnchor) instead of a bar to see if it returns a value since we noop() styles that don't have a .GetSpacing entry
							return currentBarStyler.GetSpacing(normalAnchor)
						end,
					},
					fill = {
						type = "toggle",
						name = L.fill,
						desc = L.fillDesc,
						order = 7,
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								bar:SetFill(value)
							end
							for bar in next, emphasizeAnchor.bars do
								bar:SetFill(value)
							end
						end,
					},
					texture = {
						type = "select",
						name = L.texture,
						order = 8,
						width = 2,
						values = media:List(STATUSBAR),
						itemControl = "DDI-Statusbar",
						get = function(info)
							for i, v in next, media:List(STATUSBAR) do
								if v == db[info[#info]] then return i end
							end
						end,
						set = function(info, value)
							local list = media:List(STATUSBAR)
							local tex = list[value]
							db[info[#info]] = tex
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetTexture(media:Fetch(STATUSBAR, tex))
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetTexture(media:Fetch(STATUSBAR, tex))
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					header2 = {
						type = "header",
						name = "",
						order = 9,
					},
					text = {
						type = "toggle",
						name = L.text,
						desc = L.textDesc,
						order = 10,
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetLabelVisibility(value)
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetLabelVisibility(value)
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					alignText = {
						type = "select",
						name = L.alignText,
						order = 11,
						values = {
							LEFT = L.left,
							CENTER = L.center,
							RIGHT = L.right,
						},
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar.candyBarLabel:SetJustifyH(value)
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar.candyBarLabel:SetJustifyH(value)
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					textSpacer = {
						type = "description",
						name = " ",
						order = 12,
					},
					time = {
						type = "toggle",
						name = L.time,
						desc = L.timeDesc,
						order = 13,
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetTimeVisibility(value)
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetTimeVisibility(value)
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					alignTime = {
						type = "select",
						name = L.alignTime,
						order = 14,
						values = {
							LEFT = L.left,
							CENTER = L.center,
							RIGHT = L.right,
						},
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar.candyBarDuration:SetJustifyH(value)
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar.candyBarDuration:SetJustifyH(value)
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					timeSpacer = {
						type = "description",
						name = " ",
						order = 15,
					},
					icon = {
						type = "toggle",
						name = L.icon,
						desc = L.iconDesc,
						order = 16,
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								if value then
									bar:SetIcon(bar:Get("bigwigs:iconoptionrestore") or 134337) -- Interface/Icons/INV_Misc_Orb_05
								else
									bar:Set("bigwigs:iconoptionrestore", bar:GetIcon())
									bar:SetIcon(nil)
								end
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								if value then
									bar:SetIcon(bar:Get("bigwigs:iconoptionrestore") or 134337) -- Interface/Icons/INV_Misc_Orb_05
								else
									bar:Set("bigwigs:iconoptionrestore", bar:GetIcon())
									bar:SetIcon(nil)
								end
								currentBarStyler.ApplyStyle(bar)
							end
						end,
					},
					iconPosition = {
						type = "select",
						name = L.iconPosition,
						desc = L.iconPositionDesc,
						order = 17,
						values = {
							LEFT = L.left,
							RIGHT = L.right,
						},
						set = function(info, value)
							db[info[#info]] = value
							for bar in next, normalAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetIconPosition(value)
								currentBarStyler.ApplyStyle(bar)
							end
							for bar in next, emphasizeAnchor.bars do
								currentBarStyler.BarStopped(bar)
								bar:SetIconPosition(value)
								currentBarStyler.ApplyStyle(bar)
							end
						end,
						disabled = function() return not db.icon end,
					},
					header3 = {
						type = "header",
						name = "",
						order = 18,
					},
					reset = {
						type = "execute",
						name = L.resetAll,
						desc = L.resetBarsDesc,
						func = function() plugin.db:ResetProfile() end,
						order = 19,
					},
				},
			},
			normal = {
				type = "group",
				name = L.bars,
				order = 2,
				args = {
					growup = {
						type = "toggle",
						name = L.growingUpwards,
						desc = L.growingUpwardsDesc,
						order = 1,
						set = sortBars,
					},
					visibleBarLimit = {
						type = "range",
						name = L.visibleBarLimit,
						desc = L.visibleBarLimitDesc,
						order = 2,
						max = 100,
						min = 1,
						step = 1,
						set = sortBars,
					},
					fontSize = {
						type = "range",
						name = L.fontSize,
						desc = L.fontSizeDesc,
						width = 2,
						order = 3,
						max = 200, softMax = 72,
						min = 1,
						step = 1,
						set = updateFont,
					},
					exactPositioning = {
						type = "group",
						name = L.positionExact,
						order = 4,
						inline = true,
						args = {
							BigWigsAnchor_x = {
								type = "range",
								name = L.positionX,
								desc = L.positionDesc,
								min = -2048,
								softMax = 2048,
								step = 1,
								order = 1,
								width = 3.2,
							},
							BigWigsAnchor_y = {
								type = "range",
								name = L.positionY,
								desc = L.positionDesc,
								min = -2048,
								softMax = 2048,
								step = 1,
								order = 2,
								width = 3.2,
							},
							BigWigsAnchor_width = {
								type = "range",
								name = L.width,
								desc = L.sizeDesc,
								min = 80,
								softMax = 2000,
								step = 1,
								order = 3,
								width = 1.6,
							},
							BigWigsAnchor_height = {
								type = "range",
								name = L.height,
								desc = L.sizeDesc,
								min = 8,
								softMax = 150,
								step = 1,
								order = 4,
								width = 1.6,
							},
						},
					},
				},
			},
			emphasize = {
				type = "group",
				name = L.emphasizedBars,
				order = 3,
				args = {
					emphasize = {
						type = "toggle",
						name = L.enable,
						order = 1,
					},
					emphasizeRestart = {
						type = "toggle",
						name = L.restart,
						desc = L.restartDesc,
						order = 2,
					},
					emphasizeGrowup = {
						type = "toggle",
						name = L.growingUpwards,
						desc = L.growingUpwardsDesc,
						order = 3,
						set = sortBars,
						disabled = function() return not db.emphasizeMove end, -- Disable when using 1 anchor
					},
					emphasizeMove = {
						type = "toggle",
						name = L.move,
						desc = L.moveDesc,
						order = 4,
						set = function(_, value)
							db.emphasizeMove = value
							if not value then
								db.BigWigsEmphasizeAnchor_width = db.BigWigsAnchor_width*db.emphasizeMultiplier
								db.BigWigsEmphasizeAnchor_height = db.BigWigsAnchor_height*db.emphasizeMultiplier
							else
								db.BigWigsEmphasizeAnchor_width = BigWigsEmphasizeAnchor:GetWidth()
								db.BigWigsEmphasizeAnchor_height = BigWigsEmphasizeAnchor:GetHeight()
							end
						end,
					},
					emphasizeMultiplier = {
						type = "range",
						name = L.emphasizeMultiplier,
						desc = L.emphasizeMultiplierDesc,
						width = 2,
						order = 5,
						max = 3,
						min = 1,
						step = 0.01,
						set = function(_, value)
							db.emphasizeMultiplier = value
							db.BigWigsEmphasizeAnchor_width = db.BigWigsAnchor_width*value
							db.BigWigsEmphasizeAnchor_height = db.BigWigsAnchor_height*value
						end,
						disabled = function() return db.emphasizeMove end, -- Disable when using 2 anchors
					},
					emphasizeTime = {
						type = "range",
						name = L.emphasizeAt,
						order = 6,
						min = 6,
						max = 20,
						step = 1,
					},
					fontSizeEmph = {
						type = "range",
						name = L.fontSize,
						desc = L.fontSizeDesc,
						order = 7,
						max = 200, softMax = 72,
						min = 1,
						step = 1,
						set = updateFont,
					},
					visibleBarLimitEmph = {
						type = "range",
						name = L.visibleBarLimit,
						desc = L.visibleBarLimitDesc,
						order = 8,
						max = 100,
						min = 1,
						step = 1,
						set = sortBars,
					},
					exactPositioning = {
						type = "group",
						name = L.positionExact,
						order = 9,
						inline = true,
						args = {
							BigWigsEmphasizeAnchor_x = {
								type = "range",
								name = L.positionX,
								desc = L.positionDesc,
								min = -2048,
								softMax = 2048,
								step = 1,
								order = 1,
								width = 3.2,
							},
							BigWigsEmphasizeAnchor_y = {
								type = "range",
								name = L.positionY,
								desc = L.positionDesc,
								min = -2048,
								softMax = 2048,
								step = 1,
								order = 2,
								width = 3.2,
							},
							BigWigsEmphasizeAnchor_width = {
								type = "range",
								name = L.width,
								desc = L.sizeDesc,
								min = 80,
								softMax = 2000,
								step = 1,
								order = 3,
								width = 1.6,
							},
							BigWigsEmphasizeAnchor_height = {
								type = "range",
								name = L.height,
								desc = L.sizeDesc,
								min = 8,
								softMax = 150,
								step = 1,
								order = 4,
								width = 1.6,
							},
						},
					},
				},
			},
			nameplateBars = {
				name = L.nameplateBars,
				type = "group",
				order = 4,
				set = function(info, value)
					db[info[#info]] = value
					if plugin:UnitGUID("target") then
						plugin:NAME_PLATE_UNIT_REMOVED(nil, "target")
						plugin:NAME_PLATE_UNIT_ADDED(nil, "target")
					end
				end,
				args = {
					nameplateWidth = {
						type = "range",
						name = L.width,
						order = 1,
						min = 75,
						softMax = 200,
						step = 1,
						width = 1.6,
						disabled = function() return db.nameplateAutoWidth end,
					},
					nameplateHeight = {
						type = "range",
						name = L.height,
						order = 2,
						min = 8,
						softMax = 50,
						step = 1,
						width = 1.6,
					},
					nameplateAutoWidth = {
						type = "toggle",
						name = L.nameplateAutoWidth,
						desc = L.nameplateAutoWidthDesc,
						order = 3,
						width = 1.6,
					},
					nameplateOffsetY = {
						type = "range",
						name = L.nameplateOffsetY,
						desc = L.nameplateOffsetYDesc,
						order = 4,
						min = 0,
						max = 400,
						step = 1,
						width = 1.6,
					},
					nameplateGrowUp = {
						type = "toggle",
						name = L.growingUpwards,
						desc = L.growingUpwardsDesc,
						order = 5,
						width = 1.6,
					},
					fontSizeNameplate = {
						type = "range",
						name = L.fontSize,
						desc = L.fontSizeDesc,
						order = 6,
						max = 200, softMax = 72,
						min = 1,
						step = 1,
						width = 1.6,
					},
					nameplateAlpha = {
						type = "range",
						name = L.transparency,
						desc = L.nameplateAlphaDesc,
						order = 7,
						max = 1,
						min = 0.4,
						step = 0.1,
						width = 1.6,
					},
				},
			},
			clicking = {
				name = L.clickableBars,
				type = "group",
				order = 5,
				childGroups = "tab",
				get = function(i) return plugin.db.profile[i[#i]] end,
				set = function(i, value)
					local key = i[#i]
					plugin.db.profile[key] = value
					if key == "interceptMouse" then
						plugin:RefixClickIntercepts()
					end
				end,
				args = {
					heading = {
						type = "description",
						name = L.clickableBarsDesc,
						order = 1,
						width = "full",
						fontSize = "medium",
					},
					interceptMouse = {
						type = "toggle",
						name = L.enable,
						desc = L.interceptMouseDesc,
						order = 2,
						width = "full",
					},
					onlyInterceptOnKeypress = {
						type = "toggle",
						name = L.modifierKey,
						desc = L.modifierKeyDesc,
						order = 3,
						disabled = shouldDisable,
					},
					interceptKey = {
						type = "select",
						name = L.modifier,
						desc = L.modifierDesc,
						values = {
							CTRL = _G.CTRL_KEY,
							ALT = _G.ALT_KEY,
							SHIFT = _G.SHIFT_KEY,
						},
						order = 4,
						disabled = function()
							return not plugin.db.profile.interceptMouse or not plugin.db.profile.onlyInterceptOnKeypress
						end,
					},
					LeftButton = {
						type = "group",
						name = KEY_BUTTON1 or "Left",
						order = 10,
						args = clickOptions,
						get = function(info) return plugin.db.profile.LeftButton == info[#info] end,
						set = function(info, value) plugin.db.profile.LeftButton = value and info[#info] or nil end,
					},
					MiddleButton = {
						type = "group",
						name = KEY_BUTTON3 or "Middle",
						order = 11,
						args = clickOptions,
						get = function(info) return plugin.db.profile.MiddleButton == info[#info] end,
						set = function(info, value) plugin.db.profile.MiddleButton = value and info[#info] or nil end,
					},
					RightButton = {
						type = "group",
						name = KEY_BUTTON2 or "Right",
						order = 12,
						args = clickOptions,
						get = function(info) return plugin.db.profile.RightButton == info[#info] end,
						set = function(info, value) plugin.db.profile.RightButton = value and info[#info] or nil end,
					},
				},
			},
		},
	}
end

--------------------------------------------------------------------------------
-- Bar arrangement
--

do
	local function barSorter(a, b)
		return a.remaining < b.remaining and true or false
	end
	rearrangeBars = function(anchor)
		if not anchor then return end
		if anchor == normalAnchor then -- only show the empupdater when there are bars on the normal anchor running
			if next(anchor.bars) and db.emphasize then
				empUpdate:Play()
			else
				empUpdate:Stop()
			end
		end
		if not next(anchor.bars) then return end

		local tmp = {}
		for bar in next, anchor.bars do
			tmp[#tmp + 1] = bar
		end
		table.sort(tmp, barSorter)
		local lastBar = nil
		local up, barLimit
		if anchor == normalAnchor then
			up = db.growup
			barLimit = db.visibleBarLimit
		else
			up = db.emphasizeGrowup
			barLimit = db.visibleBarLimitEmph
		end
		for i = 1, #tmp do
			local bar = tmp[i]
			if i > barLimit then
				bar:SetAlpha(0)
				bar:EnableMouse(false)
			elseif barLimit ~= 100 then
				bar:SetAlpha(1)
				if db.interceptMouse and not db.onlyInterceptOnKeypress then
					bar:EnableMouse(true)
				end
			end
			local spacing = currentBarStyler.GetSpacing(bar) or db.spacing
			bar:ClearAllPoints()
			if up then
				if lastBar then -- Growing from a bar
					bar:SetPoint("BOTTOMLEFT", lastBar, "TOPLEFT", 0, spacing)
				else -- Growing from the anchor
					bar:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT")
				end
				lastBar = bar
			else
				if lastBar then -- Growing from a bar
					bar:SetPoint("TOPLEFT", lastBar, "BOTTOMLEFT", 0, -spacing)
				else -- Growing from the anchor
					bar:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT")
				end
				lastBar = bar
			end
		end
	end
end

do
	-- returns table of bar texts ordered by time remaining
	local function getOrder(bars)
		local barTexts = {}
		for text, _ in pairs(bars) do
			barTexts[#barTexts+1] = text
		end
		table.sort(barTexts, function(a, b)
			return bars[a].bar.remaining < bars[b].bar.remaining
		end)
		return barTexts
	end

	rearrangeNameplateBars = function(guid)
		local unit = findUnitByGUID(guid)
		if not unit then return end
		local nameplate = GetNamePlateForUnit(unit)
		local unitBars = nameplateBars[guid]
		if unitBars then
			local sorted = getOrder(nameplateBars[guid])
			local offset = db.nameplateOffsetY
			local barPoint = db.nameplateGrowUp and "BOTTOM" or "TOP"
			local nameplatePoint = db.nameplateGrowUp and "TOP" or "BOTTOM"
			for i, text in ipairs(sorted) do
				local bar = unitBars[text].bar
				bar:ClearAllPoints()
				bar:SetParent(nameplate)
				bar:SetPoint(barPoint, nameplate, nameplatePoint, 0, db.nameplateGrowUp and offset or -offset)
				offset = offset + db.spacing + bar:GetHeight()
			end
		end
	end
end

local function nameplateCascadeDelete(guid, text)
	nameplateBars[guid][text] = nil
	if not next(nameplateBars[guid]) then
		nameplateBars[guid] = nil
	end
end

local function createDeletionTimer(barInfo)
	return C_Timer.NewTimer(barInfo.exp - GetTime(), function()
		nameplateCascadeDelete(barInfo.unitGUID, barInfo.text)
	end)
end

local function barStopped(event, bar)
	local countdown = bar:Get("bigwigs:stopcountdown")
	if countdown then
		plugin:SendMessage("BigWigs_StopCountdown", plugin, countdown)
	end
	local a = bar:Get("bigwigs:anchor")
	local unitGUID = bar:Get("bigwigs:unitGUID")
	if a and a.bars and a.bars[bar] then
		currentBarStyler.BarStopped(bar)
		a.bars[bar] = nil
		rearrangeBars(a)
	elseif unitGUID then
		currentBarStyler.BarStopped(bar)
		local text = bar:GetLabel()
		nameplateBars[unitGUID][text].bar = nil
		if not bar:Get("bigwigs:offscreen") then
			nameplateCascadeDelete(unitGUID, text)
			rearrangeNameplateBars(unitGUID)
		end
	end
end

--------------------------------------------------------------------------------
-- Anchors
--

local defaultPositions = {
	BigWigsAnchor = {"CENTER", UIParent, "CENTER", 450, 200},
	BigWigsEmphasizeAnchor = {"CENTER", UIParent, "CENTER", 0, -100}, --Below the Emphasized Message frame, ish
}

local function onDragHandleMouseDown(self) self:GetParent():StartSizing("BOTTOMRIGHT") end
local function onDragHandleMouseUp(self) self:GetParent():StopMovingOrSizing() end
local onResize
do
	local throttle = false
	function onResize(self, width, height)
		db[self.w] = width
		db[self.h] = height
		if self == normalAnchor and not db.emphasizeMove then
			-- Move is disabled and we are configuring the normal anchor. Make sure to update the emphasized bars also.
			db[emphasizeAnchor.w] = width * db.emphasizeMultiplier
			db[emphasizeAnchor.h] = height * db.emphasizeMultiplier
		end
		if not throttle then
			throttle = true
			plugin:ScheduleTimer(function()
				for k in next, self.bars do
					currentBarStyler.BarStopped(k)
					if db.emphasizeMove then
						k:SetSize(db[self.w], db[self.h]) -- Move enabled, set the size no matter which anchor we are configuring
					elseif self == normalAnchor then
						-- Move is disabled and we are configuring the normal anchor. Don't apply normal bar sizes to emphasized bars
						if k:Get("bigwigs:emphasized") then
							k:SetSize(db[emphasizeAnchor.w], db[emphasizeAnchor.h])
						else
							k:SetSize(db[self.w], db[self.h])
						end
					end
					currentBarStyler.ApplyStyle(k)
					rearrangeBars(self)
				end
				if self:IsMouseOver() then -- Only if we're dragging the drag handle, not sliding the GUI slider
					plugin:UpdateGUI() -- Update width/height if GUI is open
				end
				throttle = false
			end, 0.1)
		end
	end
end
local function onDragStart(self) self:StartMoving() end
local function onDragStop(self)
	self:StopMovingOrSizing()
	local s = self:GetEffectiveScale()
	db[self.x] = self:GetLeft() * s
	db[self.y] = self:GetTop() * s
	plugin:UpdateGUI() -- Update X/Y if GUI is open
end

do
	local function createAnchor(frameName, title)
		local display = CreateFrame("Frame", frameName, UIParent)
		display.w, display.h, display.x, display.y = frameName .. "_width", frameName .. "_height", frameName .. "_x", frameName .. "_y"
		display:EnableMouse(true)
		display:SetClampedToScreen(true)
		display:SetMovable(true)
		display:SetResizable(true)
		display:RegisterForDrag("LeftButton")
		display:SetMinResize(80, 8)
		display:SetFrameStrata("HIGH")
		display:SetFrameLevel(title == "BigWigsAnchor" and 10 or 15)
		if display.SetFixedFrameStrata then
			display:SetFixedFrameStrata(true)
			display:SetFixedFrameLevel(true)
		end
		local bg = display:CreateTexture(nil, "BACKGROUND")
		bg:SetAllPoints(display)
		bg:SetColorTexture(0, 0, 0, 0.3)
		display.background = bg
		local header = display:CreateFontString(nil, "ARTWORK")
		header:SetFont(plugin:GetDefaultFont(12))
		header:SetShadowOffset(1, -1)
		header:SetTextColor(1,0.82,0,1)
		header:SetText(title)
		header:SetPoint("CENTER", display, "CENTER")
		header:SetJustifyH("CENTER")
		header:SetJustifyV("MIDDLE")
		local drag = CreateFrame("Frame", nil, display)
		drag:SetWidth(16)
		drag:SetHeight(16)
		drag:SetPoint("BOTTOMRIGHT", display, -1, 1)
		drag:EnableMouse(true)
		drag:SetScript("OnMouseDown", onDragHandleMouseDown)
		drag:SetScript("OnMouseUp", onDragHandleMouseUp)
		local tex = drag:CreateTexture(nil, "OVERLAY")
		tex:SetTexture("Interface\\AddOns\\BigWigs\\Media\\Icons\\draghandle")
		tex:SetWidth(16)
		tex:SetHeight(16)
		tex:SetBlendMode("ADD")
		tex:SetPoint("CENTER", drag)
		display:SetScript("OnSizeChanged", onResize)
		display:SetScript("OnDragStart", onDragStart)
		display:SetScript("OnDragStop", onDragStop)
		display.bars = {}
		display.RefixPosition = function(self)
			self:ClearAllPoints()
			if db[self.x] and db[self.y] then
				local s = self:GetEffectiveScale()
				self:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", db[self.x] / s, db[self.y] / s)
			else
				self:SetPoint(unpack(defaultPositions[self:GetName()]))
			end
			self:SetWidth(db[self.w] or plugin.defaultDB[self.w])
			self:SetHeight(db[self.h] or plugin.defaultDB[self.h])
		end
		display:Hide()
		return display
	end

	normalAnchor = createAnchor("BigWigsAnchor", L.bars)
	emphasizeAnchor = createAnchor("BigWigsEmphasizeAnchor", L.emphasizedBars)
end

local function showAnchors()
	normalAnchor:Show()
	emphasizeAnchor:Show()
end

local function hideAnchors()
	normalAnchor:Hide()
	emphasizeAnchor:Hide()
end

local function updateProfile()
	db = plugin.db.profile
	normalAnchor:RefixPosition()
	emphasizeAnchor:RefixPosition()
	if plugin:IsEnabled() then
		if not media:Fetch(STATUSBAR, db.texture, true) then db.texture = "BantoBar" end
		SetBarStyle(db.barStyle)
		plugin:RegisterMessage("DBM_AddonMessage")
	end
	-- XXX temp 9.0.2
	if type(db.LeftButton) ~= "string" then
		db.LeftButton = "report"
	end
	if type(db.MiddleButton) ~= "string" then
		db.MiddleButton = "remove"
	end
	if type(db.RightButton) ~= "string" then
		db.RightButton = "countdown"
	end
end

--------------------------------------------------------------------------------
-- Initialization
--

function plugin:OnRegister()
	candy.RegisterCallback(self, "LibCandyBar_Stop", barStopped)

	self:RegisterMessage("BigWigs_ProfileUpdate", updateProfile)
	updateProfile()
end

function plugin:OnPluginEnable()
	colors = BigWigs:GetPlugin("Colors")
	updateProfile()

	self:RegisterMessage("BigWigs_StartBar")
	self:RegisterMessage("BigWigs_StartNameplateBar")
	self:RegisterMessage("BigWigs_PauseBar", "PauseBar")
	self:RegisterMessage("BigWigs_PauseNameplateBar", "PauseNameplateBar")
	self:RegisterMessage("BigWigs_ResumeBar", "ResumeBar")
	self:RegisterMessage("BigWigs_ResumeNameplateBar", "ResumeNameplateBar")
	self:RegisterMessage("BigWigs_StopBar", "StopSpecificBar")
	self:RegisterMessage("BigWigs_StopNameplateBar", "StopNameplateBar")
	self:RegisterMessage("BigWigs_StopBars", "StopModuleBars")
	self:RegisterMessage("BigWigs_OnBossDisable", "StopModuleBars")
	self:RegisterMessage("BigWigs_OnBossWipe", "StopModuleBars")
	self:RegisterMessage("BigWigs_OnPluginDisable", "StopModuleBars")
	self:RegisterMessage("BigWigs_StartConfigureMode", showAnchors)
	self:RegisterMessage("BigWigs_StopConfigureMode", hideAnchors)
	self:RegisterMessage("BigWigs_ProfileUpdate", updateProfile)

	self:RefixClickIntercepts()
	self:RegisterEvent("MODIFIER_STATE_CHANGED", "RefixClickIntercepts")

	-- Nameplate bars
	self:RegisterEvent("NAME_PLATE_UNIT_ADDED")
	self:RegisterEvent("NAME_PLATE_UNIT_REMOVED")

	-- custom bars
	self:RegisterMessage("BigWigs_PluginComm")
	self:RegisterMessage("DBM_AddonMessage")

	-- XXX temporary workaround for wow custom font loading issues, start a dummy bar to force load the selected font into memory
	self:SendMessage("BigWigs_StartBar", self, nil, "test", 0.01, 134376)

	local tbl = BigWigsClassicDB.breakTime
	if tbl then -- Break time present, resume it
		local prevTime, seconds, nick, isDBM = tbl[1], tbl[2], tbl[3], tbl[4]
		local curTime = time()
		if curTime-prevTime > seconds then
			BigWigsClassicDB.breakTime = nil
		else
			startBreak(seconds-(curTime-prevTime), nick, isDBM, true)
		end
	end
end

function plugin:OnPluginDisable()
	for k in next, normalAnchor.bars do
		k:Stop()
	end
	for k in next, emphasizeAnchor.bars do
		k:Stop()
	end
end

--------------------------------------------------------------------------------
-- Bar styles API
--

do
	local errorDeprecated = "An addon registered the bar style '%s' using the old method. Visit github.com/BigWigsMods/BigWigs/wiki/Custom-Bar-Styles to learn how to do it correctly."
	function plugin:RegisterBarStyle(key, styleData)
		BigWigs:Print(errorDeprecated:format(key))
		BigWigsAPI:RegisterBarStyle(key, styleData)
	end
end

do
	function plugin:SetBarStyle(styleName)
		-- Ask users to select your bar styles. Forcing a selection is deprecated.
		-- This is to allow users to install multiple styles gracefully, and to encourage authors to use new style entry APIs like `.barHeight` or `.fontSizeNormal`
		-- Want more style API entries? We're open to suggestions!
		BigWigs:Print(("SetBarStyle is deprecated, bar style '%s' was not set automatically, you may need to set it yourself."):format(styleName))
	end
	local errorNoStyle = "No style with the ID %q has been registered. Reverting to default style."
	function SetBarStyle(styleName)
		local style = BigWigsAPI:GetBarStyle(styleName)
		if not style then
			BigWigs:Print(errorNoStyle:format(styleName))
			styleName = "Default"
		end
		style = BigWigsAPI:GetBarStyle(styleName)

		-- Iterate all running bars
		if currentBarStyler then
			if normalAnchor then
				for bar in next, normalAnchor.bars do
					currentBarStyler.BarStopped(bar)
					bar.candyBarBackdrop:Hide()
					style.ApplyStyle(bar)
				end
			end
			if emphasizeAnchor then
				for bar in next, emphasizeAnchor.bars do
					currentBarStyler.BarStopped(bar)
					bar.candyBarBackdrop:Hide()
					style.ApplyStyle(bar)
				end
			end
		end
		currentBarStyler = style

		rearrangeBars(normalAnchor)
		rearrangeBars(emphasizeAnchor)

		if db then
			db.barStyle = styleName
		end
	end
end

--------------------------------------------------------------------------------
-- Pausing bars
--

function plugin:PauseBar(_, module, text)
	if not normalAnchor then return end
	for k in next, normalAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Pause()
			return
		end
	end
	for k in next, emphasizeAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Pause()
			return
		end
	end
end

function plugin:PauseNameplateBar(_, module, text, unitGUID)
	local barInfo = nameplateBars[unitGUID] and nameplateBars[unitGUID][text]
	if barInfo and not barInfo.paused then
		barInfo.paused = true
		if barInfo.bar then
			barInfo.bar:Pause()
		else
			barInfo.deletionTimer:Cancel()
		end
		barInfo.remaining = barInfo.exp - GetTime()
	end
end

function plugin:ResumeBar(_, module, text)
	if not normalAnchor then return end
	for k in next, normalAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Resume()
			return
		end
	end
	for k in next, emphasizeAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Resume()
			return
		end
	end
end

function plugin:ResumeNameplateBar(_, module, text, unitGUID)
	local barInfo = nameplateBars[unitGUID] and nameplateBars[unitGUID][text]
	if barInfo and barInfo.paused then
		barInfo.paused = false
		barInfo.exp = GetTime() + barInfo.remaining
		if barInfo.bar then
			barInfo.bar:Resume()
		else
			barInfo.deletionTimer = createDeletionTimer(barInfo)
		end
		barInfo.remaining = nil
	end
end

--------------------------------------------------------------------------------
-- Stopping bars
--

function plugin:StopSpecificBar(_, module, text)
	if not normalAnchor then return end
	for k in next, normalAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Stop()
		end
	end
	for k in next, emphasizeAnchor.bars do
		if k:Get("bigwigs:module") == module and k:GetLabel() == text then
			k:Stop()
		end
	end
end

function plugin:StopNameplateBar(_, module, text, guid)
	if not nameplateBars[guid] then return end
	local barInfo = nameplateBars[guid][text]
	if barInfo and barInfo.module == module then
		if barInfo.bar then
			barInfo.bar:Stop()
		else
			barInfo.deletionTimer:Cancel()
			nameplateCascadeDelete(guid, text)
		end
	end
end

function plugin:StopModuleBars(_, module)
	if not normalAnchor then return end
	for k in next, normalAnchor.bars do
		if k:Get("bigwigs:module") == module then
			k:Stop()
		end
	end
	for k in next, emphasizeAnchor.bars do
		if k:Get("bigwigs:module") == module then
			k:Stop()
		end
	end
	for _, bars in next, nameplateBars do
		for _, barInfo in next, bars do
			if barInfo.module == module then
				if barInfo.bar then
					barInfo.bar:Stop()
				else
					barInfo.deletionTimer:Cancel()
					nameplateCascadeDelete(barInfo.unitGUID, barInfo.text)
				end
			end
		end
	end
end

--------------------------------------------------------------------------------
-- Bar utility functions
--

function plugin:HasActiveBars()
	if next(normalAnchor.bars) then
		return true
	end
	if next(emphasizeAnchor.bars) then
		return true
	end
	return false
end

function plugin:GetBarTimeLeft(module, text)
	if normalAnchor then
		for k in next, normalAnchor.bars do
			if k:Get("bigwigs:module") == module and k:GetLabel() == text then
				return k.remaining
			end
		end
		for k in next, emphasizeAnchor.bars do
			if k:Get("bigwigs:module") == module and k:GetLabel() == text then
				return k.remaining
			end
		end
	end
	return 0
end

function plugin:GetNameplateBarTimeLeft(module, text, guid)
	if nameplateBars[guid] then
		local barInfo = nameplateBars[guid][text]
		local bar = barInfo and barInfo.bar
		if bar and bar:Get("bigwigs:module") == module then
			return bar.remaining
		else
			return barInfo.paused and barInfo.remaining or barInfo.exp - GetTime()
		end
	end
	return 0
end

--------------------------------------------------------------------------------
-- Clickable bars
--

local function barClicked(bar, button)
	local action = plugin.db.profile[button]
	if action and clickHandlers[action] then
		clickHandlers[action](bar)
	end
end

local function barOnEnter(bar)
	bar.candyBarBackground:SetVertexColor(1, 1, 1, 0.8)
end
local function barOnLeave(bar)
	local module = bar:Get("bigwigs:module")
	local key = bar:Get("bigwigs:option")
	bar.candyBarBackground:SetVertexColor(colors:GetColor("barBackground", module, key))
end

local function refixClickOnBar(intercept, bar)
	if intercept then
		bar:EnableMouse(true)
		bar:SetScript("OnMouseDown", barClicked)
		bar:SetScript("OnEnter", barOnEnter)
		bar:SetScript("OnLeave", barOnLeave)
	else
		bar:EnableMouse(false)
		bar:SetScript("OnMouseDown", nil)
		bar:SetScript("OnEnter", nil)
		bar:SetScript("OnLeave", nil)
	end
end
local function refixClickOnAnchor(intercept, anchor)
	for bar in next, anchor.bars do
		if not intercept or bar:GetAlpha() > 0 then -- Don't enable for hidden bars
			refixClickOnBar(intercept, bar)
		end
	end
end

do
	local keymap = {
		LALT = "ALT", RALT = "ALT",
		LSHIFT = "SHIFT", RSHIFT = "SHIFT",
		LCTRL = "CTRL", RCTRL = "CTRL",
	}
	function plugin:RefixClickIntercepts(event, key, state)
		if not db.interceptMouse or not normalAnchor then return end
		if not db.onlyInterceptOnKeypress or (db.onlyInterceptOnKeypress and type(key) == "string" and db.interceptKey == keymap[key] and state == 1) then
			refixClickOnAnchor(true, normalAnchor)
			refixClickOnAnchor(true, emphasizeAnchor)
		else
			refixClickOnAnchor(false, normalAnchor)
			refixClickOnAnchor(false, emphasizeAnchor)
		end
	end
end

-- Enable countdown on the clicked bar
clickHandlers.countdown = function(bar)
	-- Add 0.2sec here to catch messages for this option triggered when the bar ends.
	local text = bar:GetLabel()
	bar:Set("bigwigs:stopcountdown", text)
	plugin:SendMessage("BigWigs_StartCountdown", plugin, nil, text, bar.remaining)
end

-- Report the bar status to the active group type (raid, party, solo)
do
	local tformat1 = "%d:%02d"
	local tformat2 = "%1.1f"
	local tformat3 = "%.0f"
	local function timeDetails(t)
		if t >= 3600 then -- > 1 hour
			local h = floor(t/3600)
			local m = t - (h*3600)
			return tformat1:format(h, m)
		elseif t >= 60 then -- 1 minute to 1 hour
			local m = floor(t/60)
			local s = t - (m*60)
			return tformat1:format(m, s)
		elseif t < 10 then -- 0 to 10 seconds
			return tformat2:format(t)
		else -- 10 seconds to one minute
			return tformat3:format(floor(t + .5))
		end
	end
	local SendChatMessage = BigWigsLoader.SendChatMessage
	clickHandlers.report = function(bar)
		local text = ("%s: %s"):format(bar:GetLabel(), timeDetails(bar.remaining))
		SendChatMessage(text, (IsInGroup(2) and "INSTANCE_CHAT") or (IsInRaid() and "RAID") or (IsInGroup() and "PARTY") or "SAY")
	end
end

-- Removes the clicked bar
clickHandlers.remove = function(bar)
	bar:Stop()
end

-- Removes all bars EXCEPT the clicked one
clickHandlers.removeOther = function(bar)
	if normalAnchor then
		for k in next, normalAnchor.bars do
			if k ~= bar then
				k:Stop()
			end
		end
	end
	if emphasizeAnchor then
		for k in next, emphasizeAnchor.bars do
			if k ~= bar then
				k:Stop()
			end
		end
	end
end

-----------------------------------------------------------------------
-- Start bars
--

function plugin:CreateBar(module, key, text, time, icon, isApprox, unitGUID)
	local width, height
	if unitGUID then
		width, height = db.nameplateWidth, db.nameplateHeight
		if db.nameplateAutoWidth then
			local unit = findUnitByGUID(unitGUID)
			if unit then
				local nameplate = GetNamePlateForUnit(unit)
				local npWidth = nameplate and nameplate:GetWidth() or 110
				if npWidth < 111 then
					width = npWidth
				else
					width = 110
				end
			end
		end
	else
		width, height = db.BigWigsAnchor_width, db.BigWigsAnchor_height
	end
	local bar = candy:New(media:Fetch(STATUSBAR, db.texture), width, height)
	bar.candyBarBackground:SetVertexColor(colors:GetColor("barBackground", module, key))
	bar:Set("bigwigs:module", module)
	bar:Set("bigwigs:option", key)
	if unitGUID then
		bar:Set("bigwigs:unitGUID", unitGUID)
	else
		bar:Set("bigwigs:anchor", normalAnchor)
		normalAnchor.bars[bar] = true
	end
	bar:SetIcon(db.icon and icon or nil)
	bar:SetLabel(text)
	bar:SetDuration(time, isApprox)
	bar:SetColor(colors:GetColor("barColor", module, key))
	bar:SetTextColor(colors:GetColor("barText", module, key))
	bar:SetShadowColor(colors:GetColor("barTextShadow", module, key))
	bar.candyBarLabel:SetJustifyH(db.alignText)
	bar.candyBarDuration:SetJustifyH(db.alignTime)
	local flags = nil
	if db.monochrome and db.outline ~= "NONE" then
		flags = "MONOCHROME," .. db.outline
	elseif db.monochrome then
		flags = "MONOCHROME"
	elseif db.outline ~= "NONE" then
		flags = db.outline
	end
	local f = media:Fetch(FONT, db.fontName)
	if unitGUID then
		bar.candyBarLabel:SetFont(f, db.fontSizeNameplate, flags)
		bar.candyBarDuration:SetFont(f, db.fontSizeNameplate, flags)
		bar:SetAlpha(db.nameplateAlpha)
	else
		bar.candyBarLabel:SetFont(f, db.fontSize, flags)
		bar.candyBarDuration:SetFont(f, db.fontSize, flags)
	end

	bar:SetTimeVisibility(db.time)
	bar:SetLabelVisibility(db.text)
	bar:SetIconPosition(db.iconPosition)
	bar:SetFill(db.fill)

	if db.interceptMouse and not db.onlyInterceptOnKeypress and not unitGUID then
		refixClickOnBar(true, bar)
	end

	return bar
end

function plugin:BigWigs_StartBar(_, module, key, text, time, icon, isApprox)
	if not text then text = "" end
	self:StopSpecificBar(nil, module, text)

	local bar = self:CreateBar(module, key, text, time, icon, isApprox)
	bar:Start()
	if db.emphasize and time < db.emphasizeTime then
		self:EmphasizeBar(bar, true)
	else
		currentBarStyler.ApplyStyle(bar)
	end
	rearrangeBars(bar:Get("bigwigs:anchor"))

	self:SendMessage("BigWigs_BarCreated", self, bar, module, key, text, time, icon, isApprox)
	-- Check if :EmphasizeBar(bar) was run and trigger the callback.
	-- Bit of a roundabout method to approaching this so that we purposely keep callbacks firing last.
	if bar:Get("bigwigs:emphasized") then
		self:SendMessage("BigWigs_BarEmphasized", self, bar)
	end
end

function plugin:BigWigs_StartNameplateBar(_, module, key, text, time, icon, isApprox, unitGUID)
	if not text then text = "" end
	self:StopNameplateBar(nil, module, text, unitGUID)

	if not nameplateBars[unitGUID] then nameplateBars[unitGUID] = {} end
	local barInfo = {
		module = module,
		key = key,
		text = text,
		time = time,
		exp = GetTime() + time,
		icon = icon,
		isApprox = isApprox,
		unitGUID = unitGUID,
	}
	nameplateBars[unitGUID][text] = barInfo

	local unit = findUnitByGUID(unitGUID)
	if unit then
		local bar = self:CreateBar(module, key, text, time, icon, isApprox, unitGUID)
		barInfo.bar = bar
		bar:Start()
		rearrangeNameplateBars(unitGUID)
	else
		barInfo.deletionTimer = createDeletionTimer(barInfo)
	end
end

--------------------------------------------------------------------------------
-- Emphasize
--

do
	local dirty = nil
	local frame = CreateFrame("Frame")
	empUpdate = frame:CreateAnimationGroup()
	empUpdate:SetScript("OnLoop", function()
		for k in next, normalAnchor.bars do
			if k.remaining < db.emphasizeTime and not k:Get("bigwigs:emphasized") then
				dirty = true
				plugin:EmphasizeBar(k)
				plugin:SendMessage("BigWigs_BarEmphasized", plugin, k)
			end
		end
		if dirty then
			rearrangeBars(normalAnchor)
			rearrangeBars(emphasizeAnchor)
			dirty = nil
		end
	end)
	empUpdate:SetLooping("REPEAT")

	local anim = empUpdate:CreateAnimation()
	anim:SetDuration(0.2)
end

function plugin:EmphasizeBar(bar, freshBar)
	if db.emphasizeMove then
		normalAnchor.bars[bar] = nil
		emphasizeAnchor.bars[bar] = true
		bar:Set("bigwigs:anchor", emphasizeAnchor)
	end
	if not freshBar then
		currentBarStyler.BarStopped(bar) -- Only call BarStopped on bars that have already started (ApplyStyle was called on them first)
		if db.emphasizeRestart then
			bar:Start() -- restart the bar -> remaining time is a full length bar again after moving it to the emphasize anchor
		end
	end
	local module = bar:Get("bigwigs:module")
	local key = bar:Get("bigwigs:option")

	local flags = nil
	if db.monochrome and db.outline ~= "NONE" then
		flags = "MONOCHROME," .. db.outline
	elseif db.monochrome then
		flags = "MONOCHROME"
	elseif db.outline ~= "NONE" then
		flags = db.outline
	end
	local f = media:Fetch(FONT, db.fontName)
	bar.candyBarLabel:SetFont(f, db.fontSizeEmph, flags)
	bar.candyBarDuration:SetFont(f, db.fontSizeEmph, flags)

	bar:SetColor(colors:GetColor("barEmphasized", module, key))
	bar:SetHeight(db.BigWigsEmphasizeAnchor_height)
	bar:SetWidth(db.BigWigsEmphasizeAnchor_width)
	currentBarStyler.ApplyStyle(bar)
	bar:Set("bigwigs:emphasized", true)
end

--------------------------------------------------------------------------------
-- Custom Bars
--

local function parseTime(input)
	if type(input) == "nil" then return end
	if tonumber(input) then return tonumber(input) end
	if type(input) == "string" then
		input = input:trim()
		if input:find(":") then
			local _, _, m, s = input:find("^(%d+):(%d+)$")
			if not tonumber(m) or not tonumber(s) then return end
			return (tonumber(m) * 60) + tonumber(s)
		elseif input:find("^%d+mi?n?$") then
			local _, _, t = input:find("^(%d+)mi?n?$")
			return tonumber(t) * 60
		end
	end
end

local startCustomBar
do
	local timers, prevBars
	function startCustomBar(bar, nick, localOnly, isDBM)
		if not timers then timers, prevBars = {}, {} end

		local seconds, barText
		if localOnly then
			seconds, barText, nick = bar, localOnly, L.localTimer
		else
			if prevBars[bar] and GetTime() - prevBars[bar] < 1.2 then return end -- Throttle
			prevBars[bar] = GetTime()
			if not UnitIsGroupLeader(nick) and not UnitIsGroupAssistant(nick) then return end
			seconds, barText = bar:match("(%S+) (.*)")
			seconds = parseTime(seconds)
			if type(seconds) ~= "number" or type(barText) ~= "string" or seconds < 0 then
				return
			end
			BigWigs:Print(L.customBarStarted:format(barText, isDBM and "DBM" or "BigWigs", nick))
		end

		local id = "bwcb" .. nick .. barText
		if timers[id] then
			plugin:CancelTimer(timers[id])
			timers[id] = nil
		end

		nick = nick:gsub("%-.+", "*") -- Remove server name
		if seconds == 0 then
			plugin:SendMessage("BigWigs_StopBar", plugin, nick..": "..barText)
		else
			timers[id] = plugin:ScheduleTimer("SendMessage", seconds, "BigWigs_Message", plugin, false, L.timerFinished:format(nick, barText), "yellow", 134376)
			plugin:SendMessage("BigWigs_StartBar", plugin, id, nick..": "..barText, seconds, 134376) -- 134376 = "Interface\\Icons\\INV_Misc_PocketWatch_01"
		end
	end
end

do
	local timerTbl, lastBreak = nil, 0
	function startBreak(seconds, nick, isDBM, reboot)
		if not reboot then
			if (not UnitIsGroupLeader(nick) and not UnitIsGroupAssistant(nick) and not UnitIsUnit(nick, "player")) or IsEncounterInProgress() then return end
			seconds = tonumber(seconds)
			if not seconds or seconds < 0 or seconds > 3600 or (seconds > 0 and seconds < 60) then return end -- 1h max, 1m min

			local t = GetTime()
			if t-lastBreak < 0.5 then return else lastBreak = t end -- Throttle
		end

		if timerTbl then
			for i = 1, #timerTbl do
				plugin:CancelTimer(timerTbl[i])
			end
			if seconds == 0 then
				timerTbl = nil
				BigWigsClassicDB.breakTime = nil
				BigWigs:Print(L.breakStopped:format(nick))
				plugin:SendMessage("BigWigs_StopBar", plugin, L.breakBar)
				plugin:SendMessage("BigWigs_StopBreak", plugin, seconds, nick, isDBM, reboot)
				return
			end
		end

		if not reboot then
			BigWigsClassicDB.breakTime = {time(), seconds, nick, isDBM}
		end

		BigWigs:Print(L.breakStarted:format(isDBM and "DBM" or "BigWigs", nick))

		timerTbl = {}
		if seconds > 30 then
			timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds - 30, "BigWigs_Message", plugin, nil, L.breakSeconds:format(30), "orange", 134062) -- 134062 = "Interface\\Icons\\inv_misc_fork&knife"
		end
		if seconds > 10 then
			timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds - 10, "BigWigs_Message", plugin, nil, L.breakSeconds:format(10), "orange", 134062)
		end
		if seconds > 5 then
			timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds - 5, "BigWigs_Message", plugin, nil, L.breakSeconds:format(5), "orange", 134062)
		end
		timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds, "BigWigs_Message", plugin, nil, L.breakFinished, "red", 134062)
		timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds, "BigWigs_Sound", plugin, nil, "Long")
		timerTbl[#timerTbl+1] = plugin:ScheduleTimer(function() BigWigsClassicDB.breakTime = nil timerTbl = nil end, seconds)

		if seconds > 119 then -- 2min
			timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", seconds - 60, "BigWigs_Message", plugin, nil, L.breakMinutes:format(1), "yellow", 134062)
		end
		if seconds > 239 then -- 4min
			local half = seconds / 2
			local m = half % 60
			local halfMin = (half - m) / 60
			timerTbl[#timerTbl+1] = plugin:ScheduleTimer("SendMessage", half + m, "BigWigs_Message", plugin, nil, L.breakMinutes:format(halfMin), "yellow", 134062)
		end

		plugin:SendMessage("BigWigs_Message", plugin, nil, seconds < 61 and L.breakSeconds:format(seconds) or L.breakMinutes:format(seconds/60), "green", 134062)
		if not reboot then
			plugin:SendMessage("BigWigs_Sound", plugin, nil, "Long")
		end
		plugin:SendMessage("BigWigs_StartBar", plugin, nil, L.breakBar, seconds, 134062)
		plugin:SendMessage("BigWigs_StartBreak", plugin, seconds, nick, isDBM, reboot)
	end
end

function plugin:DBM_AddonMessage(_, sender, prefix, seconds, text)
	if prefix == "U" then
		startCustomBar(seconds.." "..text, sender, nil, true)
	elseif prefix == "BT" then
		startBreak(seconds, sender, true)
	end
end

function plugin:BigWigs_PluginComm(_, msg, seconds, sender)
	if seconds then
		if msg == "CBar" then
			startCustomBar(seconds, sender)
		elseif msg == "Break" then
			startBreak(seconds, sender)
		end
	end
end

-------------------------------------------------------------------------------
-- Nameplate bar management
--

function plugin:NAME_PLATE_UNIT_ADDED(_, unit)
	local guid = plugin:UnitGUID(unit)
	local unitBars = nameplateBars[guid]
	if not unitBars then return end
	for _, barInfo in next, unitBars do
		local time = barInfo.paused and barInfo.remaining or barInfo.exp - GetTime()
		local bar = plugin:CreateBar(
			barInfo.module,
			barInfo.key,
			barInfo.text,
			time,
			barInfo.icon,
			barInfo.isApprox,
			barInfo.unitGUID
		)
		barInfo.bar = bar
		barInfo.deletionTimer:Cancel()
		barInfo.deletionTimer = nil
		bar:Start(barInfo.time)
		if barInfo.paused then
			bar:Pause()
		end
	end
	rearrangeNameplateBars(guid)
end

function plugin:NAME_PLATE_UNIT_REMOVED(_, unit)
	local guid = plugin:UnitGUID(unit)
	local unitBars = nameplateBars[guid]
	if not unitBars then return end

	for _, barInfo in next, unitBars do
		barInfo.bar:Set("bigwigs:offscreen", true)
		barInfo.bar:Stop()
		if not barInfo.paused then
			barInfo.deletionTimer = createDeletionTimer(barInfo)
		end
	end
end

-------------------------------------------------------------------------------
-- Slashcommand
--

local SendAddonMessage = BigWigsLoader.SendAddonMessage
local isBC = BigWigsLoader.isBC
do
	local times
	SlashCmdList.BIGWIGSRAIDBAR = function(input)
		if not plugin:IsEnabled() then BigWigs:Enable() end

		if not IsInGroup() or (not UnitIsGroupLeader("player") and not UnitIsGroupAssistant("player")) then BigWigs:Print(L.requiresLeadOrAssist) return end

		local seconds, barText = input:match("(%S+) (.*)")
		if not seconds or not barText then BigWigs:Print(L.wrongCustomBarFormat) return end

		seconds = parseTime(seconds)
		if not seconds or seconds < 0 then BigWigs:Print(L.wrongTime) return end

		if not times then times = {} end
		local t = GetTime()
		if not times[input] or (times[input] and (times[input] + 2) < t) then
			times[input] = t
			BigWigs:Print(L.sendCustomBar:format(barText))
			plugin:Sync("CBar", input)
			SendAddonMessage(isBC and "D4BC" or "D4C", ("U\t%d\t%s"):format(seconds, barText), IsInGroup(2) and "INSTANCE_CHAT" or "RAID") -- DBM message
		end
	end
	SLASH_BIGWIGSRAIDBAR1 = "/raidbar"
end

SlashCmdList.BIGWIGSLOCALBAR = function(input)
	if not plugin:IsEnabled() then BigWigs:Enable() end

	local seconds, barText = input:match("(%S+) (.*)")
	if not seconds or not barText then BigWigs:Print(L.wrongCustomBarFormat:gsub("/raidbar", "/localbar")) return end

	seconds = parseTime(seconds)
	if not seconds then BigWigs:Print(L.wrongTime) return end

	startCustomBar(seconds, plugin:UnitName("player"), barText)
end
SLASH_BIGWIGSLOCALBAR1 = "/localbar"

SlashCmdList.BIGWIGSBREAK = function(input)
	if not plugin:IsEnabled() then BigWigs:Enable() end
	if IsEncounterInProgress() then BigWigs:Print(L.encounterRestricted) return end -- Doesn't make sense to allow this in combat
	if not IsInGroup() or UnitIsGroupLeader("player") or UnitIsGroupAssistant("player") then -- Solo or leader/assist
		local minutes = tonumber(input)
		if not minutes or minutes < 0 or minutes > 60 or (minutes > 0 and minutes < 1) then BigWigs:Print(L.wrongBreakFormat) return end -- 1h max, 1m min

		if minutes ~= 0 then
			BigWigs:Print(L.sendBreak)
		end
		local seconds = minutes * 60
		plugin:Sync("Break", seconds)

		if IsInGroup() then
			SendAddonMessage(isBC and "D4BC" or "D4C", ("BT\t%d"):format(seconds), IsInGroup(2) and "INSTANCE_CHAT" or "RAID") -- DBM message
		end
	else
		BigWigs:Print(L.requiresLeadOrAssist)
	end
end
SLASH_BIGWIGSBREAK1 = "/break"
