-- Colour tables now taken from WoW values (Since 1.6.4) - Well, we want to be ready when there's Paladin and Shaman in same raid
-- and we can leave the colour choice up to Blizzard and it'll just all work.

local conf
XPerl_RequestConfig(function(new) conf = new end)

if (not XPerl_Tutorial) then
	function XPerl_Tutorial()
	end
end

-- We craeted our string based colour table from Blizzard's raid colour table in
XPerlColourTable = {}
for class,c in pairs(RAID_CLASS_COLORS) do
	XPerlColourTable[class] = format("|c00%02X%02X%02X", 255 * c.r, 255 * c.g, 255 * c.b)
end

XPerl_AnchorList = {"TOP", "LEFT", "BOTTOM", "RIGHT"}

-- BestBandage
function FindABandage()
	local prefix, suffix = "Heavy ", " Bandage"
	local Bandages = {"Netherweave", "Runecloth", "Mageweave", "Silk", "Wool", "Linen"}

	if (GetLocale() == "deDE") then
		prefix, suffix = "Schwerer ", "stoffverband"
		Bandages = {"Runen", "Magie", "Seiden", "Woll", "Leinen"}
	elseif (GetLocale() == "zhTW") then
		prefix, suffix = "厚", "繃帶"
		Bandages = {"符文布", "魔紋", "絲質", "絨線", "亞麻"}
	end

	-- Didn't do French cos.... well, I just couldn't be bothered with the syntax, cos it's totally different and I'm lazy

	for k,v in pairs(Bandages) do
		if (GetItemCount(prefix..v..suffix) > 0) then
			return prefix..v..suffix
		elseif (GetItemCount(v..suffix) > 0) then
			return v..suffix
		end
	end
end

local playerClass

-- We have a dummy do-nothing function here for classes that don't have range checking
-- The do-something function is setup after variables_loaded and we work out spell to use just once
function XPerl_UpdateSpellRange()
	return
end

-- DoRangeCheck
local function DoRangeCheck(self, unit, opt)

	local range
	if (opt.PlusHealth) then
		local hp, hpMax = UnitHealth(unit), UnitHealthMax(unit)
		if (hp / hpMax > opt.HealthLowPoint) then
			range = 0
		end
	end

	if (not range and opt.PlusDebuff) then
		local name = UnitDebuff(unit, 1, 1)
		if (not name) then
			range = 0
		end
	end

	if (not range) then
		if (opt.spell) then
			range = IsSpellInRange(opt.spell, unit)
		elseif (opt.item) then
			range = IsItemInRange(opt.item, unit)
		else
			range = 1
		end
	end

	if (range ~= 1) then
		return conf.Transparency * opt.FadeAmount
	end
end

-- XPerl_UpdateSpellRange(self)
function XPerl_UpdateSpellRange2(self, overrideUnit)
	local unit
	if (overrideUnit) then
		unit = overrideUnit
	else
		unit = self:GetAttribute("unit")
		if (not unit) then
			unit = SecureButton_GetUnit(self)
		end
	end
	if (unit) then
		local rf = conf.RangeFinder
		local mainA, nameA, statsA		-- Receives main, name and stats alpha levels

		if (rf.enabled) then
			if (not UnitIsVisible(unit)) then
				if (rf.Main.enabled) then
					mainA = conf.Transparency * rf.Main.FadeAmount
				else
					if (rf.NameFrame.enabled) then
						nameA = conf.Transparency * rf.NameFrame.FadeAmount
					end
					if (rf.StatsFrame.enabled) then
						statsA = conf.Transparency * rf.StatsFrame.FadeAmount
					end
				end

			elseif (UnitCanAssist("player", unit)) then
				if (rf.Main.enabled) then
					mainA = DoRangeCheck(self, unit, rf.Main)
				end

				if (rf.NameFrame.enabled) then
					-- check for same item/spell. Saves doing the check multiple times
					if (rf.Main.enabled and (rf.Main.spell == rf.NameFrame.spell) and (rf.Main.item == rf.NameFrame.item) and (rf.Main.PlusHealth == rf.NameFrame.PlusHealth)) then
						if (mainA) then
							nameA = rf.NameFrame.FadeAmount
						end
					else
						nameA = DoRangeCheck(self.nameFrame, unit, rf.NameFrame)
						if (not nameA and mainA) then
							-- In range, but 'Whole' frame is out of range, so we need to override the fade for name
							nameA = conf.Transparency
						end
					end
				end
				if (rf.StatsFrame.enabled) then
					-- check for same item/spell. Saves doing the check multiple times
					if (rf.Main.enabled and (rf.Main.spell == rf.StatsFrame.spell) and (rf.Main.item == rf.StatsFrame.item) and (rf.Main.PlusHealth == rf.StatsFrame.PlusHealth)) then
						if (mainA) then
							statsA = rf.StatsFrame.FadeAmount
						end
					else
						statsA = DoRangeCheck(self.statsFrame, unit, rf.StatsFrame)
						if (not statsA and mainA) then
							-- In range, but 'Whole' frame is out of range, so we need to override the fade for stats
							statsA = conf.Transparency
						end
					end
				end
			end
		end

		local forcedMainA
		if (not mainA) then
			if (UnitIsConnected(unit)) then
				mainA = conf.Transparency
				forcedMainA = true
			else
				mainA = conf.Transparency * rf.Main.FadeAmount
				nameA, statsA = mainA
				forcedMainA = true
			end
		end

--if (self == XPerl_Target) then
--   ChatFrame7:AddMessage(format("%4s %4s %4s", tostring(mainA), tostring(nameA), tostring(statsA)))
--end

		self:SetAlpha(mainA)
		if (nameA or forcedMainA) then
			if (self.nameFrame) then
				self.nameFrame:SetAlpha(nameA or mainA)
			end
		end
		if (nameA or forcedMainA) then
			if (self.statsFrame) then
				self.statsFrame:SetAlpha(statsA or mainA)
			end
		end
	end
end

-- XPerl_StartupSpellRange()
function XPerl_StartupSpellRange()
	local _
	_, playerClass = UnitClass("player")

	local b = FindABandage()
	if (b) then
		XPerl_DefaultRangeSpells.ANY.item = b
	end

	local rf = conf.RangeFinder

	local function Setup1(self)
		local reset
		if (type(self.spell) ~= "string" or type(self.item) ~= "string") then
			reset = true

		elseif (self.item and not GetItemInfo(self.item)) then
			reset = true
		end

		if (reset) then
			self.spell = XPerl_DefaultRangeSpells[playerClass] and XPerl_DefaultRangeSpells[playerClass].spell
			if (type(self.spell) ~= "string") then
				self.item = XPerl_DefaultRangeSpells.ANY.item
			end
		end

		if (not self.FadeAmount) then
			self.FadeAmount = 0.3
		end
		if (not self.HealthLowPoint) then
			self.HealthLowPoint = 0.7
		end
	end

	Setup1(rf.Main)
	Setup1(rf.NameFrame)
	Setup1(rf.StatsFrame)

	--if (rangeCheckSpell) then
		-- Put the real work function in place
		XPerl_UpdateSpellRange = XPerl_UpdateSpellRange2
	--else
	--	XPerl_UpdateSpellRange = function() end
	--end
end

-- XPerl_StatsFrame_SetGrey
local function XPerl_StatsFrame_SetGrey(self)
	self.healthBar:SetStatusBarColor(0.5, 0.5, 0.5, 1)
	self.healthBar.bg:SetVertexColor(0.5, 0.5, 0.5, 0.5)
	self.manaBar:SetStatusBarColor(0.5, 0.5, 0.5, 1)
	self.manaBar.bg:SetVertexColor(0.5, 0.5, 0.5, 0.5)
	self.greyMana = true
end

-- XPerl_SetChildMembers - Recursive
-- This iterates a frame's child frames and regions and assigns member variables
-- based on the sub-set part of the child's name compared to the parent frame name
function XPerl_SetChildMembers(self)
	local n = self:GetName()
	if (n) then
		local match = "^"..n.."(.+)$"

		local function AddList(list)
			for k,v in pairs(list) do
				local t = v:GetName()
				if (t) then
					local found = strmatch(t, match)
					if (found) then
						--if (self[found] == v) then
						--	break		-- Already done
						--end
						self[found] = v
					end
				end
			end
		end

		AddList({self:GetRegions()})

		local c = {self:GetChildren()}
		AddList(c)

		for k,v in pairs(c) do
			if (v:GetName()) then
				XPerl_SetChildMembers(v)
			end
		end
	end
end

-- XPerl_StatsFrame_Setup
function XPerl_StatsFrame_Setup(self)
	XPerl_SetChildMembers(self)
	self.SetGrey = XPerl_StatsFrame_SetGrey
end

-- XPerl_GetClassColour
function XPerl_GetClassColour(class)
	if (class) then
		local color = RAID_CLASS_COLORS[class];		-- Now using the WoW class color table
		if (color) then
			return color
		end
	end
	return {r = 0.5, g = 0.5, b = 1}
end

-- XPerl_IsFeignDeath(unit)
function XPerl_IsFeignDeath(unit)
	for i = 1,20 do
		local name, rank, buff = UnitBuff(unit, i)

		if (buff) then
			if (strfind(strlower(buff), "feigndeath")) then
				return true
			end
		else
			break
		end
	end
end

---------------------------------
--Loading Function             --
---------------------------------

-- XPerl_BlizzFrameDisable
function XPerl_BlizzFrameDisable(self)
	self:UnregisterAllEvents()
	self:Hide()
	-- Make it so it won't be visible, even if shown by another mod
	self:ClearAllPoints()
	self:SetPoint("BOTTOMLEFT", UIParent, "TOPLEFT", -400, 500)

	local healthBar = getglobal(self:GetName().."HealthBar")
	if (healthBar) then
		healthBar:UnregisterAllEvents()
	end

	local manaBar = getglobal(self:GetName().."ManaBar")
	if (manaBar) then
		manaBar:UnregisterAllEvents()
	end
end

---------------------------------
--Smooth Health Bar Color      --
---------------------------------
function XPerl_SetSmoothBarColor(bar, percentage)
	if (bar) then
		local r, g, b
		if (conf.ClassicHealthBar == 1) then
			if (percentage < 0.5) then
				r = 1
				g = 2*percentage
				b = 0
			else
				g = 1
				r = 2*(1 - percentage)
				b = 0
			end
		else
			r = conf.ColourHealthEmpty.r + ((conf.ColourHealthFull.r - conf.ColourHealthEmpty.r) * percentage)
			g = conf.ColourHealthEmpty.g + ((conf.ColourHealthFull.g - conf.ColourHealthEmpty.g) * percentage)
			b = conf.ColourHealthEmpty.b + ((conf.ColourHealthFull.b - conf.ColourHealthEmpty.b) * percentage)
		end

		if (r >= 0 and g >= 0 and b >= 0 and r <= 1 and g <= 1 and b <= 1) then
			bar:SetStatusBarColor(r, g, b)

			if (bar.bg) then
				bar.bg:SetVertexColor(r, g, b, 0.25)
			end
		end
	end
end

-- XPerl_SetHealthBar
function XPerl_SetHealthBar(bar, hp, max, healerMode, healerModeType)
	bar:SetMinMaxValues(0, max)
	if (conf.InverseBars == 1) then
		bar:SetValue(max - hp)
	else
		bar:SetValue(hp)
	end

	local percent = hp / max
	local healthPct = format("%3.0f", percent * 100)

	XPerl_SetSmoothBarColor(bar, percent)

	if (bar.percent) then
		bar.percent:SetText(healthPct.."%")
	end

	if (bar.text) then
		if (healerMode == 1) then
			if (healerModeType == 1) then
				bar.text:SetText(format("%d/%d", hp - max, max))
			else
				bar.text:SetText(hp - max)
			end
		else
			bar.text:SetText(hp.."/"..max)
		end
	end
end

---------------------------------
--Class Icon Location Functions--
---------------------------------
function XPerl_ClassPos (class)
	if(class=="WARRIOR") then return 0,    0.25,    0,	0.25;	end
	if(class=="MAGE")    then return 0.25, 0.5,     0,	0.25;	end
	if(class=="ROGUE")   then return 0.5,  0.75,    0,	0.25;	end
	if(class=="DRUID")   then return 0.75, 1,       0,	0.25;	end
	if(class=="HUNTER")  then return 0,    0.25,    0.25,	0.5;	end
	if(class=="SHAMAN")  then return 0.25, 0.5,     0.25,	0.5;	end
	if(class=="PRIEST")  then return 0.5,  0.75,    0.25,	0.5;	end
	if(class=="WARLOCK") then return 0.75, 1,       0.25,	0.5;	end
	if(class=="PALADIN") then return 0,    0.25,    0.5,	0.75;	end
	return 0.25, 0.5, 0.5, 0.75	-- Returns empty next one, so blank
end

-- XPerl_Toggle
function XPerl_Toggle()
	if (XPerlLocked == 1) then
		XPerl_UnlockFrames()
	else
		XPerl_LockFrames()
	end
end

-- XPerl_UnlockFrames
function XPerl_UnlockFrames()
	EnableAddOn("XPerl_Options")
	if (not IsAddOnLoaded("XPerl_Options")) then
		local loaded, reason = LoadAddOn("XPerl_Options")
		if (not loaded) then
			XPerl_Notice("Failed to load X-Perl Options ("..reason..")")
		end
	end

	XPerlLocked = 0

	if (XPerl_Party_Virtual) then
		XPerl_Party_Virtual(true)
	end

	if (XPerl_Options) then
		XPerl_Tutorial(7)
		XPerl_Options:Show()
		XPerl_Options:SetAlpha(0)
		XPerl_Options.Fading = "in"
	end

	if (XPerl_RaidTitles) then
		XPerl_RaidTitles()
		if (XPerl_RaidPets_Titles) then
			XPerl_RaidPets_Titles()
		end
	end
end

-- XPerl_LockFrames
function XPerl_LockFrames()
	XPerlLocked = 1
	if (XPerl_Options) then
		XPerl_Options.Fading = "out"
	end

	if (XPerl_Party_Virtual) then
		XPerl_Party_Virtual()
	end

	if (XPerl_RaidTitles) then
		XPerl_RaidTitles()
		if (XPerl_RaidPets_Titles) then
			XPerl_RaidPets_Titles()
		end
	end

	XPerl_OptionActions()
end

-- Minimap Icon
function XPerl_MinimapButton_OnClick(self)
	XPerl_Toggle()
end

-- XPerl_MinimapButton_Init
function XPerl_MinimapButton_Init(self)
	if(conf.MinimapButtonShown == 1) then
		self:Show()
	else
		self:Hide()
	end
end

-- XPerl_MinimapButton_UpdatePosition
function XPerl_MinimapButton_UpdatePosition(self)
	self:SetPoint(
		"TOPLEFT",
		"Minimap",
		"TOPLEFT",
		54 - (78 * cos(conf.MinimapButtonPosition)),
		(78 * sin(conf.MinimapButtonPosition)) - 55
	)
	XPerl_MinimapButton_Init(self)
end

-- XPerl_MinimapButton_Dragging
function XPerl_MinimapButton_Dragging(self)
	local xpos,ypos = GetCursorPosition()
	local xmin,ymin = Minimap:GetLeft(), Minimap:GetBottom()

	xpos = xmin-xpos/UIParent:GetScale()+70
	ypos = ypos/UIParent:GetScale()-ymin-70

	XPerl_MinimapButton_SetPosition(self, math.deg(math.atan2(ypos,xpos)))
end

-- XPerl_MinimapButton_SetPosition
function XPerl_MinimapButton_SetPosition(self, v)
	if (v < 0) then
		v = v + 360
	end

	conf.MinimapButtonPosition = v
	XPerl_MinimapButton_UpdatePosition(self)
end

-- XPerl_MinimapButton_OnEnter
function XPerl_MinimapButton_OnEnter(self)
	XPerl_Tutorial(1)			-- Minimap Icon/Options

	GameTooltip:SetOwner(self, "ANCHOR_LEFT")
	GameTooltip:SetText(XPerl_Version, 1, 1, 1)
	GameTooltip:AddLine(XPERL_MINIMAP_HELP1)
	GameTooltip:AddLine(XPERL_MINIMAP_HELP2)

	if (GetRealNumRaidMembers) then
		if (GetNumRaidMembers() > 0 and GetRealNumRaidMembers() > 0) then
			if (IsInInstance() and GetNumWorldStateUI() > 0) then
				GameTooltip:AddLine(format(XPERL_MINIMAP_HELP3, GetRealNumRaidMembers(), GetRealNumPartyMembers()))

				if (IsRealPartyLeader()) then
					GameTooltip:AddLine(XPERL_MINIMAP_HELP4)
				end
			end
		end
	end

	GameTooltip:Show()
end

-- XPerl_SetManaBarType
local ManaColours = {"ColourMana", "ColourRage", "ColourFocus", "ColourEnergy"}
function XPerl_SetManaBarType(self)
	local unit = self:GetAttribute("unit")
	if (unit) then
		local p = UnitPowerType(unit)
		if (p) then
			local c = conf[ManaColours[p + 1]]

			self.statsFrame.manaBar:SetStatusBarColor(c.r, c.g, c.b, 1)
			self.statsFrame.manaBar.bg:SetVertexColor(c.r, c.g, c.b, 0.25)
		end
	end
end

-- XPerl_PlayerTip
function XPerl_PlayerTip(self, unitid)
	if (not unitid) then
		unitid = SecureButton_GetUnit(self)
	end

	if (not unitid or XPerlLocked == 0 or conf.UnitTooltips == 0) then
		return
	end

	local mod = conf.UnitTooltipsModifiers
	if (mod == "alt" and not IsAltKeyDown()) then
		return
	elseif (mod == "shift" and not IsShiftKeyDown()) then
		return
	elseif (mod == "control" and not IsControlKeyDown()) then
		return
	end

        if (SpellIsTargeting()) then
                if (SpellCanTargetUnit(unitid)) then
                        SetCursor("CAST_CURSOR")
                else
                        SetCursor("CAST_ERROR_CURSOR")
                end
        end

	GameTooltip_SetDefaultAnchor(GameTooltip, this)
	GameTooltip:SetUnit(unitid)

	if (XPerl_RaidTipExtra) then
		XPerl_RaidTipExtra(unitid)
	end

	if (conf.XPerlTooltipInfo == 1 and XPerl_GetUsage and not strmatch(unitid, "pet")) then
		local xpUsage = XPerl_GetUsage(UnitName(unitid))
		if (xpUsage) then
			local xp, any = "|cFFD00000X-Perl|r "
			if (xpUsage.version) then
				xp = xp..xpUsage.version
			else
				xp = xp..XPerl_VersionNumber
			end
			any = true

			if (xpUsage.mods and IsShiftKeyDown()) then
				local modList = XPerl_DecodeModuleList(xpUsage.mods)
				if (modList) then
					xp = xp.." : |c00909090"..modList
				end
			end
			if (any) then
				GameTooltip:AddLine(xp, 1, 1, 1, 1)
				GameTooltip:Show()
			end
		end
	end

	XPerl_Highlight:TooltipInfo(UnitName(unitid))
end

-- XPerl_PlayerTipHide
function XPerl_PlayerTipHide()
	if (conf.FadingTooltip == 1) then
		GameTooltip:FadeOut()
	else
		GameTooltip:Hide()
	end
end

-- XPerl_ToolTip_AddBuffDuration
function XPerl_ToolTip_AddBuffDuration(partyid, x)
	if (XPerl_Raid_AddBuffDuration) then
		XPerl_Raid_AddBuffDuration(partyid, x)
	end
end

-- XPerl_ToolTip_AddBuffDuration
function XPerl_ToolTip_AddDebuffDuration(partyid, x, index, cureCast)
	if (XPerl_Raid_AddDebuffDuration) then
		XPerl_Raid_AddDebuffDuration(partyid, x, index, cureCast)
	end
end

-- XPerl_ColourFriendlyUnit
function XPerl_ColourFriendlyUnit(frame, partyid)
	local color
	if (UnitCanAttack("player", partyid) and UnitIsEnemy("player", partyid)) then	-- For dueling
		color = conf.ColourReactionEnemy
	else
		if (conf.ClassColouredNames == 1) then
			local _, engClass = UnitClass(partyid)
			color = XPerl_GetClassColour(engClass)
		else
			if (UnitIsPVP(partyid)) then
				color = conf.ColourReactionFriend
			else
				color = conf.ColourReactionNone
			end
		end
	end

	frame:SetTextColor(color.r, color.g, color.b, conf.TextTransparency)
end

-- XPerl_ReactionColour
function XPerl_ReactionColour(argUnit)

        if (UnitPlayerControlled(argUnit) or not UnitIsVisible(argUnit)) then
                if (UnitFactionGroup("player") == UnitFactionGroup(argUnit)) then
                        if (UnitIsEnemy("player", argUnit)) then
				-- Dueling
				return conf.ColourReactionEnemy

                        elseif (UnitIsPVP(argUnit)) then
				return conf.ColourReactionFriend
			end
		else
                        if (UnitIsPVP(argUnit)) then
				if (UnitIsPVP("player")) then
					return conf.ColourReactionEnemy
				else
					return conf.ColourReactionNeutral
				end
			end
		end
	else
                if (UnitIsTapped(argUnit) and not UnitIsTappedByPlayer(argUnit)) then
                        return conf.ColourTapped
                else
			local reaction = UnitReaction(argUnit, "player")
			if (reaction) then
				if (reaction >= 5) then
					return conf.ColourReactionFriend
				elseif (reaction <= 2) then
					return conf.ColourReactionEnemy
				elseif (reaction == 3) then
					return conf.ColourReactionUnfriendly
				else
					return conf.ColourReactionNeutral
				end
			else
				if (UnitFactionGroup("player") == UnitFactionGroup(argUnit)) then
					return conf.ColourReactionFriend
				elseif (UnitIsEnemy("player", argUnit)) then
					return conf.ColourReactionEnemy
				else
					return conf.ColourReactionNeutral
				end
			end
		end
	end

	return conf.ColourReactionNone
end

-- XPerl_SetUnitNameColor
function XPerl_SetUnitNameColor(argUnit,argFrame)
	local color
        if (UnitPlayerControlled(argUnit) or not UnitIsVisible(argUnit)) then
		-- 1.8.3 - Changed to override pvp name colours
		if (conf.ClassColouredNames == 1) then
			local _, class = UnitClass(argUnit)
			color = XPerl_GetClassColour(class)
		else
			color = XPerl_ReactionColour(argUnit)
		end
	else
                if (UnitIsTapped(argUnit) and not UnitIsTappedByPlayer(argUnit)) then
                        color = conf.ColourTapped
                else
			color = XPerl_ReactionColour(argUnit)
		end
	end

	argFrame:SetTextColor(color.r, color.g, color.b, conf.TextTransparency)
end

-- XPerl_UnitEvents
local unitEvents = {}
function XPerl_UnitEvents(self, eventArray, eventList)

	local unit = self.partyid
	if (not unit) then
		unit = self:GetAttribute("unit")
		if (not unit) then
			return
		end
	end

--ChatFrame1:AddMessage("XPerl_UnitEvents - self:"..self:GetName()..", unit:"..(unit or "nil"))

	local a = unitEvents[unit]
	if (not a) then
		a = {}
		unitEvents[unit] = a
	end

	a.array = eventArray
	for k,v in pairs(eventList) do
		local selves = a[v]
		if (not selves) then
			selves = {}
			a[v] = selves
		end
		tinsert(selves, self)
		XPerl_Globals:RegisterEvent(v)
	end
end

function XPerl_UnitEvent(unit, event)
	local a = unitEvents[unit]
	if (a) then
		local selves = a[event]
		if (selves) then
			local array = a.array
			if (array) then
				for k,v in pairs(selves) do
--ChatFrame1:AddMessage("Event: |c0080FF80"..event.."|r, unit = |c00FFFF80"..unit.."|r, self = |c0080FFFF"..v:GetName())
					array[event](v)
				end
				return true
			end
		end
	end

--ChatFrame1:AddMessage("Event: |c0080FF80"..event.."|r, unit = |c00FFFF80"..unit.."|r, NOT SENT")
end

-- XPerl_RegisterBasics
function XPerl_RegisterBasics(self, events)
	XPerl_UnitEvents(self, events, {"UNIT_RAGE", "UNIT_MAXRAGE", "UNIT_ENERGY", "UNIT_MAXENERGY",
			"UNIT_MANA", "UNIT_MAXMANA", "UNIT_HEALTH", "UNIT_MAXHEALTH",
			"UNIT_LEVEL", "UNIT_DISPLAYPOWER", "UNIT_NAME_UPDATE"})
end

-- PerlSetPortrait3D
function XPerlSetPortrait3D(self, argUnit)
	self:ClearModel()
	self:SetUnit(argUnit)
	self:SetCamera(0)
end

-- XPerl_CombatFlashSet
function XPerl_CombatFlashSet (elapsed, self, argNew, argGreen)
	if (conf.PerlCombatFlash == 0) then
		self.PlayerFlash = nil
		return false
	end

	if (self) then
		if (argNew) then
			self.PlayerFlash = 1
			self.PlayerFlashGreen = argGreen
			self.PlayerFlashHold = 0.5
		else
			if (elapsed) then
				if (self.PlayerFlashHold) then
					self.PlayerFlashHold = self.PlayerFlashHold - elapsed
					if (self.PlayerFlashHold <= 0) then
						self.PlayerFlashHold = nil
					end

				elseif (self.PlayerFlash) then
					self.PlayerFlash = self.PlayerFlash - elapsed

					if (self.PlayerFlash <= 0) then
						self.PlayerFlash = 0
						self.PlayerFlashTime = nil
						self.PlayerFlashGreen = nil
						self.PlayerFlashHold = nil
					end
				else
					return false
				end
			else
				return false
			end
		end

		return true
	end
end

-- XPerl_CombatFlashSetFrames
function XPerl_CombatFlashSetFrames(self)
	if (self.PlayerFlash) then
		local baseColour
		if (self.forcedColour) then
			baseColour = self.forcedColour
		else
			baseColour = conf.BorderColour
		end

		local r, g, b, a
		if (self.PlayerFlash > 0) then
			local flashOffsetColour = self.PlayerFlash / 2
			if (self.PlayerFlashGreen) then
				r = baseColour.r - flashOffsetColour
				g = baseColour.g + flashOffsetColour
				b = baseColour.b - flashOffsetColour
				a = baseColour.a + flashOffsetColour
			else
				r = baseColour.r + flashOffsetColour
				g = baseColour.g - flashOffsetColour
				b = baseColour.b - flashOffsetColour
				a = baseColour.a + flashOffsetColour
			end

			if (r < 0) then r = 0; elseif (r > 1) then r = 1; end
			if (g < 0) then g = 0; elseif (g > 1) then g = 1; end
			if (b < 0) then b = 0; elseif (b > 1) then b = 1; end
			if (a < 0) then a = 0; elseif (a > 1) then a = 1; end
		else
			r, g, b = baseColour.r, baseColour.g, baseColour.b, baseColour.a
		end

		if (not a) then
			a = conf.BorderColour.a
		end

		for i, frame in pairs(self.FlashFrames) do
			frame:SetBackdropBorderColor(r, g, b, a)
		end

		if (self.PlayerFlash == 0) then
			self.PlayerFlash = nil
		end
	end
end

local bgDef = {bgFile = "Interface\\Addons\\XPerl\\Images\\XPerl_FrameBack",
	       edgeFile = "",
	       tile = true, tileSize = 32, edgeSize = 16,
	       insets = { left = 5, right = 5, top = 5, bottom = 5 }
		}

-- XPerl_CheckDebuffs
function XPerl_CheckDebuffs(self, unit)
	if (not unit) then
		unit = self:GetAttribute("unit")
		if (not unit) then
			return
		end
	end

	local high = (conf.HighlightDebuffs == 1) or (self == XPerl_Target and conf.TargetDebuffHighlight == 1)

	if (not high) then
		if (self.FlashFrames) then
			-- Reset the frame edges back to normal in case they changed options while debuffed.
			self.forcedColour = nil
			bgDef.edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border"
			for i, f in pairs(self.FlashFrames) do
				f:SetBackdrop(bgDef)
				f:SetBackdropColor(conf.BackColour.r, conf.BackColour.g, conf.BackColour.b, conf.BackColour.a)
				f:SetBackdropBorderColor(conf.BorderColour.r, conf.BorderColour.g, conf.BorderColour.b, conf.BorderColour.a)
			end
		end
		return
	end

	local show
	local Curses = {}
	local debuffCount = 0

	for i = 1, 40 do
		local _,_, debuff, debuffStack, debuffType = UnitDebuff(unit, i)

		if (not debuff) then
			break
		end

		if (debuffType) then
			Curses[debuffType] = debuffType
			debuffCount = debuffCount + 1
		end
	end

	if (debuffCount > 0) then
		if (conf.HighlightDebuffsClass == 0) then
			show = Curses.Magic or Curses.Curse or Curses.Poison or Curses.Disease
		end

		-- We also re-set the colours here so that we highlight best colour per class
		if (playerClass == "MAGE") then
			show = Curses.Curse or show

		elseif (playerClass == "DRUID") then
			show = Curses.Curse or Curses.Poison or show

		elseif (playerClass == "PRIEST") then
			show = Curses.Magic or Curses.Disease or show

		elseif (playerClass == "WARLOCK") then
			show = Curses.Magic or show

		elseif (playerClass == "PALADIN") then
			show = Curses.Magic or Curses.Poison or Curses.Disease or show

		elseif (playerClass == "SHAMAN") then
			show = Curses.Poison or Curses.Disease or show

		elseif (playerClass == "ROGUE") then
			show = Curses.Poison or show
		end
	end

	local colour, borderColour
	if (show) then
		colour = DebuffTypeColor[show]
		colour.a = 1

		if (conf.HighlightDebuffsBorder > 0) then
			borderColour = colour
		else
			borderColour = conf.BorderColour
		end
	else
		colour = conf.BackColour
		borderColour = conf.BorderColour
	end

	if (self.FlashFrames) then
		if (show and conf.HighlightDebuffsBorder > 0) then
			self.forcedColour = borderColour
		else
			self.forcedColour = nil
		end

		for i, f in pairs(self.FlashFrames) do
			if (show and conf.HighlightDebuffsBorder > 0) then
				bgDef.edgeFile = "Interface\\Addons\\XPerl\\Images\\XPerl_Curse"
				f:SetBackdrop(bgDef)
			else
				bgDef.edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border"
				f:SetBackdrop(bgDef)
			end

			if (conf.HighlightDebuffsBorder == 2) then
				colour = conf.BackColour
			end
			f:SetBackdropColor(colour.r, colour.g, colour.b, colour.a)
			f:SetBackdropBorderColor(borderColour.r, borderColour.g, borderColour.b, borderColour.a)
		end
	end
end

-- XPerl_SavePosition(frame)
function XPerl_SavePosition(frame)
	if (not conf.SavedPositions) then
		conf.SavedPositions = {}
	end
	conf.SavedPositions[frame:GetName()] = {top = frame:GetTop(), left = frame:GetLeft()}
end

-- XPerl_RestorePosition(frame)
function XPerl_RestorePosition(frame)
	if (conf.SavedPositions) then
		local pos = conf.SavedPositions[frame:GetName()]
		if (pos) then
			if (pos.left or pos.right) then
				frame:ClearAllPoints()
				frame:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", pos.left, pos.top)
			end
		end
	end
end

-- true indicates the buff is valid on anyone, otherwise a class string dictates we only count it if the player with the buff matches
local BuffExceptions = {
	--ALL = {Spell_Misc_Food = true},	-- Enable this for food
	PRIEST = {Spell_Nature_ResistNature = true, Spell_Nature_Rejuvenation = true},	-- Druid regens
	DRUID = {Spell_Holy_Renew = true},		-- Priest regens
	WARLOCK = {Spell_Shadow_SoulGem = true},	-- Soulstone Resurrection
	HUNTER = {Spell_Nature_RavenForm = "HUNTER", Ability_Mount_JungleTiger = "HUNTER", Ability_Mount_WhiteTiger = true, Ability_Mount_PinkTiger = "HUNTER", Ability_Hunter_AspectOfTheMonkey = "HUNTER", Spell_Nature_ProtectionformNature = true, Ability_Rogue_FeignDeath = "HUNTER", Ability_Hunter_RunningShot = "HUNTER", Ability_TrueShot = true, Ability_Hunter_BeastTraining = "WARRIOR"},
	ROGUE = {Ability_Stealth = "ROGUE", Spell_Shadow_ShadowWard = "ROGUE", Ability_Vanish = "ROGUE", Ability_Rogue_Sprint = "ROGUE"}
}

local DebuffExceptions = {
	ALL = {INV_Misc_Bandage_08 = true},		-- Recently Bandaged
	PRIEST = {Spell_Holy_AshesToAshes = true}	-- Weakened Soul
}

-- BuffException
--local showInfo
local function BuffException(unit, index, flag, func, exceptions)

	local name, rank, buff, count, debuffType
	if (not flag or flag == 0 or flag == "0") then
		-- Not filtered, just return it
		name, rank, buff, count, debuffType = func(unit, index)
		return name, rank, buff, count, debuffType, index
	end

	name, rank, buff, count, debuffType = func(unit, index, 1)
	if (buff) then
		--if (showInfo) then
		--	ChatFrame7:AddMessage("Found buff with normal filter at index "..index)
		--end
		-- We need the index of the buff unfiltered later for tooltips
		for i = 1,20 do
			local name1, rank1, buff1, count1, debuffType1 = func(unit, i)
			if (name == name1 and rank == rank1 and buff == buff1 and count == count1) then
				index = i
				break
			end
		end

		return name, rank, buff, count, debuffType, index
	end

	-- See how many filtered buffs WoW has returned by default
	local normalBuffFilterCount = 0
	for i = 1,20 do
		name, rank, buff, count, debuffType = func(unit, i, 1)
		if (not buff) then
			normalBuffFilterCount = i - 1
			break
		end
	end

	-- Nothing found by default, so look for exceptions
	local _, unitClass = UnitClass(unit)
	local foundValid = 0
	for i = 1,20 do
		name, rank, buff, count, debuffType = func(unit, i)

		if (not buff) then
			break
		end

		if (strsub(buff, 1, 16) == "Interface\\Icons\\") then
			local test = strsub(buff, 17)
			local good

			if (exceptions[playerClass]) then
				good = exceptions[playerClass][test]
			elseif (exceptions.ALL) then
				good = exceptions.ALL[test]
			end

			-- Enable this for potions
			--if (not good) then
			--	if (exceptions == BuffExceptions and strsub(test, 1, 11) == "INV_Potion_") then
			--		good = true
			--	end
			--end

			if (good and type(good) == "string" and good ~= unitClass) then
				good = nil
			end

			if (good) then
				foundValid = foundValid + 1
				if (foundValid + normalBuffFilterCount == index) then
					--if (showInfo) then
					--	ChatFrame7:AddMessage("Found extra: "..buff..", requested index == "..index..", actual buff index == "..i)
					--end
					return name, rank, buff, count, debuffType, i
				end
			end
		end
	end
end

-- XPerl_UnitBuff
function XPerl_UnitBuff(unit, index, flag)
	return BuffException(unit, index, flag, UnitBuff, BuffExceptions)
end

-- XPerl_UnitBuff
function XPerl_UnitDebuff(unit, index, flag)
	return BuffException(unit, index, flag, UnitDebuff, DebuffExceptions)
end

-- XPerl_TooltipSetUnitBuff
-- Retreives the index of the actual unfiltered buff, and uses this on unfiltered tooltip call
function XPerl_TooltipSetUnitBuff(tooltip, unit, ind, flag)
	--showInfo = true
	local name, rank, buff, count, _, index = BuffException(unit, ind, flag, UnitBuff, BuffExceptions)
	--showInfo = nil
	tooltip:SetUnitBuff(unit, index)
end

-- XPerl_TooltipSetUnitDebuff
-- Retreives the index of the actual unfiltered debuff, and uses this on unfiltered tooltip call
function XPerl_TooltipSetUnitDebuff(tooltip, unit, ind, flag)
	local name, rank, buff, count, debuffType, index = BuffException(unit, ind, flag, UnitDebuff, DebuffExceptions)
	tooltip:SetUnitDebuff(unit, index)
end

local colourList = {
		[XPERL_LOC_CLASS_WARRIOR]	= "WARRIOR",
		[XPERL_LOC_CLASS_MAGE]		= "MAGE",
		[XPERL_LOC_CLASS_ROGUE]		= "ROGUE",
		[XPERL_LOC_CLASS_DRUID]		= "DRUID",
		[XPERL_LOC_CLASS_HUNTER]	= "HUNTER",
		[XPERL_LOC_CLASS_SHAMAN]	= "SHAMAN",
		[XPERL_LOC_CLASS_PRIEST]	= "PRIEST",
		[XPERL_LOC_CLASS_WARLOCK]	= "WARLOCK",
		[XPERL_LOC_CLASS_PALADIN]	= "PALADIN"}

-- XPerl_GuildStatusUpdate()
function XPerl_GuildStatusUpdate()
	if (conf.ClassColouredNames == 1 or conf.XPerlTooltipInfo == 1) then
		local myZone = GetRealZoneText()

		local guildOffset = FauxScrollFrame_GetOffset(GuildListScrollFrame)
		for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
			local guildIndex = guildOffset + i

			local button = getglobal("GuildFrameButton"..i);
			button.guildIndex = guildIndex;
			local name, rank, rankIndex, level, class, zone, note, officernote, online = GetGuildRosterInfo(guildIndex)
			if (not name) then
				break
			end

			if (conf.XPerlTooltipInfo == 1 and XPerl_GetUsage) then
				local u = XPerl_GetUsage(name)

				if (u) then
					if (online) then
						getglobal("GuildFrameButton"..i.."Name"):SetTextColor(1, 0.4, 0.4)
						getglobal("GuildFrameGuildStatusButton"..i.."Name"):SetTextColor(1, 0.4, 0.4)
					else
						getglobal("GuildFrameButton"..i.."Name"):SetTextColor(0.5, 0.2, 0.2)
						getglobal("GuildFrameGuildStatusButton"..i.."Name"):SetTextColor(0.5, 0.2, 0.2)
					end
				end
			end

			if (conf.ClassColouredNames == 1 and conf.ApplyToGuildList == 1) then
				class = colourList[class]

				if (class) then
					local color = XPerl_GetClassColour(class)
					if (color) then
						if (online) then
							getglobal("GuildFrameButton"..i.."Class"):SetTextColor(color.r, color.g, color.b)
						else
							getglobal("GuildFrameButton"..i.."Class"):SetTextColor(color.r / 2, color.g / 2, color.b / 2)
						end
					end
				end

				if (zone == myZone) then
					if (online) then
						getglobal("GuildFrameButton"..i.."Zone"):SetTextColor(0, 1, 0)
					else
						getglobal("GuildFrameButton"..i.."Zone"):SetTextColor(0, 0.5, 0)
					end
				end

				local color = GetDifficultyColor(level)
				if (online) then
					getglobal("GuildFrameButton"..i.."Level"):SetTextColor(color.r, color.g, color.b)
				else
					getglobal("GuildFrameButton"..i.."Level"):SetTextColor(color.r / 2, color.g / 2, color.b / 2)
				end
			end
		end
	end
end

hooksecurefunc("GuildStatus_Update", XPerl_GuildStatusUpdate)

-- XPerl_WhoList_Update
function XPerl_WhoList_Update()
	if (conf.ClassColouredNames == 1 and conf.ApplyToGuildList == 1) then
		local numWhos, totalCount = GetNumWhoResults()
		local whoOffset = FauxScrollFrame_GetOffset(WhoListScrollFrame)

		local myZone = GetRealZoneText()
		local myRace = UnitRace("player")
		local myGuild = GetGuildInfo("player")

		for i=1, WHOS_TO_DISPLAY, 1 do
			local name, guild, level, race, class, zone = GetWhoInfo(whoOffset + i)
			local color
			if (not name) then
				break
			end

			getglobal("WhoFrameButton"..i.."Name"):SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
			if (conf.XPerlTooltipInfo == 1 and XPerl_GetUsage) then
				local u = XPerl_GetUsage(name)
				if (u) then
					getglobal("WhoFrameButton"..i.."Name"):SetTextColor(1, 0.4, 0.4)
				end
			end

			if (conf.ClassColouredNames == 1 and conf.ApplyToGuildList == 1) then
				if (UIDropDownMenu_GetSelectedID(WhoFrameDropDown) == 1) then
					-- Zone
					if (zone == myZone) then
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(0, 1, 0)
					else
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(1, 1, 1)
					end
				elseif (UIDropDownMenu_GetSelectedID(WhoFrameDropDown) == 2) then
					if (guild == myGuild) then
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(0, 1, 0)
					else
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(1, 1, 1)
					end

				elseif (UIDropDownMenu_GetSelectedID(WhoFrameDropDown) == 3) then
					if (race == myRace) then
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(0, 1, 0)
					else
						getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(1, 1, 1)
					end
				end

				getglobal("WhoFrameButton"..i.."Class"):SetTextColor(1, 1, 1)
				class = colourList[class]
				if (class) then
					local color = XPerl_GetClassColour(class)
					if (color) then
						getglobal("WhoFrameButton"..i.."Class"):SetTextColor(color.r, color.g, color.b)
					end
				end

				local color = GetDifficultyColor(level)
				getglobal("WhoFrameButton"..i.."Level"):SetTextColor(color.r, color.g, color.b)
			else
				getglobal("WhoFrameButton"..i.."Variable"):SetTextColor(1, 1, 1)
				getglobal("WhoFrameButton"..i.."Level"):SetTextColor(1, 1, 1)
				getglobal("WhoFrameButton"..i.."Class"):SetTextColor(1, 1, 1)
			end
		end
	end
end

hooksecurefunc("WhoList_Update", XPerl_WhoList_Update)

----------------------
-- Fading Bar Stuff --
----------------------
local fadeBars = {}
local freeFadeBars = {}
local tempDisableFadeBars

function XPerl_NoFadeBars(tempDisable)
	tempDisableFadeBars = tempDisable
end

-- CheckOnUpdate
local function CheckOnUpdate()
	local any
	for k,v in pairs(fadeBars) do
		any = true
		break
	end

	if (any) then
		XPerl_Globals:SetScript("OnUpdate", XPerl_BarUpdate)
	else
		XPerl_Globals:SetScript("OnUpdate", nil)
	end
end

-- XPerl_BarUpdate
--local speakerTimer = 0
--local speakerCycle = 0
function XPerl_BarUpdate()
	local did
	for k,v in pairs(fadeBars) do
		if (k:IsShown()) then
			v:SetAlpha(k.fadeAlpha)
			k.fadeAlpha = k.fadeAlpha - (arg1 / conf.FadingBarsTime)

			local r, g, b = v.tex:GetVertexColor()
			v:SetStatusBarColor(r, g, b)
		else
			-- Not shown, so end it
			k.fadeAlpha = 0
		end

		if (k.fadeAlpha <= 0) then
			tinsert(freeFadeBars, v)
			fadeBars[k] = nil
			k.fadeAlpha = nil
			k.fadeBar = nil
			v:SetValue(0)
			v:Hide()
			v.tex = nil
			did = true
		end
	end

	if (did) then
		CheckOnUpdate()
	end
end

-- GetFreeFader
local function GetFreeFader(parent)
	local bar = freeFadeBars[1]
	if (bar) then
		tremove(freeFadeBars, 1)
		bar:SetParent(parent)
	else
		bar = CreateFrame("StatusBar", nil, parent)
	end

	if (bar) then
		fadeBars[parent] = bar
		CheckOnUpdate()

		bar.tex = parent.tex

		local tex = parent:GetStatusBarTexture()
		bar:SetStatusBarTexture(tex:GetTexture())

		local r, g, b = bar.tex:GetVertexColor()
		bar:SetStatusBarColor(r, g, b)

		bar:SetFrameLevel(parent:GetFrameLevel())

		bar:ClearAllPoints()
		bar:SetPoint("TOPLEFT", 0, 0)
		bar:SetPoint("BOTTOMRIGHT", 0, 0)
		bar:SetAlpha(parent:GetAlpha())

		return bar
	end
end

-- XPerl_StatusBarSetValue
function XPerl_StatusBarSetValue(self, val)
	if (not tempDisableFadeBars and conf.FadingBars == 1 and self:GetName()) then
		local min, max = self:GetMinMaxValues()
		local current = self:GetValue()

		if (val < current and val <= max and val >= min) then
			local bar = fadeBars[self]

			if (not bar) then
				bar = GetFreeFader(self)
			end

			if (bar) then
				if (not self.fadeAlpha) then
					self.fadeAlpha = self:GetParent():GetAlpha()
					bar:SetValue(current)
				end

				bar:SetMinMaxValues(min, max)
				bar:SetAlpha(self.fadeAlpha)
				bar:Show()
			end
		end
	end

	XPerl_OldStatusBarSetValue(self, val)
end

-- XPerl_RegisterClickCastFrame
function XPerl_RegisterClickCastFrame(self)
	if (not ClickCastFrames) then
		ClickCastFrames = {}
	end
	ClickCastFrames[self] = true
end

function XPerl_UnregisterClickCastFrame(self)
	if (ClickCastFrames) then
		ClickCastFrames[self] = nil
	end
end

function XPerl_SecureUnitButton_OnLoad(self, unit, menufunc)
	self:SetAttribute("*type1", "target")
	self:SetAttribute("type2", "menu")
	self:SetAttribute("unit", unit)
	self.menu = menufunc
	XPerl_RegisterClickCastFrame(self)
end

-- XPerl_GenericDropDown_OnLoad
function XPerl_GenericDropDown_OnLoad(self)
	UIDropDownMenu_Initialize(self, XPerl_GenericDropDown_Initialize, "MENU")
	tinsert(UnitPopupFrames, "XPerl_DropDown")
end

-- XPerl_GenericDropDown_Initialize
function XPerl_GenericDropDown_Initialize()
	local unitid = XPerl_DropDown.unit or "player"
	local menu
	local name
	local id

	if ( UnitIsUnit(unitid, "player") ) then
		menu = "SELF"
	elseif ( UnitIsUnit(unitid, "pet") ) then
		menu = "PET"
	elseif ( UnitIsPlayer(unitid) ) then
		id = UnitInRaid(unitid)
		if ( id ) then
			menu = "RAID_PLAYER"		-- "RAID" ?
		elseif ( UnitInParty(unitid) ) then
			menu = "PARTY"
		else
			menu = "PLAYER"
		end
	else
		menu = "RAID_TARGET_ICON"
		name = RAID_TARGET_ICON
	end
	if (menu) then
		UnitPopup_ShowMenu(XPerl_DropDown, menu, unitid, name, id)
	end
end

-- XPerl_ShowGenericMenu
-- self, unit, button are passed from secure template handler (SecureTemplates.lua, line 288 in SecureActionButton_OnClick)
function XPerl_ShowGenericMenu(self, unit, button, anchor)
	HideDropDownMenu(1)

	if (not unit) then
		unit = SecureButton_GetUnit(self)
	end
	XPerl_DropDown.unit = unit

	if (XPerl_DropDown.unit) then
		XPerl_DropDown.id = strmatch(XPerl_DropDown.unit or "", "(%d+)")
		XPerl_DropDown.displayMode = "MENU"

		XPerl_DropDown.initialize = XPerl_GenericDropDown_Initialize

		if (not anchor) then
			if (self.statsFrame) then
				anchor = self.statsFrame:GetName()
			elseif (self:GetParent().statsFrame) then
				anchor = self:GetParent().statsFrame:GetName()
			end
		end

--ChatFrame7:AddMessage("Generic menu for "..tostring(unit).." anchor: "..tostring(anchor))

		ToggleDropDownMenu(1, nil, XPerl_DropDown, anchor or "cursor", 0, 0)
	end
end

-- XPerl_GetBuffButton
local buffIconCount = 0
function XPerl_GetBuffButton(self, buffnum, debuff, createIfAbsent)
	debuff = (debuff or 0)
	local buffType, buffList

	if (debuff == 1) then
		buffType = "DeBuff"
		buffList = self.buffFrame.debuff
	else
		buffType = "Buff"
		buffList = self.buffFrame.buff
	end

	local button = buffList and buffList[buffnum]

	if (not button and createIfAbsent) then
		local setup = self.buffSetup

		buffIconCount = buffIconCount + 1
		button = CreateFrame("Button", "XPerlBuff"..buffIconCount, self.buffFrame, "XPerl_"..buffType.."Template")
		button:SetID(buffnum)
		button:SetAlpha(self:GetAlpha())		-- New frames always seem to have 100% alpha

		local sizeOpt = setup.buffSizeOpt
		if (type(sizeOpt) == "string") then
			sizeOpt = conf[setup.buffSizeOpt]
		end
		local size = sizeOpt * (1 + (setup.debuffSizeMod * debuff))
		button:SetHeight(size)
		button:SetWidth(size)

		if (debuff == 1) then
			button:SetScript("OnEnter", setup.debuffOnEnter)

			if (not buffList) then
				self.buffFrame.debuff = {}
				buffList = self.buffFrame.debuff
			end
		else
			button:SetScript("OnEnter", setup.buffOnEnter)

			if (not buffList) then
				self.buffFrame.buff = {}
				buffList = self.buffFrame.buff
			end
		end
		buffList[buffnum] = button

		button:SetScript("OnLeave", setup.buffOnLeave)

		button:ClearAllPoints()
		if (buffnum == 1) then
			if (debuff == 1) then
				setup.debuffAnchor1(self, button)
			else
				setup.buffAnchor1(self, button)
			end
		else
			button:SetPoint("TOPLEFT", buffList[buffnum - 1], "TOPRIGHT", 1 + debuff, 0)
		end
	end

	return button
end

-- XPerl_SetBuffSize
function XPerl_SetBuffSize(self)
	local sizeOpt = self.buffSetup.buffSizeOpt
	if (type(sizeOpt) == "string") then
		sizeOpt = conf[self.buffSetup.buffSizeOpt]
	end
	local sizeBuff = sizeOpt
	local sizeDebuff = sizeOpt * (1 + self.buffSetup.debuffSizeMod)

	local buff
	for i = 1,40 do
		buff = self.buffFrame.buff and self.buffFrame.buff[i]
		if (buff) then
			buff:SetHeight(sizeBuff)
			buff:SetWidth(sizeBuff)
		end

		buff = self.buffFrame.debuff and self.buffFrame.debuff[i]
		if (buff) then
			buff:SetHeight(sizeDebuff)
			buff:SetWidth(sizeDebuff)
		end
	end
end
