
-- these are kept for debug purposes. We need two because next attack abilities are split into two.
KLHTM_LastAttack = nil
KLHTM_SecondLastAttack = nil
KLHTM_LifeTapWasLastAction = false

function KLHTM_MyRaidThreat()

	return KLHTM_MyData[KLHTM_String("threatsource", "total")].threat + KLHTM_RaidThreatOffset

end

function KLHTM_ResetRaidThreat()
	
	KLHTM_RaidThreatOffset = - KLHTM_MyData[KLHTM_String("threatsource", "total")].threat
	
end

-- from the mod's OnEvent method
function KLHTM_CombatOnEvent()

	if KLHTM_CombatOnEventInternal()then 
		KLHTM_RedrawTable(KLHTM_MainWindow)
	end
	
end

-- This is used by a few methods in this file. Declared at file level to avoid memory reuse.
local combatevent = 
{
	["hits"] = 0,
	["damage"] = 0,
	["rage"] = 0,
	["threat"] = 0,
	["name"] = 0,
}
	
-- returns non-nil if a valid combat event is picked up
function KLHTM_CombatOnEventInternal()
	
	local ability
	local target
	local amount
	local isholy = false -- important: defaults to false.
	local damagetype
	
	if event == "CHAT_MSG_SPELL_FAILED_LOCALPLAYER" then
		if string.find(arg1, KLHTM_String("spell", "sunder")) then
			KLHTM_RetractSunderCast(arg1)
			return true 
		else
			return
		end
	
	elseif event == "CHAT_MSG_MONSTER_EMOTE" then
		KLHTM_PrintTrace("MonsterEmote", "Emote: " .. arg1)
		
		if string.find(arg1, KLHTM_String("combatlog", "razorphase2")) then
			KLHTM_ResetRaidThreat()
			KLHTM_MasterTarget = KLHTM_String("mobs", "razorgore")
			KLHTM_Print(KLHTM_String("print", "combat", "razorphase2"))
			return true
		end
	
	elseif event == "CHAT_MSG_MONSTER_YELL" then
		if string.find(arg1, KLHTM_String("combatlog", "onyxiaphase3")) then
			KLHTM_Print(KLHTM_String("print", "combat", "onyxiaphase3"))
			KLHTM_ResetRaidThreat()
			return true 
		end
	
	elseif event == "CHAT_MSG_COMBAT_FRIENDLY_DEATH" then
		
		if arg1 == UNITDIESSELF then
			-- wipe your raid threat
			KLHTM_ResetRaidThreat()
			return true
		end
	
	elseif event == "CHAT_MSG_COMBAT_SELF_HITS" then
		
		for target, amount in string.gfind(arg1, KLHTM_String("combatlog", "whiteattackhit")) do
			KLHTM_RegisterHit(KLHTM_String("threatsource", "whitedamage"), amount, false, target, false)
			return true 
		end

		for target, amount in string.gfind(arg1, KLHTM_String("combatlog", "whiteattackcrit")) do
			KLHTM_RegisterHit(KLHTM_String("threatsource", "whitedamage"), amount, false, target, true)
			return true
		end

	elseif event == "CHAT_MSG_SPELL_DAMAGESHIELDS_ON_SELF" then
		
		for amount, damagetype, target in string.gfind(arg1, KLHTM_String("combatlog", "damageshield")) do
			if damagetype == SPELL_SCHOOL1_CAP then -- SPELL_SCHOOL1_CAP = "Holy"
				isholy = true
			end
			
			KLHTM_RegisterHit(KLHTM_String("threatsource", "damageshield"), amount, false, target, false, isholy)
			return true
		end 
		
	-- max 448 bytes memory created
	elseif event == "CHAT_MSG_SPELL_SELF_DAMAGE" then
			
		-- 1) Spell School Damage Crit
		for ability, target, amount, damagetype in string.gfind(arg1, KLHTM_String("combatlog", "spellcrit")) do
			
			if damagetype == SPELL_SCHOOL1_CAP then -- SPELL_SCHOOL1_CAP = "Holy"
				isholy = true
			end
			
			KLHTM_RegisterHit(ability, amount, false, target, true, isholy)
			return true
		end
		
		-- 2) Spell School Damage Hit
		for ability, target, amount, damagetype in string.gfind(arg1, KLHTM_String("combatlog", "spellhit")) do
			
			if damagetype == SPELL_SCHOOL1_CAP then -- SPELL_SCHOOL1_CAP = "Holy"
				isholy = true
			end
			
			KLHTM_RegisterHit(ability, amount, false, target, true, isholy)
			return true
		end
				
		-- 3) Non-School Ability Hits
		for ability, target, amount in string.gfind(arg1, KLHTM_String("combatlog", "abilityhit")) do
			KLHTM_RegisterHit(ability, amount, false, target, false)
			return true
		end
		
		-- 4) Non-School Ability Crits
		for ability, target, amount in string.gfind(arg1, KLHTM_String("combatlog", "abilitycrit")) do
			KLHTM_RegisterHit(ability, amount, false, target, false)
			return true
		end
		
		-- 5) Special Attacks
		for ability, target in string.gfind(arg1, KLHTM_String("combatlog", "perform")) do
			
			if (KLHTM_MyLocale == "zhTW") or (KLHTM_MyLocale == "zhCN") then
				ability, target = target, ability
			end
						
			if ability == KLHTM_String("spell", "feint") then
				KLHTM_RegisterHit(ability, 0, false, target, false)
				return true
			
			elseif ability == KLHTM_String("spell", "cower") then
				KLHTM_RegisterHit(ability, 0, false, target, false)
				return true
				
			elseif ability == KLHTM_String("spell", "taunt") then
				KLHTM_RegisterTaunt(target)
				return true
				
			elseif ability == KLHTM_String("spell", "growl") then
				KLHTM_RegisterTaunt(target)
				return true
			end
			
			return
		end
			
		-- 6) Sunder fails due to parry / dodge / miss
		for target in string.gfind(arg1, KLHTM_String("spell", "sunder")) do
			KLHTM_RetractSunderCast(arg1)
			return true
		end
		
		-- 7) Black Amnesty proc
		for ability, target in string.gfind(arg1, KLHTM_String("combatlog", "spellcast")) do
			
			if (KLHTM_MyLocale == "zhTW") or (KLHTM_MyLocale == "zhCN") then
				-- {2, 1}
				target, ability = ability, target
			end
			
			if ability == KLHTM_String("spell", "reducethreat") then
				KLHTM_RegisterHit("blackamnesty", 0, false, target, false, false)
				return true
			end
			
			return
		end

	elseif event == "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE" then

		for target, amount, damagetype, ability in string.gfind(arg1, KLHTM_String("combatlog", "dot")) do
				
			if damagetype == SPELL_SCHOOL1_CAP then -- SPELL_SCHOOL1_CAP = "Holy"
				isholy = true
			end
			
			if KLHTM_MyLocale == "frFR" then
				-- 4, 2, 3, 1
				ability, amount, damagetype, target = target, amount, damagetype, ability
				
			elseif (KLHTM_MyLocale == "zhTW") or (KLHTM_MyLocale == "zhCN") then
				-- 4, 1, 2, 3
				ability, target, amount, damagetype = target, amount, damagetype, ability
			end
			
			KLHTM_RegisterHit(ability, amount, true, target, false, isholy)
			
			return true
		end
	
	elseif event == "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS" then
		
		-- heal over times deduct overheals automatically
		for target, amount, ability in string.gfind(arg1, KLHTM_String("combatlog", "yourhotonother")) do

			if KLHTM_MyLocale == "frFR" then
				-- French has inverted argument order
				KLHTM_RegisterPossibleOverheal(target, amount, ability, true)
				
			else
				KLHTM_RegisterPossibleOverheal(ability, amount, target, true)
			end
			
			return true
		end
	
	elseif event ==	"CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" then
		
		-- a) clean out hots by other players
		for amount, _, _ in string.gfind(arg1, KLHTM_String("combatlog", "othershotonyou")) do
			return
		end
		
		-- b) hots from us
		for amount, ability in string.gfind(arg1, KLHTM_String("combatlog", "hotonself")) do

			if (KLHTM_MyLocale == "frFR") or (KLHTM_MyLocale == "zhTW") or (KLHTM_MyLocale == "zhCN") then
				-- 2, 1
				amount, ability = ability, amount
			end
			
			KLHTM_RegisterPossibleOverheal(ability, amount, UnitName("player"), true) 
			
			return true
		end
		
		-- c) periodic power gain (bloodrage, essence of the red, etc)
		for amount, ability, source in string.gfind(arg1, KLHTM_String("combatlog", "powergain")) do
			
			if (KLHTM_MyLocale == "zhTW") or (KLHTM_MyLocale == "zhCN") then
				-- 3, 1, 2
				source, amount, ability = amount, ability, source
			end
			
			KLHTM_RegisterPowerGain(amount, ability)
			return true
		end
	
		-- Buff gains
		for ability in string.gfind(arg1, KLHTM_String("combatlog", "buffstart")) do
			
			-- Fetish of the Sand Reaver activation
			if ability == KLHTM_String("spell", "arcaneshroud") then
				KLHTM_SetState("arcaneshroud", true)
			
			-- Rogue Vanish
			elseif ability == KLHTM_String("spell", "vanish") then
				
				-- this is a threat wipe, not a threat reset.
				combatevent.hits = 1
				combatevent.damage = 0
				combatevent.rage = 0
				combatevent.threat = -KLHTM_MyRaidThreat()
							
				KLHTM_AddAttackToData(KLHTM_String("threatsource", "threatwipe"), combatevent)
				KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
				return true
			end
			
			return
		end
				
	elseif event == "CHAT_MSG_SPELL_SELF_BUFF" then

		-- 1) Crit Heal on Self
		for ability, amount in string.gfind(arg1, KLHTM_String("combatlog", "healcritonself")) do
			KLHTM_RegisterPossibleOverheal(ability, amount, UnitName("player"), false)
			return true
		end
		
		-- 2) Non Crit Heal on Self
		for ability, amount in string.gfind(arg1, KLHTM_String("combatlog", "healhitonself")) do
			KLHTM_RegisterPossibleOverheal(ability, amount, UnitName("player"), false)
			return true
		end
		
		-- 3) Crit Heal on Other
		for ability, target, amount in string.gfind(arg1, KLHTM_String("combatlog", "healcritonother")) do
			KLHTM_RegisterPossibleOverheal(ability, amount, target, false)
			return true
		end
		
		-- 4) Heal Hit on Other
		for ability, target, amount in string.gfind(arg1, KLHTM_String("combatlog", "healhitonother")) do
			KLHTM_RegisterPossibleOverheal(ability, amount, target, false)
			return true
		end
		
		-- catch earthfury mana gain, mana pot, etc
		for amount, ability, source in string.gfind(arg1, KLHTM_String("combatlog", "powergain")) do
			
			if KLHTM_MyLocale == "frFR" then
				amount = ability
				ability = source
			end
						
			-- stop Warlock life tap mana gain
			if (ability == KLHTM_String("power", "mana")) and (KLHTM_LifeTapWasLastAction == true) then
				KLHTM_LifeTapWasLastAction = false
				return
			else
				KLHTM_RegisterPowerGain(amount, ability)
				return true
			end
			
		end
		
	elseif event == "CHAT_MSG_SPELL_PERIODIC_SELF_DAMAGE" then
		
		-- Debuff gains
		for ability in string.gfind(arg1, KLHTM_String("combatlog", "debuffstart")) do
			if ability == KLHTM_String("spell", "burningadrenaline") then
				KLHTM_SetState("burningadrenaline", true)
				
			elseif ability == KLHTM_String("spell", "twinteleport") then
				KLHTM_ResetThreat() 
			end
			
			return -- don't return true, no threat change
		end
		
	elseif event == "CHAT_MSG_SPELL_AURA_GONE_SELF" then
		
		-- Buff / Debuff fades
		for ability in string.gfind(arg1, KLHTM_String("combatlog", "buffend")) do
			
			if ability == KLHTM_String("spell", "burningadrenaline") then
				KLHTM_SetState("burningadrenaline", false)
				
			elseif ability == KLHTM_String("spell", "arcaneshroud") then
				KLHTM_SetState("arcaneshroud", false)
				
			elseif ability == KLHTM_String("spell", "twinteleport") then 
				-- Search for targetting from either Emp.
				
			end
			
			return -- don't return true, no threat change
		end
		
	elseif event == "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE" then
		
		for target, ability, amount in string.gfind(arg1, KLHTM_String("combatlog", "enemyspellhit")) do
			
			if KLHTM_MyLocale == "frFR" then
				-- 2, 1, 3
				ability, target, amount = target, ability, amount
			end
			
			if KLHTM_RegisterPossibleKnockback(target, ability) then
				return true
			end
		end
		
	else
		return
	end
	
end

function KLHTM_TwinEmperorScript()

	

end


function KLHTM_RegisterPossibleKnockback(Enemy, Ability)

	local knockbackdata
	local mobname
	local knockbackvalue
	local mobfound = false

	combatevent.hits = 1
	combatevent.damage = 0
	combatevent.rage = 0
	
	-- Check whether this ability is a known threat reducer
	knockbackdata = KLHTM_Knockbacks[Ability]
	if  knockbackdata == nil then
		return
	end
	
	-- Now look for the specific value for our mob, if it exists
	if knockbackdata[Enemy] then
		knockbackvalue = knockbackdata[Enemy]
	else
		knockbackvalue = knockbackdata["#Default"]
	end
	
	-- Some knockbacks don't reduce threat (e.g. Onyxia Wing Buffet)
	if knockbackvalue == 0 then 
		return
	end
	
	-- create a combat event and fire it		
	combatevent.threat = knockbackvalue * KLHTM_MyRaidThreat()
	
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "threatwipe"), combatevent)
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)				
							
	-- Debug Print for Verification:
	KLHTM_PrintTrace("Knockback", Event)
	
	-- Report it for knockback discovery
			
	if (KLHTM_KnockbackDiscoveryIsActive == true) and Enemy == KLHTM_MasterTarget then
		KLHTM_SendMessage("knockaway " .. math.ceil(0.5 + KLHTM_MyRaidThreat))
		KLHTM_SendMessage("knockawaytext {" .. Enemy .. ", " .. Ability .. ", " .. knockbackvalue .. "}")
	end
	
end

-- Sunder has failed for some reason, so remove it from our threat data
function KLHTM_RetractSunderCast(reason)

	-- 1) check for master target
	if (KLHTM_MasterTarget ~= nil) and (UnitName("target") ~= KLHTM_MasterTarget) then
		return -- disregard; master target was not targetted
	end

	combatevent.hits = -1
	combatevent.damage = 0
	combatevent.rage = - KLHTM_Ability(KLHTM_String("spell", "sunder"), "rage")
	
	local threatmodifier = KLHTM_GlobalThreat.Value
	combatevent.threat = - KLHTM_Ability(KLHTM_String("spell", "sunder"), "threat") * threatmodifier

	KLHTM_AddAttackToData(KLHTM_String("spell", "sunder"), combatevent)
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
	
	KLHTM_RedrawTable(KLHTM_MainWindow)
end

function KLHTM_RegisterTaunt(target)
	
	KLHTM_PrintTrace("TargetDebug", "Taunting " .. target .. "!")
	
	if target == KLHTM_MasterTarget then
		local previoustargetthreat = KLHTM_RaidData[KLHTM_MTTrueTarget]
		
		if (previoustargetthreat ~= nil) and (previoustargetthreat > KLHTM_MyRaidThreat()) then
			local tauntgain = previoustargetthreat - KLHTM_MyRaidThreat()
			
			combatevent.hits = 1
			combatevent.damage = 0
			combatevent.rage = 0
			combatevent.threat = tauntgain
			combatevent.name = KLHTM_String("spell", "taunt")
			
			KLHTM_AddAttackToData(KLHTM_String("spell", "taunt"), combatevent)
			KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
		
			KLHTM_PrintTrace("TargetDebug", string.format("You taunt %s from %s, gaining %d threat.", target, KLHTM_MTTrueTarget or "<nil>", tauntgain))
		
		else
			KLHTM_PrintTrace("TargetDebug", string.format("You taunt %s from %s, but he had a lower threat, so you gain no threat.", target, KLHTM_MTTrueTarget or "<nil>"))
		end
	end
	
end

-- combatevent structure has .hits, .damage, .threat, .name, .rage
function KLHTM_RegisterHit(attack, damage, isdot, target, iscrit, isholy)
	-- e.g. attack = "Heroic Strike", damage = 150, isdot = false, target = "Elder Mottled Boar", iscrit = false
	
	if damage == nil then
		KLHTM_PrintTrace("Assertion", "Damage is nil for attack '" .. attack or "<nil>" .. "'.")
		damage = 0
	end
	
	-- Check for Master Target Match
	if KLHTM_MasterTarget ~= nil then
		
		-- check for nil target. shoudln't happen, but it is
		if target == nil then
			KLHTM_PrintTrace("Assertion", string.format("nil target found. damage = %d, attack = %s.", damage, attack))
		
		elseif target ~= KLHTM_MasterTarget then
			-- disregard this completely
			return
		end
	end

	-- threatmodifier includes global things, like defensive stance, tranquil air totem, rogue passive modifier, etc.
	local threatmodifier = KLHTM_GlobalThreat.Value
	
	combatevent.hits = 1
	combatevent.rage = 0
	combatevent.name = attack
	combatevent.damage = damage
	
	if attack == KLHTM_String("threatsource", "whitedamage") then

		combatevent.threat = damage * threatmodifier

	elseif attack == KLHTM_String("spell", "heroicstrike") then
		-- this one is special, hard to integrate with the rest, so it goes on its own
		-- basic idea is to split it into a white damage hit and a heroic strike hit
		
		local preimpaledamage = damage
		if iscrit == true then
			preimpaledamage = damage / (1 + KLHTM_ThreatParameters.impalebonus)
		end
		
		local addeddamage = KLHTM_Ability(attack, "nextattack")
		local myaveragedamage = KLHTM_AverageMainHandDamage()
		local whitedamage = preimpaledamage * (myaveragedamage / (addeddamage + myaveragedamage))
		
		KLHTM_RegisterHit(KLHTM_String("threatsource", "whitedamage"), whitedamage, isdot, target, iscrit)
		
		combatevent.damage = damage - whitedamage
		combatevent.threat = (combatevent.damage + KLHTM_Ability(attack, "threat")) * threatmodifier
		combatevent.rage =  KLHTM_Ability(attack, "rage") + whitedamage / (UnitLevel("player") / 2)
		
	elseif attack == KLHTM_String("spell", "maul") then
		-- same as heroic strike, but a bit different
		
		local presavagefurydamage = damage / (1 + KLHTM_ThreatParameters.savagefurybonus)		
		local addeddamage = KLHTM_Ability(attack, "nextattack")
		local myaveragedamage = KLHTM_AverageMainHandDamage()
		local whitedamage = presavagefurydamage * (myaveragedamage / (addeddamage + myaveragedamage))
		
		KLHTM_RegisterHit(KLHTM_String("threatsource", "whitedamage"), whitedamage, isdot, target, iscrit)
		
		combatevent.damage = damage - whitedamage
		combatevent.threat = threatmodifier * (damage * KLHTM_Ability(attack, "multiplier") - whitedamage)
		combatevent.rage = KLHTM_Ability(attack, "rage") + whitedamage / (UnitLevel("player") / 2)
		
	elseif attack == KLHTM_String("spell", "swipe") then
		-- another special case
		combatevent.damage = damage
		combatevent.threat = damage * KLHTM_Ability(attack, "multiplier") * threatmodifier
		combatevent.rage = KLHTM_Ability(attack, "rage") 
	
	elseif (attack == KLHTM_String("spell", "feint")) or (attack == KLHTM_String("spell", "cower")) then
		
		combatevent.threat = KLHTM_Ability(attack, "threat") * threatmodifier
		
		-- However, feint can't take you negative
		if combatevent.threat + KLHTM_MyRaidThreat() < 0 then
			combatevent.threat = - KLHTM_MyRaidThreat() 
		end
	
		-- make this attack come up in the "Threat Wipes" row of your personal meter
		attack = KLHTM_String("threatsource", "threatwipe")
	
	elseif attack == "blackamnesty" then -- black amnesty proc
		combatevent.threat = -540 * threatmodifier
		
		-- However, -threat abilities can't take you negative
		if combatevent.threat + KLHTM_MyRaidThreat() < 0 then
			combatevent.threat = - KLHTM_MyRaidThreat() 
		end
	
		-- make this attack come up in the "Threat Wipes" row of your personal meter
		attack = KLHTM_String("threatsource", "threatwipe")
		
	-- "if there is a row in the personal meter with the same name as this ability, then..."
	elseif KLHTM_MyData[attack] then
		
		combatevent.threat = (damage + KLHTM_Ability(attack, "threat")) * threatmodifier
		combatevent.rage = KLHTM_Ability(attack, "rage")

	-- these are periodic_spell_damage
	elseif isdot == true then
		
		combatevent.hits = 0
		attack = KLHTM_String("threatsource", "dot")
		combatevent.threat = damage * threatmodifier
		
	else
		attack = KLHTM_String("threatsource", "special")
		combatevent.threat = damage * threatmodifier
	end
	
	-- Now apply class-specific filters
	
	-- warlock
	if UnitClass("player") == KLHTM_String("class", "warlock") then
			
		-- Nemesis 8/8
		if (KLHTM_ThreatParameters.nemesis8active == true) and (KLHTM_SpellMatchesSet("Warlock Destruction", combatevent.name) == true) then
			combatevent.threat = combatevent.threat * 0.8
		end
	
	-- Priest
	elseif UnitClass("player") == KLHTM_String("class", "priest") then
			
		-- silent resolve
		if attack ~= KLHTM_String("threatsource", "whitedamage") then
			combatevent.threat = combatevent.threat * KLHTM_ThreatParameters.priestspellthreat
		end 

		-- shadow affinity
		if KLHTM_SpellMatchesSet("Priest Shadow Spells", combatevent.name) == true then
			combatevent.threat = combatevent.threat * KLHTM_ThreatParameters.priestshadowdamage
		end
		
	-- Mage
	elseif UnitClass("player") == KLHTM_String("class", "mage") then
			
		-- netherwind
		if KLHTM_ThreatParameters.netherwind3active == true then
			if (combatevent.name == KLHTM_String("spell", "frostbolt")) or (combatevent.name == KLHTM_String("spell", "scorch")) then
				combatevent.threat = math.max(0, (damage - 100) * threatmodifier)
			
			elseif (combatevent.name == KLHTM_String("spell", "fireball")) and (isdot == false) then
				combatevent.threat = math.max(0, (damage - 100) * threatmodifier)
				
			elseif combatevent.name == KLHTM_String("spell", "arcanemissiles") then
				combatevent.threat = math.max((damage - 20) * threatmodifier)
			end
		end
		
		-- arcane subtlety
		if KLHTM_SpellMatchesSet("Mage Offensive Arcane", combatevent.name) == true then
			combatevent.threat = combatevent.threat * KLHTM_ThreatParameters.magearcanedamage
		end
		
	-- Paladin
	elseif UnitClass("player") == KLHTM_String("class", "paladin") then
		
		-- righteous fury
		if isholy == true then
			combatevent.threat = combatevent.threat * KLHTM_ThreatParameters.paladinholythreat
		end
	end

	-- now add combatevent to individual and totals
	KLHTM_AddAttackToData(attack, combatevent)
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
end

-- to work out which part of a next attack ability was from white damage
function KLHTM_AverageMainHandDamage()

	local min, max = UnitDamage("player")
	return (min + max) / 2

end

function KLHTM_RegisterPossibleOverheal(spell, amount, target, isdot)
	
	-- we can check the target's health, which will be the health before the heal. Then we work out what the 
	-- heal did, and we can calculate overheal.
	
	-- for target, 1) check "you", 2) check partyx, 3) check raidx, 4) raidxpet
	
	local unit = KLHTM_FindUnitIdFromName(target)
	
	if unit == nil then
		KLHTM_PrintTrace("TargetNotInRaid", "Could not find a UnitID for the name " .. target)
		-- (and assume there was no overheal)
	else
		local hpvoid = UnitHealthMax(unit) - UnitHealth(unit)
		amount = math.min(amount, hpvoid)
	end
	
	KLHTM_RegisterHeal(spell, amount, isdot, target)
	
end

function KLHTM_FindUnitIdFromName(name)
	
	if name == UnitName("player") then
		return "player"
	end 
	
	local x = 0
	
	if GetNumRaidMembers() > 0 then
		for x = 1, 40 do
			if UnitName("raid" .. x) == name then
				return "raid" .. x
			end
		end
		
		for x = 1, 40 do
			if UnitName("raidpet" .. x) == name then
				return "raidpet" .. x
			end
		end
		
	elseif GetNumPartyMembers() > 0 then
		for x = 1, 4 do
			if UnitName("party" .. x) == name then
				return "party" .. x
			end
		end
		
		for x = 1, 4 do
			if UnitName("partypet" .. x) == name then
				return "partypet" .. x
			end
		end
	end
	
end

function KLHTM_RegisterHeal(spell, amount, isdot, target)

	if target == KLHTM_String("mobs", "ebonroc") then
		return
		
	-- in general, don't count heals towards the master target
	elseif target == KLHTM_MasterTarget then
		return
	end

	combatevent.name = spell
	combatevent.hits = 1
	combatevent.rage = 0
	combatevent.damage = amount
	combatevent.threat = amount * KLHTM_ThreatParameters.healing * KLHTM_GlobalThreat.Value
	
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "healing"), combatevent)
	
	combatevent.damage = 0
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
end

-- powertype = "Rage" or "Energy" or "Mana". Could be a random different value; then it wil be ignored.
function KLHTM_RegisterPowerGain(amount, powertype)
	
	combatevent.name = powertype .. " Gain"
	combatevent.damage = amount
	combatevent.hits = 1
	combatevent.rage = 0
	
	if powertype == KLHTM_String("power", "rage") then
		combatevent.threat = amount * KLHTM_ThreatParameters.ragegain
		
	elseif powertype == KLHTM_String("power", "energy") then
		combatevent.threat = amount * KLHTM_ThreatParameters.energygain
		
	elseif powertype == KLHTM_String("power", "mana") then
		combatevent.threat = amount * KLHTM_ThreatParameters.managain
		
	else
		return
	end
	
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "powergain"), combatevent)
	
	-- now mod it a bit to work into total beter
	combatevent.damage = 0
	combatevent.hits = 0
	
	KLHTM_AddAttackToData(KLHTM_String("threatsource", "total"), combatevent)
	
end

function KLHTM_AddAttackToData(name, data)
	
	-- Ignore if charmed
	if KLHTM_States.playercharmed.value == true then
		return
	end 
	
	if name ~= KLHTM_String("threatsource", "total") then
		KLHTM_SecondLastAttack = KLHTM_LastAttack
		KLHTM_LastAttack = data
		
		-- Add this to the recent attacks list, if we are not in combat
		if KLHTM_States.incombat.value == false then
			table.insert(KLHTM_RecentAttacks, {GetTime(), data.threat})
		end
	end
	
	KLHTM_MyData[name].hits = KLHTM_MyData[name].hits + data.hits
	KLHTM_MyData[name].threat = KLHTM_MyData[name].threat + data.threat
	KLHTM_MyData[name].rage = KLHTM_MyData[name].rage + data.rage
	KLHTM_MyData[name].damage = KLHTM_MyData[name].damage + data.damage
	
end

-- Call this from other addons that cast Sunder for you
function KLHTM_SubmitSunderCast()
	
	-- check for Master Target
	if (KLHTM_MasterTarget ~= nil) and  (UnitName("target") ~= KLHTM_MasterTarget) then
		return -- disregard; this is not an action against the master target
	end
	
	KLHTM_RegisterHit(KLHTM_String("spell", "sunder"), 0, false, UnitName("target"))
	KLHTM_RedrawTable(KLHTM_MainWindow)
end

-- Call this from a macro, to replace your normal sunder button
KLHTM_SpellBookSunderIndex = 1

function KLHTM_Sunder()
	
	if UnitClass("player") ~= KLHTM_String("class", "warrior") then
		return
	end
	
	-- 1) Check if the old position is fine
	if GetSpellName(KLHTM_SpellBookSunderIndex, "spell") ~= KLHTM_String("spell", "sunder") then
		
		-- get spell number of spells
		local spelltabs = GetNumSpellTabs()
		local numspells = 0
		local i;	local temp
	
		for i = 1, spelltabs do
			_, _, _, temp = GetSpellTabInfo(i)
			numspells = numspells + temp
		end
	
		-- 2) locate sunder armor in the spell book
		for i = 1, numspells do
			if GetSpellName(KLHTM_SpellBookSunderIndex + i, "spell") == KLHTM_String("spell", "sunder") then
				KLHTM_SpellBookSunderIndex = KLHTM_SpellBookSunderIndex + i
				break
				
			elseif i == numspells then
				KLHTM_PrintTrace("SunderDebug", "Can't find sunder in your spellbook!")
				return -- can't find sunder
			end
		end
	end
	
	-- Now we've found sunder. Check the cooldown		
	if GetSpellCooldown(KLHTM_SpellBookSunderIndex, "spell") ~= 0 then 
		return
	end
	
	-- Test for target
	if UnitCanAttack("player", "target") == nil then
		return
	end 
	
	-- Cast
	CastSpellByName(KLHTM_String("spell", "sunder") .. "()")
	KLHTM_SubmitSunderCast()
	
end


KLHTM_OriginalUseAction = UseAction

function KLHTM_NewUseAction(ActionIndex, x, y)
	
	-- Check Sunder
	if UnitClass("player") == KLHTM_String("class", "warrior") and ActionIndex ~= nil and GetActionText(ActionIndex) == nil and GetActionTexture(ActionIndex) == "Interface\\Icons\\Ability_Warrior_Sunder" then
		if GetActionCooldown(ActionIndex) > 0 then
			KLHTM_PrintTrace("SunderDebug", "Preventing Sunder cast due to cooldown!")
			return
			
		else
			-- Now check we have a decent target. Otherwise press "tab" - this is what the UI does anyway
			if UnitCanAttack("player", "target") ~= 1 then
				KLHTM_PrintTrace("SunderDebug", "Preventing Sunder cast due to invalid target!")
				return
			end
			
			KLHTM_SubmitSunderCast()
			-- At the bottom of this method the sunder will be cast
		end
	
	-- Check for Life Tap
	elseif UnitClass("player") == KLHTM_String("class", "warlock") and ActionIndex ~= nil then
		if GetActionText(ActionIndex) == nil and GetActionTexture(ActionIndex) == "Interface\\Icons\\Spell_Shadow_BurningSpirit" then
			KLHTM_LifeTapWasLastAction = true
		else
			KLHTM_LifeTapWasLastAction = false
		end
	end

   -- Call the original function
   KLHTM_OriginalUseAction(ActionIndex, x, y)   

end

UseAction = KLHTM_NewUseAction
