--[[

	MobHealth: A database of estimated creature health values, with display
		copyright 2004 by Telo
	
	- Displays the estimated current and maximum health values of your target
	- Continually updates its estimates for each creature's health as you play
	- Thanks to Wyv for drawing my attention to the UNIT_COMBAT event
	
]]

--------------------------------------------------------------------------------------------------
-- Local variables
--------------------------------------------------------------------------------------------------

-- Current target data
local lTargetData;

--------------------------------------------------------------------------------------------------
-- Internal functions
--------------------------------------------------------------------------------------------------

local function MobHealth_PPP(index)
	if( index and MobHealthDB[index] ) then
		local s, e;
		local pts;
		local pct;
		
		s, e, pts, pct = string.find(MobHealthDB[index], "^(%d+)/(%d+)$");
		if( pts and pct ) then
			pts = pts + 0;
			pct = pct + 0;
			if( pct ~= 0 ) then
				return pts / pct;
			end
		end
	end
	return 0;
end

local function MobHealth_Pts(index)
	if( index and MobHealthDB[index] ) then
		local s, e;
		local val;
		
		s, e, val = string.find(MobHealthDB[index], "^(%d+)/");
		
		if( val ) then
			return val + 0;
		end
	end
	return 0;
end

local function MobHealth_Pct(index)
	if( index and MobHealthDB[index] ) then
		local s, e;
		local val;
		
		s, e, val = string.find(MobHealthDB[index], "/(%d+)$");
		
		if( val ) then
			return val + 0;
		end
	end
	return 0;
end

local function MobHealth_Set(index, pts, pct)
	if( index ) then
		if( pts ) then
			pts = pts + 0;
		else
			pts = 0;
		end
		if( pct ) then
			pct = pct + 0;
		else
			pct = 0;
		end
		if( pts == 0 and pct == 0 ) then
			MobHealthDB[index] = nil;
		else
			MobHealthDB[index] = pts.."/"..pct;
		end
	end
end

local function MobHealth_Display(currentPct, index)
	local field = getglobal("MobHealthText");
	local text = "";
	
	if( field ) then
		local pointsPerPct = MobHealth_PPP(index);
		if( pointsPerPct > 0 ) then	
			if( currentPct ) then
				text = string.format("%d/%d", (currentPct * pointsPerPct) + 0.5, (100 * pointsPerPct) + 0.5);
			else
				text = string.format("???/%d", (100 * pointsPerPct) + 0.5);
			end
		end
		field:SetText(text);
	end
end

local function MobHealth_VariablesLoaded()
	if( not MobHealthDB ) then
		MobHealthDB = { };
	else
		local index, value;
		
		for index, value in pairs(MobHealthDB) do
			-- Convert the old-style data into the newer, more compact form
			if( type(value) == "table" ) then
				MobHealth_Set(index, value.damPts, value.damPct);
			end
		end
	end
end

--------------------------------------------------------------------------------------------------
-- OnFoo functions
--------------------------------------------------------------------------------------------------

function MobHealth_OnLoad()
	this:RegisterEvent("VARIABLES_LOADED");
	this:RegisterEvent("UNIT_HEALTH");
	this:RegisterEvent("PLAYER_TARGET_CHANGED");
	this:RegisterEvent("UNIT_COMBAT");

	if( DEFAULT_CHAT_FRAME ) then
		DEFAULT_CHAT_FRAME:AddMessage("Telo's MobHealth AddOn loaded");
	end
	UIErrorsFrame:AddMessage("Telo's MobHealth AddOn loaded", 1.0, 1.0, 1.0, 1.0, UIERRORS_HOLD_TIME);
end

function MobHealth_OnEvent(event)
	if( event == "VARIABLES_LOADED" ) then
		MobHealth_VariablesLoaded();
	elseif( event == "UNIT_HEALTH" ) then
		MobHealth_Display(nil, nil);
		if( lTargetData ) then
			local health = UnitHealth("target");
			if( health and health ~= 0 ) then
				local change = lTargetData.currentHealthPercent - health;
				if( change ~= 0 ) then
					local damage = lTargetData.tempDamagePoints;
					local persistPts = MobHealth_Pts(lTargetData.index);
					local persistPct = MobHealth_Pct(lTargetData.index);
					local currentPPP = damage / change;
					local updatedPPP;

					if( (persistPct + change) ~= 0 ) then
						updatedPPP = (persistPts + damage) / (persistPct + change);
					else
						updatedPPP = 0;
					end

					lTargetData.currentHealthPercent = health;
					lTargetData.tempDamagePoints = 0;

					if( updatedPPP > 0 ) then
						MobHealth_Set(lTargetData.index, persistPts + damage, persistPct + change);
					end
				end
				MobHealth_Display(health, lTargetData.index);
			end
		end
	elseif( event == "PLAYER_TARGET_CHANGED" ) then
		local name = UnitName("target");
		if( name ) then
			if( UnitCanAttack("player", "target") and not UnitIsDead("target") and not UnitIsPlayer("target") ) then
				-- Attackable, alive, non-player target
				lTargetData = { };
				lTargetData.name = name;
				lTargetData.level = UnitLevel("target");
				lTargetData.index = lTargetData.name..":"..lTargetData.level;
				lTargetData.currentHealthPercent = UnitHealth("target");
				lTargetData.tempDamagePoints = 0;
				
				MobHealth_Display(lTargetData.currentHealthPercent, lTargetData.index);
				return;
			end
		end

		-- Unusable target
		lTargetData = nil;

		MobHealth_Display(nil, nil);
	elseif( event == "UNIT_COMBAT" ) then
		if( lTargetData and arg1 == "target" and arg4 and arg4 ~= 0 ) then
			if( arg2 == "HEAL" ) then
				lTargetData.tempDamagePoints = lTargetData.tempDamagePoints - arg4;
			else
				lTargetData.tempDamagePoints = lTargetData.tempDamagePoints + arg4;
			end
		end
	end
end
