--[[------------------------------------------------------------
	OnScreenHealth
	Simple text displays of player and target health and power.
	Author:	Phanx <addons[at]phanx.net>
	Website:	http://phanx.net/addons/onscreenhealth
	Credits:	Alumno, Blink, damjau, rdji
------------------------------------------------------------]]--

OnScreenHealth = AceLibrary("AceAddon-2.0"):new("AceEvent-2.0", "AceConsole-2.0", "AceDB-2.0")

--[[------------------------------------------------------------
	Locals
------------------------------------------------------------]]--
local select = select
local type = type
local tonumber = tonumber
local unpack = unpack
local string_find = string.find
local string_format = string.format
local string_gmatch = string.gmatch
local string_gsub = string.gsub
local string_sub = string.sub

local GameTooltip_UnitColor = GameTooltip_UnitColor
local GetComboPoints = GetComboPoints
local UnitAffectingCombat = UnitAffectingCombat
local UnitClass = UnitClass
local UnitExists = UnitExists
local UnitHealth = UnitHealth
local UnitHealthMax = UnitHealthMax
local UnitIsConnected = UnitIsConnected
local UnitIsGhost = UnitIsGhost
local UnitIsDeadOrGhost = UnitIsDeadOrGhost
local UnitIsPlayer = UnitIsPlayer
local UnitIsUnit = UnitIsUnit
local UnitMana = UnitMana
local UnitManaMax = UnitManaMax
local UnitName = UnitName
local UnitPowerType = UnitPowerType

local OnScreenHealth = OnScreenHealth
local VERSION = GetAddOnMetadata("OnScreenHealth", "Version"); if VERSION:find("%a") then VERSION = "1.0-dev" end
local db, isPetClass, isComboClass, currentToT
local frame, font, color, text, cur, max, perc, kind
local tmp1, tmp2, tmp3, tmp4, tmp5, tmp6

local classColors = {}
for class, color in pairs(RAID_CLASS_COLORS) do
	classColors[class] = string.format("%02x%02x%02x", color.r * 255, color.g * 255, color.b * 255)
end

local SharedMedia = LibStub and LibStub("LibSharedMedia-3.0", true)

--[[-------------------------------------------------------------
	Debugging
-------------------------------------------------------------]]--
local debugShow = false
local debugLevel = 1

local Debug = function(lvl, msg)
	if debugShow and debugLvl >= lvl then
		ChatFrame1:AddMessage("|cff7fff7f(DEBUG) OnScreenHealth: ["..date("%H:%M:%S").."."..string_format("%3d", (GetTime() % 1) * 1000).."]|r "..msg)
	end
end
OnScreenHealth.Debug = Debug

--[[------------------------------------------------------------
	Localization
------------------------------------------------------------]]--
local L

if ONSCREENHEALTH_LOCALS then
	L = setmetatable(ONSCREENHEALTH_LOCALS, { __index = function(self, key) Debug(1, "Missing translation for \""..key.."\".") rawset(self, key, key) return key end })
	ONSCREENHEALTH_LOCALS = nil
else
	L = setmetatable({}, { __index = function(self, key) rawset(self, key, key) return key end })
end
OnScreenHealth.L = L

--[[------------------------------------------------------------
	Utilities
------------------------------------------------------------]]--
function OnScreenHealth:Short(num)
	if not num then return end
	Debug(3, "Shortening"..num)

	if type(num) == "number" then
		if num >= 10000000 then
			return string_format("%.1fm", num / 1000000)
		elseif num >= 1000000 then
			return string_format("%.2fm", num / 1000000)
		elseif num >= 100000 then
			return string_format("%.0fk", num / 1000)
		elseif num >= 10000 then
			return string_format("%.1fk", num / 1000)
		end
	end
	return num
end

function OnScreenHealth:GetUnitColor(unit)
	if not unit then return end

	if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) then
		return db.colorAbsent
	else
		tmp1 = UnitIsPlayer(unit) and classColors[select(2, UnitClass(unit))] or nil
		if tmp1 then
			return tmp1
		else
			tmp1, tmp2, tmp3 = GameTooltip_UnitColor(unit)
			return string.format("%02x%02x%02x", tmp1 * 255, tmp2 * 255, tmp3 * 255)
		end
	end
end

function OnScreenHealth:GetHealthColor(perc, unit)
	if not perc then return end
	Debug(3, "Getting health color")

	if db.colorHealthMode == "CLASS" then
		return self:GetUnitColor(unit)
	elseif db.colorHealthMode == "GRADIENT" then
		if perc <= 0.5 then
			perc = perc * 2
			tmp1, tmp2, tmp3 = unpack(db.colorHealthMin)
			tmp4, tmp5, tmp6 = unpack(db.colorHealthMid)
		else
			perc = perc * 2 - 1
			tmp1, tmp2, tmp3 = unpack(db.colorHealthMid)
			tmp4, tmp5, tmp6 = unpack(db.colorHealthMax)
		end
		return string.format("%02x%02x%02x", (tmp1 + (tmp4 - tmp1) * perc) * 255, (tmp2 + (tmp5 - tmp2) * perc) * 255, (tmp3 + (tmp6 - tmp3) * perc) * 255)
	else
		if perc < 0.33 then
			tmp1, tmp2, tmp3 = unpack(db.colorHealthMin)
		elseif perc < 0.67 then
			tmp1, tmp2, tmp3 = unpack(db.colorHealthMid)
		else
			tmp1, tmp2, tmp3 = unpack(db.colorHealthMax)
		end
		return string.format("%02x%02x%02x", tmp1 * 255, tmp2 * 255, tmp3 * 255)
	end
end

function OnScreenHealth:GetHealthAlpha(perc)
	if not perc then return end
	Debug(3, "Getting health alpha")

	if perc < 0.25 then
		return 1
	else
		return 1.25 - perc
	end
end

function OnScreenHealth:GetFormattedText(text, cur, max)
	if not text and cur and max then return end
	Debug(3, "Getting formatted text")

	text = string_gsub(text, "$c:s", self:Short(cur))
	text = string_gsub(text, "$c", cur)

	text = string_gsub(text, "$m:s", self:Short(max))
	text = string_gsub(text, "$m", max)

	text = string_gsub(text, "$d:s", self:Short(max - cur))
	text = string_gsub(text, "$d", max - cur)

	text = string_gsub(text, "$p", string_format("%.0f", cur / max * 100))

	return text
end

--[[------------------------------------------------------------
	Generic updaters
------------------------------------------------------------]]--
function OnScreenHealth:UpdateHealth(unit)
	if unit ~= "player" and unit ~= "target" and unit ~= "pet" then return end
	Debug(2, "Updating health for "..unit)

	if unit == "player" then
		frame, font = OSH_PlayerFrame, OSH_PlayerHealth
	elseif unit == "target" then
		frame, font = OSH_TargetFrame, OSH_TargetHealth
	elseif unit == "pet" then
		frame, font = OSH_PetFrame, OSH_PetHealth
	end

	if not frame or not frame:IsShown() then return end

	if UnitIsDeadOrGhost(unit) then
		if UnitIsGhost(unit) then
			font:SetText("|cff"..db.colorAbsent..L["Ghost"].."|r")
			return
		else
			font:SetText("|cff"..db.colorAbsent..L["Dead"].."|r")
			return
		end
	elseif not UnitIsConnected(unit) then
		font:SetText("|cff"..db.colorAbsent..L["Offline"].."|r")
		return
	end

	cur, max = UnitHealth(unit), UnitHealthMax(unit)
	perc = cur / max

	font:SetText("|cff"..self:GetHealthColor(perc, unit)..self:GetFormattedText(UnitIsPlayer(unit) and db.textFormatHealthPlayer or db.textFormatHealthMonster, cur, max).."|r")

	if db.alphaMode == "HEALTH" then
		frame:SetAlpha(self:GetHealthAlpha(perc))
	end
end

function OnScreenHealth:UpdatePower(unit)
	if unit ~= "player" and unit ~= "target" and unit ~= "pet" then return end
	Debug(2, "Updating power for "..unit)

	if unit == "player" then
		frame, font = OSH_PlayerFrame, OSH_PlayerPower
	elseif unit == "target" then
		frame, font = OSH_TargetFrame, OSH_TargetPower
	elseif unit == "pet" then
		frame, font = OSH_PetFrame, OSH_PetPower
	end

	if not frame or not frame:IsShown() then return end

	if UnitIsDeadOrGhost(unit) or not UnitIsConnected(unit) or UnitManaMax(unit) == 0 then
		font:SetText(" ")
		return
	end

	kind = UnitPowerType(unit)
	if kind == 0 then
		color = db.colorMana
	elseif kind == 1 then
		color = db.colorRage
	elseif kind == 3 then
		color = db.colorEnergy
	elseif kind == 2 then
		color = db.colorFocus
	else
		color = db.colorDefault
	end

	font:SetText("|cff"..color..self:GetFormattedText(UnitIsPlayer(unit) and db.textFormatPowerPlayer or db.textFormatPowerMonster, UnitMana(unit), UnitManaMax(unit)).."|r")
end

--[[------------------------------------------------------------
	Unit-specific updaters
------------------------------------------------------------]]--
function OnScreenHealth:UpdateAll(type)
	if type and type == "health" then
		self:UpdateHealth("player")
		self:UpdateHealth("target")
		if isPetClass then
			self:UpdateHealth("pet")
		end
	elseif type and type == "power" and db.showPower then
		self:UpdatePower("player")
		self:UpdatePower("target")
		if isPetClass then
			self:UpdatePower("pet")
		end
	else
		self:UpdatePlayer()
		self:UpdateTarget()
		if isPetClass then
			self:UpdatePet()
		end
	end
end

function OnScreenHealth:UpdatePlayer()
	if not db.playerEnable or not (db.playerShowOOC or UnitAffectingCombat("player")) or not (db.playerShowDead or not UnitIsDeadOrGhost("player")) then
		OSH_PlayerFrame:Hide()
		return
	end
	Debug(1, "Updating player")

	OSH_PlayerFrame:Show()
	self:UpdateHealth("player")
	if db.showPower then
		self:UpdatePower("player")
	end
	if db.playerShowCombatStatus then
		self:UpdateCombatStatus("player")
	end
end

function OnScreenHealth:UpdateCombatStatus(unit)
	if not unit then unit = "player" end
	Debug(1, "Updating "..unit.." status")

	if db[unit.."ShowCombatStatus"] and UnitAffectingCombat(unit) then
		OSH_PlayerStatus:SetText("|cff"..db.colorCombatStatus.."+|r")
	else
		OSH_PlayerStatus:SetText()
	end
end

function OnScreenHealth:UpdatePet(owner)
	if owner and owner ~= "player" or db.disablePet then return end
	if not db.petEnable or not (db.playerShowOOC or UnitAffectingCombat("player")) or not (db.petShowDead or not UnitIsDeadOrGhost("pet")) or not UnitExists("pet") then
		OSH_PetFrame:Hide()
		return
	end
	Debug(1, "Updating pet")

	if UnitExists("pet") then
		if db.hidePetDead then
			if UnitIsDeadOrGhost("pet") then
				OSH_PetFrame:Hide()
				return
			end
		end
		OSH_PetFrame:Show()
		self:UpdateHealth("pet")
		if db.showPower then
			self:UpdatePower("pet")
		end
	else
		OSH_PetFrame:Hide()
	end
end

function OnScreenHealth:UpdateTarget()
	if not UnitExists("target") or not db.targetEnable or not (db.targetShowOOC or UnitAffectingCombat("player")) or not (db.targetShowDead or (not UnitIsDeadOrGhost("target") and UnitIsConnected("target"))) then
		OSH_TargetFrame:Hide()
		currentToT = nil
		return
	end
	Debug(1, "Updating target")

	OSH_TargetFrame:Show()
	self:UpdateHealth("target")
	if db.showPower then
		self:UpdatePower("target")
	end
	if isComboClass then
		self:UpdateCP()
	end
end

function OnScreenHealth:CheckToT()
	tmp1 = UnitExists("targettarget") and UnitName("targettarget") or "NONE"
	if currentToT ~= tmp1 then
		currentToT = tmp1
		OnScreenHealth:UpdateToT()
	end
end

function OnScreenHealth:UpdateToT()
	if UnitExists("target") and UnitExists("targettarget") then
		if UnitIsUnit("player", "targettarget") then
			OSH_TargetTarget:SetText("|cff"..db.colorTargetSelf..L["<<YOU>>"].."|r")
			return
		else
			OSH_TargetTarget:SetText("|cff"..self:GetUnitColor("targettarget")..UnitName("targettarget").."|r")
			return
		end
	else
		OSH_TargetTarget:SetText(nil)
	end
end

function OnScreenHealth:UpdateCP()
	tmp1 = GetComboPoints("player", "target")
	if tmp1 ~= 0 then
		OSH_TargetCombo:SetText("|cff"..db.colorCombo..tmp1.."|r")
	else
		OSH_TargetCombo:SetText()
	end
end

--[[------------------------------------------------------------
	Event handlers
------------------------------------------------------------]]--
function OnScreenHealth:EnterCombat()
	Debug(1, "Entering combat")
	self:UpdatePlayer()
	if isPetClass then
		self:UpdatePet()
	end
	self:UpdateTarget()
	if db.alphaMode == "COMBAT" then
		tmp1 = db.alphaCombat
		OSH_PlayerFrame:SetAlpha(tmp1)
		OSH_TargetFrame:SetAlpha(tmp1)
		if isPetClass then
			OSH_PetFrame:SetAlpha(tmp1)
		end
	end
end

function OnScreenHealth:LeaveCombat()
	Debug(1, "Leaving combat")
	self:UpdatePlayer()
	if not db.playerShowOOC then
		OSH_PlayerFrame:Hide()
		if isPetClass then
			OSH_PetFrame:Hide()
		end
	end
	if not db.targetShowOOC then
		self:UpdateTarget()
	end
	if db.alphaMode == "COMBAT" then
		tmp1 = db.alphaOOC
		OSH_PlayerFrame:SetAlpha(tmp1)
		OSH_TargetFrame:SetAlpha(tmp1)
		if isPetClass then
			OSH_PetFrame:SetAlpha(tmp1)
		end
	end
end

function OnScreenHealth:PlayerDead()
	Debug(1, "Died")
	self:UpdateCombatStatus("player")
	OSH_PlayerFrame:Hide()
	if isPetClass then
		OSH_PetFrame:Hide()
	end
end

function OnScreenHealth:PlayerAlive()
	Debug(1, "Resurrected")
	if not UnitIsGhost("player") and db.playerShowOOC or UnitAffectingCombat("player") then
		OSH_PlayerFrame:Show()
		self:UpdateHealth("player")
		if db.showPower then
			self:UpdatePower("player")
		end
		if isPetClass then
			self:UpdatePet()
		end
	end
end

--[[------------------------------------------------------------
	Frame creation and manipulation
------------------------------------------------------------]]--
function OnScreenHealth:CreateFrames()
	Debug(1, "Creating frames")
	local pf, ph, pp, ps, mf, mh, mp, tf, th, tp, tt, tc

	if db.fontShadow then
		tmp1, tmp2 = 1, -1
	else
		tmp1, tmp2 = 0, 0
	end

	pf = CreateFrame("Frame", "OSH_PlayerFrame", UIParent)
	pf:SetFrameStrata("BACKGROUND")
	pf:SetFrameLevel(0)
	pf:SetWidth(100)
	pf:SetHeight(50)

	ph = pf:CreateFontString("OSH_PlayerHealth", "OVERLAY")
	ph:SetShadowOffset(tmp1, tmp2)

	pp = pf:CreateFontString("OSH_PlayerPower", "OVERLAY")
	pp:SetShadowOffset(tmp1, tmp2)

	ps = pf:CreateFontString("OSH_PlayerStatus", "OVERLAY")
	ps:SetShadowOffset(tmp1, tmp2)

	if isPetClass then
		mf = CreateFrame("Frame", "OSH_PetFrame", UIParent)
		mf:SetFrameStrata("BACKGROUND")
		mf:SetFrameLevel(0)
		mf:SetWidth(100)
		mf:SetHeight(50)

		mh = mf:CreateFontString("OSH_PetHealth", "OVERLAY")
		mh:SetShadowOffset(tmp1, tmp2)

		mp = mf:CreateFontString("OSH_PetPower", "OVERLAY")
		mp:SetShadowOffset(tmp1, tmp2)
	end

	tf = CreateFrame("Frame", "OSH_TargetFrame", UIParent)
	tf:SetFrameStrata("BACKGROUND")
	tf:SetFrameLevel(0)
	tf:SetWidth(100)
	tf:SetHeight(50)

	th = tf:CreateFontString("OSH_TargetHealth", "OVERLAY")
	th:SetShadowOffset(tmp1, tmp2)

	tp = tf:CreateFontString("OSH_TargetPower", "OVERLAY")
	tp:SetShadowOffset(tmp1, tmp2)

	tt = tf:CreateFontString("OSH_TargetTarget", "OVERLAY")
	tt:SetShadowOffset(tmp1, tmp2)

	if isComboClass then
		tc = tf:CreateFontString("OSH_TargetCombo", "OVERLAY")
		tc:SetShadowOffset(tmp1, tmp2)
	end

	if db.alphaMode == "COMBAT" then
		tmp3 = UnitAffectingCombat("player") and db.alphaCombat or db.alphaOOC
	else
		tmp3 = db.alphaFixed
	end
	pf:SetAlpha(tmp3)
	tf:SetAlpha(tmp3)
	if isPetClass then
		mf:SetAlpha(tmp3)
	end

	self:ApplyPositions()
	self:ApplyFonts()
	self:UpdatePlayer()
	self:UpdateTarget()
	if isPetClass then
		self:UpdatePet()
	end
end

function OnScreenHealth:ApplyPositions()
	Debug(1, "Setting frame positions")

	if db.textAlign == "CENTER" then
		tmp1, tmp2, tmp3, tmp4, tmp5, tmp6 = "TOP", "BOTTOM", "CENTER", "TOP", "BOTTOM", "CENTER"
	elseif db.textAlign == "OUTSIDE" then
		tmp1, tmp2, tmp3, tmp4, tmp5, tmp6 = "TOPLEFT", "BOTTOMLEFT", "LEFT", "TOPRIGHT", "BOTTOMRIGHT", "RIGHT"
	else
		tmp1, tmp2, tmp3, tmp4, tmp5, tmp6 = "TOPRIGHT", "BOTTOMRIGHT", "RIGHT", "TOPLEFT", "BOTTOMLEFT", "LEFT"
	end

	OSH_PlayerFrame:ClearAllPoints()
	OSH_PlayerFrame:SetPoint(tmp1, UIParent, "CENTER", -db.posX, db.posY)
	OSH_PlayerHealth:ClearAllPoints()
	OSH_PlayerHealth:SetPoint(tmp1, OSH_PlayerFrame, tmp1, 0, 0)
	OSH_PlayerHealth:SetJustifyH(tmp3)
	OSH_PlayerPower:ClearAllPoints()
	OSH_PlayerPower:SetPoint(tmp1, OSH_PlayerHealth, tmp2, 0, 0)
	OSH_PlayerPower:SetJustifyH(tmp3)
	OSH_PlayerStatus:ClearAllPoints()
	OSH_PlayerStatus:SetPoint(tmp2, OSH_PlayerHealth, tmp1, 0, 0)
	OSH_PlayerStatus:SetJustifyH(tmp3)

	OSH_TargetFrame:ClearAllPoints()
	OSH_TargetFrame:SetPoint(tmp4, UIParent, "CENTER", db.posX, db.posY)
	OSH_TargetHealth:ClearAllPoints()
	OSH_TargetHealth:SetPoint(tmp4, OSH_TargetFrame, tmp4, 0, 0)
	OSH_TargetHealth:SetJustifyH("CENTER")
	OSH_TargetPower:ClearAllPoints()
	OSH_TargetPower:SetPoint(tmp4, OSH_TargetHealth, tmp5, 0, 0)
	OSH_TargetPower:SetJustifyH(tmp6)
	OSH_TargetTarget:ClearAllPoints()
	OSH_TargetTarget:SetPoint(tmp4, OSH_TargetPower, tmp5, 0, 0)
	OSH_TargetTarget:SetJustifyH(tmp6)

	if isComboClass then
		OSH_TargetCombo:ClearAllPoints()
		OSH_TargetCombo:SetPoint(tmp5, OSH_TargetHealth, tmp4, 0, 0)
		OSH_TargetCombo:SetJustifyH(tmp6)
	end

	if isPetClass then
		OSH_PetFrame:ClearAllPoints()
		OSH_PetFrame:SetPoint(tmp2, OSH_PlayerFrame, tmp1, 0, db.posPet)
		OSH_PetHealth:ClearAllPoints()
		OSH_PetHealth:SetPoint(tmp1, OSH_PetFrame, tmp1, 0, 0)
		OSH_PetHealth:SetJustifyH(tmp3)
		OSH_PetPower:ClearAllPoints()
		OSH_PetPower:SetPoint(tmp1, OSH_PetHealth, tmp2, 0, 0)
		OSH_PetPower:SetJustifyH(tmp3)
	end
end

function OnScreenHealth:ApplyFonts()
	tmp1 = SharedMedia and SharedMedia:Fetch("font", db.fontFace) or "Fonts\\FRIZQT__.ttf"
	tmp2, tmp3, tmp4 = db.fontSizeHealth, db.fontSizePower, db.fontOutline
	OSH_PlayerHealth:SetFont(tmp1, tmp2, tmp4)
	OSH_PlayerPower:SetFont(tmp1, tmp3, tmp4)
	OSH_PlayerStatus:SetFont(tmp1, tmp3, tmp4)
	OSH_TargetHealth:SetFont(tmp1, tmp2, tmp4)
	OSH_TargetPower:SetFont(tmp1, tmp3, tmp4)
	OSH_TargetTarget:SetFont(tmp1, db.fontSizeTarget, tmp4)
	if isComboClass then
		OSH_TargetCombo:SetFont(tmp1, db.fontSizeCombo, tmp4)
	end
	if isPetClass then
		OSH_PetHealth:SetFont(tmp1, tmp2 * db.fontSizePet, tmp4)
		OSH_PetPower:SetFont(tmp1, tmp3 * db.fontSizePet, tmp4)
	end
end

--[[------------------------------------------------------------
--	Event registration
------------------------------------------------------------]]--
function OnScreenHealth:UpdatePowerEvents()
	if db.showPower then
		if not self:IsEventRegistered("UNIT_MANA") then
			self:RegisterEvent("UNIT_MANA", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_MAXMANA") then
			self:RegisterEvent("UNIT_MAXMANA", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_RAGE") then
			self:RegisterEvent("UNIT_RAGE", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_MAXRAGE") then
			self:RegisterEvent("UNIT_MAXRAGE", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_ENERGY") then
			self:RegisterEvent("UNIT_ENERGY", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_MAXENERGY") then
			self:RegisterEvent("UNIT_MAXENERGY", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_FOCUS") then
			self:RegisterEvent("UNIT_FOCUS", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_MAXFOCUS") then
			self:RegisterEvent("UNIT_MAXFOCUS", "UpdatePower")
		end
		if not self:IsEventRegistered("UNIT_DISPLAYPOWER") then
			self:RegisterEvent("UNIT_DISPLAYPOWER", "UpdatePower")
		end
	else
		if self:IsEventRegistered("UNIT_MANA") then
			self:UnregisterEvent("UNIT_MANA")
		end
		if self:IsEventRegistered("UNIT_MAXMANA") then
			self:UnregisterEvent("UNIT_MAXMANA")
		end
		if self:IsEventRegistered("UNIT_RAGE") then
			self:UnregisterEvent("UNIT_RAGE")
		end
		if self:IsEventRegistered("UNIT_MAXRAGE") then
			self:UnregisterEvent("UNIT_MAXRAGE")
		end
		if self:IsEventRegistered("UNIT_ENERGY") then
			self:UnregisterEvent("UNIT_ENERGY")
		end
		if self:IsEventRegistered("UNIT_MAXENERGY") then
			self:UnregisterEvent("UNIT_MAXENERGY")
		end
		if self:IsEventRegistered("UNIT_FOCUS") then
			self:UnregisterEvent("UNIT_FOCUS")
		end
		if self:IsEventRegistered("UNIT_MAXFOCUS") then
			self:UnregisterEvent("UNIT_MAXFOCUS")
		end
		if self:IsEventRegistered("UNIT_DISPLAYPOWER") then
			self:UnregisterEvent("UNIT_DISPLAYPOWER")
		end
	end
end

function OnScreenHealth:UpdateCombatEvents()
	if db.playerShowOOC and db.targetShowOOC and db.alphaMode ~= "COMBAT" and not db.playerShowCombatStatus then
		if self:IsEventRegistered("PLAYER_REGEN_DISABLED") then
			self:UnregisterEvent("PLAYER_REGEN_DISABLED")
		end
		if self:IsEventRegistered("PLAYER_REGEN_ENABLED") then
			self:UnregisterEvent("PLAYER_REGEN_ENABLED")
		end
	else
		if not self:IsEventRegistered("PLAYER_REGEN_DISABLED") then
			self:RegisterEvent("PLAYER_REGEN_DISABLED", "EnterCombat")
		end
		if not self:IsEventRegistered("PLAYER_REGEN_ENABLED") then
			self:RegisterEvent("PLAYER_REGEN_ENABLED", "LeaveCombat")
		end
	end
end

function OnScreenHealth:UpdateDeathEvents()
	if db.playerShowDead then
		if self:IsEventRegistered("PLAYER_ALIVE") then
			self:UnregisterEvent("PLAYER_ALIVE")
		end
		if self:IsEventRegistered("PLAYER_DEAD") then
			self:UnregisterEvent("PLAYER_DEAD")
		end
	else
		if not self:IsEventRegistered("PLAYER_ALIVE") then
			self:RegisterEvent("PLAYER_ALIVE", "PlayerAlive")
			self:RegisterEvent("PLAYER_UNGHOST", "PlayerAlive")
		end
		if not self:IsEventRegistered("PLAYER_DEAD") then
			self:RegisterEvent("PLAYER_DEAD", "PlayerDead")
		end
	end
end

--[[------------------------------------------------------------
	Initialization
------------------------------------------------------------]]--
function OnScreenHealth:OnInitialize()
	_, tmp1 = UnitClass("player")
	isPetClass = tmp1 == "HUNTER" or tmp1 == "WARLOCK"
	isComboClass = tmp1 == "DRUID" or tmp1 == "ROGUE"

	self:RegisterDB("OnScreenHealthDB")
	self:RegisterDefaults("profile", {
		playerEnable = true,
		playerShowDead = false,
		playerShowOOC = true,
		playerShowCombatStatus = false,
		targetEnable = true,
		targetShowDead = true,
		targetShowOOC = true,
		targetShowCP = true,
		targetShowToT = false,
		petEnable = true,
		petShowDead = false,
		alphaMode = "FIXED",
		alphaFixed = 1,
		alphaCombat = 1,
		alphaOOC = 0.5,
		colorHealthMode = "GRADIENT",
		showPower = true,
		textAlign = "INSIDE",
		textFormatHealthMonster = "$c",
		textFormatHealthPlayer = "$c",
		textFormatPowerMonster = "$c",
		textFormatPowerPlayer = "$c",
		fontFace = "Friz Quadrata TT",
		fontOutline = "OUTLINE",
		fontShadow = true,
		fontSizeHealth = 32,
		fontSizePower = 24,
		fontSizeTarget = 24,
		fontSizeCombo = 24,
		fontSizePet = 0.8,
		colorHealthMax = { 0, 1, 0 },
		colorHealthMid = { 1, 1, 0 },
		colorHealthMin = { 1, 0, 0 },
		colorMana = "0000FF",
		colorRage = "FF0000",
		colorEnergy = "FFFF00",
		colorFocus = "FF9933",
		colorAbsent = "999999",
		colorCombatStatus = "FFFFFF",
		colorCombo = "FF7F00",
		colorTargetSelf = "FFFFFF",
		posX = 200,
		posY = 0,
		posPet = 20,
		version = VERSION
	})
	db = self.db.profile

	--
	-- upgrade from old health formats
	--
	local upgradePaths = {
		["VALUE"] = "$c",
		["VALUE-S"] = "$c:s",
		["DEF"] = "$d",
		["DEF-S"] = "$d:s",
		["PER"] = "$p%",
		["PER-N"] = "$p",
		["VALUE-DEF"] = "$c-$d",
		["VALUE-DEF-S"] = "$c:s-$d:s",
		["VALUE-PER"] = "$c ($p%)",
		["VALUE-PER-N"] = "$c ($p)",
		["VALUE-PER-M"] = "$c$n$p%",
		["VALUE-PER-N-M"] = "$c$n$p"
	}
	local upgradeKeys = {
		"textFormatHealthMonster",
		"textFormatHealthPlayer",
		"textFormatPowerMonster",
		"textFormatPowerPlayer"
	}
	local old, new
	for _, k in ipairs(upgradeKeys) do
		new = upgradePaths[db[k]]
		if new then
			db[k] = new
		end
	end
	--
	-- end upgrade
	--

	self:LoadOptions()
end

function OnScreenHealth:OnEnable()
	Debug(1, "Enabling")
	if not OSH_PlayerFrame then
		self:CreateFrames()
	end

	self:RegisterEvent("UNIT_HEALTH", "UpdateHealth")
	self:RegisterEvent("PLAYER_TARGET_CHANGED", "UpdateTarget")

	self:UpdatePowerEvents()
	self:UpdateCombatEvents()
	self:UpdateDeathEvents()

	if isPetClass then
		Debug(1, "Registering pet events")
		self:RegisterEvent("UNIT_PET", "UpdatePet")
	end

	if db.targetShowToT then
		OSH_TargetFrame:SetScript("OnUpdate", OnScreenHealth.CheckToT)
	end

	if db.targetShowCP and isComboClass then
		Debug(1, "Registering combo point events")
		self:RegisterEvent("UNIT_COMBO_POINTS", "UpdateCP")
	end
end

function OnScreenHealth:OnDisable()
	Debug(1, "Disabling")
	OSH_PlayerFrame:Hide()
	OSH_TargetFrame:Hide()
	if isPetClass then
		OSH_PetFrame:Hide()
	end
end