--[[
Name: Banzai-1.1
Revision: $Rev: 20651 $
Author(s): Rabbit (rabbit.magtheridon@gmail.com), maia
Documentation: http://www.wowace.com/index.php/Banzai-1.1_API_Documentation
SVN: http://svn.wowace.com/wowace/trunk/BanzaiLib/Banzai-1.1
Description: Aggro notification library.
Dependencies: AceLibrary, AceOO-2.0, AceEvent-2.0, Roster-2.1
]]

-------------------------------------------------------------------------------
-- Locals
-------------------------------------------------------------------------------

local MAJOR_VERSION = "Banzai-1.1"
local MINOR_VERSION = "$Revision: 20651 $"

if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary.") end
if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end

if AceLibrary:HasInstance("Banzai-1.0") then error(MAJOR_VERSION .. " can't run alongside Banzai-1.0.") end
if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0.") end
if not AceLibrary:HasInstance("AceEvent-2.0") then error(MAJOR_VERSION .. " requires AceEvent-2.0.") end
if not AceLibrary:HasInstance("Roster-2.1") then error(MAJOR_VERSION .. " requires Roster-2.1.") end

local lib = {}
AceLibrary("AceEvent-2.0"):embed(lib)

local RL = nil
local roster = nil
local playerName = nil

-------------------------------------------------------------------------------
-- Initialization
-------------------------------------------------------------------------------

-- Activate a new instance of this library
function activate(self, oldLib, oldDeactivate)
	if oldLib then
		self.vars = oldLib.vars
		if oldLib:IsEventScheduled("UpdateAggroList") then
			oldLib:CancelScheduledEvent("UpdateAggroList")
			self:StartOrStop()
		end
	else
		self.vars = {}
	end

	RL = AceLibrary("Roster-2.1")
	roster = RL.roster
	playerName = UnitName("player")

	if not self.vars then self.vars = {} end

	self:RegisterEvent("AceEvent_EventRegistered", "StartOrStop")
	self:RegisterEvent("AceEvent_EventUnregistered", "StartOrStop")

	if oldDeactivate then oldDeactivate(oldLib) end
end

-------------------------------------------------------------------------------
-- Events
-------------------------------------------------------------------------------

function lib:StartOrStop()
	local aceEvent = AceLibrary("AceEvent-2.0")
	if aceEvent:IsEventRegistered("Banzai_UnitGainedAggro") or
		aceEvent:IsEventRegistered("Banzai_PlayerGainedAggro") or
		aceEvent:IsEventRegistered("Banzai_UnitLostAggro") or
		aceEvent:IsEventRegistered("Banzai_PlayerLostAggro") or
		aceEvent:IsEventRegistered("Banzai_Run") then
		if not self:IsEventScheduled("UpdateAggroList") then
			self:ScheduleRepeatingEvent("UpdateAggroList", self.UpdateAggroList, 0.2, self)
			self.vars.running = true
			self:TriggerEvent("Banzai_Enabled")
		end
	elseif self:IsEventRegistered("UpdateAggroList") then
		self:CancelScheduledEvent("UpdateAggroList")
		for i, unit in pairs(roster) do
			unit.banzai = nil
			unit.banzaiModifier = nil
		end
		self.vars.running = nil
		self:TriggerEvent("Banzai_Disabled")
	end
end

-------------------------------------------------------------------------------
-- Library
-------------------------------------------------------------------------------

function lib:UpdateAggroList()
	local oldBanzai = {}

	for i, unit in pairs(roster) do
		oldBanzai[unit.unitid] = unit.banzai

		-- deduct aggro for all, increase it later for everyone with aggro
		if not unit.banzaiModifier then unit.banzaiModifier = 0 end
		unit.banzaiModifier = math.max(0, unit.banzaiModifier - 5)

		-- check for aggro
		local targetId = unit.unitid .. "target"
		local targetName = UnitName(targetId .. "target")
		if roster[targetName] and UnitCanAttack("player", targetId) and UnitCanAttack(targetId, "player") then
			if not roster[targetName].banzaiModifier then roster[targetName].banzaiModifier = 0 end
			roster[targetName].banzaiModifier = roster[targetName].banzaiModifier + 10
			if not roster[targetName].banzaiTarget then roster[targetName].banzaiTarget = {} end
			table.insert(roster[targetName].banzaiTarget, targetId)
		end

		-- cleanup
		unit.banzaiModifier = math.max(0, unit.banzaiModifier)
		unit.banzaiModifier = math.min(25, unit.banzaiModifier)

		-- set aggro
		unit.banzai = (unit.banzaiModifier > 15)
	end

	for i, unit in pairs(roster) do
		if oldBanzai[unit.unitid] ~= nil and oldBanzai[unit.unitid] ~= unit.banzai then
			-- Aggro status has changed.
			if unit.banzai == true and unit.banzaiTarget then
				-- Unit has aggro
				self:TriggerEvent("Banzai_UnitGainedAggro", unit.unitid, unit.banzaiTarget)
				if unit.name == playerName then
					self:TriggerEvent("Banzai_PlayerGainedAggro", unit.banzaiTarget)
				end
			elseif unit.banzai == false then
				-- Unit lost aggro
				self:TriggerEvent("Banzai_UnitLostAggro", unit.unitid)
				if unit.name == playerName then
					self:TriggerEvent("Banzai_PlayerLostAggro", unit.unitid)
				end
			end
		end
		unit.banzaiTarget = nil
	end

	oldBanzai = nil
end

-------------------------------------------------------------------------------
-- API
-------------------------------------------------------------------------------

function lib:GetUnitAggroByUnitId( unitId )
	if not self.vars.running then error(MAJOR_VERSION.." is not running. You must register for one of the events.") end
	local rosterUnit = RL:GetUnitObjectFromUnit(unitId)
	if not rosterUnit then return nil end
	return rosterUnit.banzai
end

function lib:GetUnitAggroByUnitName( unitName )
	if not self.vars.running then error(MAJOR_VERSION.." is not running. You must register for one of the events.") end
	local rosterUnit = RL:GetUnitObjectFromName(unitName)
	if not rosterUnit then return nil end
	return rosterUnit.banzai
end

function lib:IsRunning()
	return self:IsEventScheduled("UpdateAggroList")
end

-------------------------------------------------------------------------------
-- Register
-------------------------------------------------------------------------------
AceLibrary:Register(lib, MAJOR_VERSION, MINOR_VERSION, activate)

