local MI2_HpPctList, MI2_HpDmg, MI2_HpData

function MI2_HpDecode( hpData )
	local _,_, pts, pct = string.find(hpData, "^(%d+)/(%d+)$")
	pts = tonumber( pts )
	pct = tonumber( pct )
	return pts, pct
end

function MobHealth_GetTargetCurHP()
	return MI2_Target.curHealth
end

function MobHealth_GetTargetMaxHP()
	return MI2_Target.maxHealth
end

function MobHealth_PPP( index )
	if index and MobHealthDB[index]  then
		local pts, pct = MI2_HpDecode( MobHealthDB[index] )
		if pts and pct and pct ~= 0 then
			return pts / pct
		end
	end
	return 0
end

local function MI2_HpGet( database, index )
	if not database[index] then return nil,0 end
	local pts, pct = MI2_HpDecode( database[index] )
	local quality
	if pct == 200 then
		quality = 3
		pts = pts / 2
	elseif pct == 100 then
		quality = 2
	elseif pct and pts then
		quality = 1
		pts = floor(pts * 100 / pct + 0.5)
	else
		return nil,0
	end
	return pts, quality
end

local function MI2_HpSet( database, index, hpMax, quality )
	local pct, pts
	hpMax = floor(hpMax + 0.51)
	if quality == 3 then
		pct = 200
		pts = hpMax * 2
	elseif quality == 2 then
		pct = 100
		pts = hpMax
	else
		pct = 50
		pts = floor(hpMax / 2 + 0.51)
	end
	midebug( "writing HP to DB: new=["..pts.."/"..pct.."], old=["..(database[index] or "nil").."], hpm="..hpMax..", q="..quality, 1 )
	database[index] = pts.."/"..pct
end

function MI2_HpSetNewTarget()
	local unitHealth = UnitHealth("target")
	if MI2_Debug > 0 and MI2_Target.healthDB then
		midebug( "new target: ["..(MI2_Target.index or "none").."], unitHp="..(unitHealth or "none")..", hDB="..(MI2_Target.healthDB[MI2_Target.index] or "nil"), 1 )
	end
	MI2_HpData = { totalDmg=0, newQuality=0 }
	if unitHealth > 0 and MI2_Target.healthDB then
		MI2_HpDmg = {}
		MI2_HpPctList = {}
		MI2_HpTexts={ MI2_Target.index }
		if MI2_Debug == 0 then MI2_DbgData = nil end
		MI2_HpData.dbMax, MI2_HpData.dbQuality = MI2_HpGet( MI2_Target.healthDB, MI2_Target.index )
		MI2_Target.showHealth = 1
		if unitHealth == 100 then
			tinsert( MI2_HpPctList, {100,0} )
			MI2_HpData.newQuality = 2
		else
			MI2_HpData.newQuality = 1
		end
		MI2_RecordTargetHealth( unitHealth )
	else
		MobHealth_Display()
	end
end

function MobHealth_Display( )
	local healthText, manaText
	if MI2_Target.showHealth then
		if  MobInfoConfig.TargetHealth == 1 and MI2_Target.maxHealth then
			if MI2_HpData.dbQuality == 3 then
				healthText = string.format("%d", MI2_Target.curHealth )
			else
				healthText = string.format("%d", MI2_Target.curHealth )
			end
		end
		if	MobInfoConfig.HealthPercent	== 1 then
			if healthText then
				healthText = healthText..string.format(" /%d%%", MI2_Target.unitHealth )
			else
				healthText = string.format("%d%%", MI2_Target.unitHealth )
			end
		end
	end
	local maxmana = UnitManaMax("target")
	if maxmana > 0 then
		local mana = UnitMana("target")
		if MobInfoConfig.TargetMana == 1 then
			manaText = string.format("%d", mana )
		end
		if MobInfoConfig.ManaPercent == 1 then
			if manaText then
				manaText = manaText..string.format(" /%d%%", floor(100.0 * mana / maxmana))
			else
				manaText = string.format("%d%%", floor(100.0 * mana / maxmana))
			end
		end
	end
	MI2_MobHealthText:SetText( healthText or "" )
	MI2_MobManaText:SetText( manaText or "" )
	MI2_MobHealthText:SetAlpha(0.7);
	MI2_MobManaText:SetAlpha(0.7);
end

function MI2_MobHealth_SetPos( )
	local font
	MI2_MobHealthText:SetPoint( "TOP", "TargetFrameHealthBar", "BOTTOM", MobInfoConfig.HealthPosX, MobInfoConfig.HealthPosY )
	MI2_MobManaText:SetPoint( "TOP", "TargetFrameManaBar", "BOTTOM", MobInfoConfig.ManaPosX, MobInfoConfig.ManaPosY )
	MobHealth_Display()
end

function MI2_MobHealth_Reset()
	MI2_MobHealth_ClearTargetData()
	MobHealthDB	= {}
	MobHealthPlayerDB =	{}
end

function MI2_SaveTargetHealthData( updateOnly )
	if MI2_Target.index and MI2_HpData and MI2_HpData.newMax then
		if MI2_Debug > 0 and not updateOnly then
			if not MI2_DbgData or getn(MI2_DbgData) > 60 then MI2_DbgData = {} end
			tinsert( MI2_DbgData, MI2_HpTexts )
		end
		local newHpMax = MI2_HpData.newMax
		local newQuality = MI2_HpData.newQuality
		if MI2_HpData.pct and MI2_HpData.pct < 10 then newQuality = 1 end
		if newQuality == MI2_HpData.dbQuality then
			local delta = newHpMax / 100 + 1
			if MI2_HpData.dbQuality == 1 or abs(MI2_HpData.dbMax - newHpMax) > delta then
				newHpMax = (MI2_HpData.dbMax + newHpMax) / 2
			else
				newHpMax = max(MI2_HpData.dbMax, newHpMax)
			end
		end
		MI2_HpSet( MI2_Target.healthDB, MI2_Target.index, newHpMax, newQuality )
	end
end

function MI2_MobHealth_ClearTargetData()
	if MI2_Target.index then
		MI2_Target.healthDB[MI2_Target.index] = nil
		MI2_Target = {}
		MobHealth_Display()
		MI2_HpData = nil
	end
end

local function MI2_CalculateHp()
	local numDmg = getn( MI2_HpDmg )
	local numPct = getn( MI2_HpPctList )
	if numPct < 2 or numDmg < 2 then return end
	local firstPct = MI2_HpPctList[1][1]
	local lastPct = MI2_HpPctList[numPct][1]
	local deltaPct = firstPct - lastPct
	local dmg1 = MI2_HpDmg[MI2_HpPctList[numPct][2]]
	local dmg2 = (MI2_HpDmg[MI2_HpPctList[numPct][2]+1] or dmg1)
	local hpm1 = dmg1 * 100 / deltaPct
	local hpm2 = dmg2 * 100 / deltaPct
	MI2_HpData.pct = deltaPct
	if MI2_Debug > 0 then tinsert( MI2_HpTexts, "hpm=("..floor(hpm1).."/"..floor(hpm2).."), dmg=("..dmg1.."/"..dmg2.."), dPct="..deltaPct ) end
	local hpm1Count = 0
	local hpm2Count = 0
	local hpm1Delta = (hpm1 / 50) + 1
	local hpm2Delta = (hpm2 / 50) + 1
	for i=2,(numPct-1) do
		local dmg = MI2_HpDmg[MI2_HpPctList[i][2]]
		if dmg then
			local pct = MI2_HpPctList[i][1]
			local hpm = dmg * 100 / (firstPct - pct)
			if abs(hpm-hpm1) < hpm1Delta then hpm1Count = hpm1Count + 1 end
			if abs(hpm-hpm2) < hpm2Delta then hpm2Count = hpm2Count + 1 end
		end
	end
	local hpm, hpmCount, hpmDelta
	if hpm2Count > hpm1Count then
		hpm = hpm2
		hpmCount = hpm2Count
		hpmDelta = hpm2Delta
		if MI2_Debug > 0 then tinsert( MI2_HpTexts, "hpm[2]="..floor(hpm2)..", hpm1Count="..hpm1Count..", hpm2Count="..hpm2Count ) end
	else
		hpm = hpm1
		hpmCount = hpm1Count
		hpmDelta = hpm1Delta
		if MI2_Debug > 0 then tinsert( MI2_HpTexts, "hpm[1]="..floor(hpm1)..", hpm1Count="..hpm1Count..", hpm2Count="..hpm2Count ) end
	end
	if not MI2_HpData.maxCount or hpmCount >= MI2_HpData.maxCount then
		MI2_HpData.maxCount = hpmCount
		if MI2_HpData.newMax and abs(hpm-MI2_HpData.newMax) < hpmDelta then
			MI2_HpData.newMax = max( hpm, MI2_HpData.newMax )
		else
			MI2_HpData.newMax = hpm
		end
	end
	if MI2_Debug > 0 then tinsert( MI2_HpTexts, ">>  "..floor(MI2_HpData.newMax).." ("..MI2_HpData.maxCount..") <<" ) end
end

function MI2_RecordTargetCombat( damage, isHeal )
	if MI2_Debug > 0 then
		if isHeal then
			tinsert( MI2_HpTexts, "    *H*="..damage.." -> "..(MI2_HpData.totalDmg-damage)..", (p="..UnitHealth("target")..")" )
		else
			tinsert( MI2_HpTexts, "    *D*="..damage.." -> "..(MI2_HpData.totalDmg+damage) )
		end
	end
	if isHeal then
		MI2_HpData.totalDmg = max( (MI2_HpData.totalDmg-damage), 0 )
	else
		MI2_HpData.totalDmg = MI2_HpData.totalDmg + damage
	end
	if MI2_HpData.totalDmg > 0 then
		tinsert( MI2_HpDmg, MI2_HpData.totalDmg )
		if MI2_HpData.pctAdded then
			MI2_CalculateHp()
			MI2_HpData.pctAdded = nil
		end
	end
end

function MI2_RecordTargetHealth( health )
	if not MI2_HpData.dbQuality then return end
	if MI2_Debug > 0 then tinsert( MI2_HpTexts, "    *P*="..health ) end
	local unitHpMax = UnitHealthMax("target")
	if unitHpMax ~= 100 then
		MI2_HpData.newMax = unitHpMax
		MI2_HpData.newQuality = 3
		MI2_HpData.pctAdded = nil
		MI2_Target.unitHealth = floor(100.0 * health / MI2_HpData.newMax + 0.5)
		MI2_Target.curHealth = health
		MI2_Target.maxHealth = unitHpMax
	else
		MI2_Target.unitHealth = health
		if MI2_HpData.newQuality < 3 and health > 1 and health < 100 then
			tinsert( MI2_HpPctList, {health,getn(MI2_HpDmg)} )
			MI2_HpData.pctAdded = true
		end
		local hpMax = (MI2_HpData.newMax or MI2_HpData.dbMax)
		if hpMax then
			if MI2_HpData.dbQuality < 2 or not MI2_Target.maxHealth then
				MI2_Target.maxHealth = floor(hpMax + 0.5)
				if MI2_HpData.dbQuality < 1 then
				    MI2_SaveTargetHealthData( true )
				end
			end
			MI2_Target.curHealth = floor((MI2_Target.maxHealth * health) / 100 + 0.5)
		end
	end
	MobHealth_Display()
end