--------------------------------------------------------------------------------
-- GLOBALS
--------------------------------------------------------------------------------

--Widgets
Global( "AnnounceText", nil )

--Variables
Global('config', nil)
Global('avatarID', nil)
Global('avatarName', '')
Global('announceDesc', nil)
Global('announceList', {})
Global('announceContent', '')
Global('announceCount', 0)
Global('moving', false)
Global('checkpoints', {})
Global('avatarMarkId', nil)
Global('progressInfo', nil)

Global('colorList', {
	killedByPlayer = 0,
	playerKilled = 0,
	killedByFriend = 0,
	friendKilled = 0
})

--Announce constants
Global('ANNOUNCE_FADE_IN_TIME', 300)
Global('ANNOUNCE_FADE_OUT_TIME', 900)
Global('firstPos', {})
Global('distance', 0)

--------------------------------------------------------------------------------
-- EVENT HANDLERS
--------------------------------------------------------------------------------

--EVENT_AVATAR_CREATED
function OnAvatarCreated ()
	avatarID = avatar.GetId()
	avatarName = object.GetName(avatarID)
	--Register avatar-related handlers
	common.RegisterEventHandler(OnUnitDamageReceived, 'EVENT_UNIT_DAMAGE_RECEIVED')
	common.RegisterEventHandler(onMemberAdded, 'EVENT_MATCH_MAKING_EVENT_MEMBER_ADDED')
end


--EVENT_UNIT_DAMAGE_RECEIVED
function OnUnitDamageReceived (damage)	
	if unit.IsPlayer(damage.target) then
		if damage.lethal then		
			--The player was killed
			if damage.target == avatarID then
				if config['playerKilled'] then
					playerKilled(damage.source)
				end
			else
				--Someone else was killed
				unitKilled(damage.source, damage.target, unit.IsFriend(damage.target))
			end
		end
	end
end


--EVENT_MATCH_MAKING_EVENT_MEMBER_ADDED
function onMemberAdded (event)
	local eventId = matchMaking.GetCurrentEventId()
	local matchInfo = matchMaking.GetEventInfo(eventId)
	
	--matchMaking.ListenEventProgress(true)
	progressInfo = matchMaking.GetEventProgressInfo()
end


--EVENT_EFFECT_FINISHED
function onEffectFinished ( event )
	if event.effectType == ET_FADE then
		local fadeStatus = event.wtOwner:GetFade()
		
		--An announcement was removed
		if fadeStatus < 0.9 then
			--Destroy the widget and remove the nil reference from the list to prevent memory leaks
			event.wtOwner:Show(false)
			event.wtOwner:DestroyWidget()
			--Move all announcements down 1 place
			moveAnnouncements()
			table.remove(announceList, 1)
			announceCount = table.getn(announceList)
		end
		
		--Pretty clever, huh?
		if fadeStatus > 0.9 and fadeStatus < 1.0 then
			event.wtOwner:PlayFadeEffect( 1.0, 1.0, tonumber(config['visibleTime']), EA_MONOTONOUS_INCREASE )
		end
		
		if fadeStatus == 1.0 then
			event.wtOwner:PlayFadeEffect(1.0, 0.0, ANNOUNCE_FADE_OUT_TIME, EA_MONOTONOUS_INCREASE)
		end
	end
end

--------------------------------------------------------------------------------
-- FUNCTIONS
--------------------------------------------------------------------------------

function playerKilled (killerID)
	local killer = ''
	
	--To prevent the pet name from showing up instead of the owner in the anouncement
	if unit.IsPet(killerID) then
		killerID = unit.GetPetOwner(killerID)
	end
	
	killer = object.GetName(killerID)
	
	announceContent = string.format('You were killed by %s!', userMods.FromWString(killer))
	addAnnouncement('playerKilled')
end

function unitKilled (killerID, victimID, isFriendly)
	if killerID == nil then return end
	
	local killer = ''
	local victim = userMods.FromWString(object.GetName(victimID))
	
	if unit.IsPet(killerID) then
		killerID = unit.GetPetOwner(killerID)
	end
	
	killer = userMods.FromWString(object.GetName(killerID))
	
	if unit.IsPet(victimID) then
		return
	end
	
	--The unit was killed by the player
	if killerID == avatarID and config['killedByPlayer'] then
		announceContent = string.format('You killed %s!', victim)
		addAnnouncement('killedByPlayer')
		return
	end
	
	announceContent = string.format('%s has killed %s!', killer, victim)
	
	--A friendly unit was killed
	if isFriendly then
		if config['friendKilled'] then
			addAnnouncement('friendKilled')
			return
		end
	--An enemy was killed by a friendly
	elseif config['killedByFriend'] then
		addAnnouncement('killedByFriend')
	end	
end


function addAnnouncement (killType)
	--Create and format the announcement
	local announcement = mainForm:CreateWidgetByDesc(announceDesc)
	local form = string.format('<header color="0x%s" alignx="center" fontsize="%s" outline="1" shadow="1"><rs class="class"><r name="value"/></rs></header>', colorList[killType], tostring(config['fontSize']))
	local placement = nil
	
	announcement:SetFormat(userMods.ToWString(form))
	announcement:SetVal('value', userMods.ToWString(announceContent))
	
	table.insert(announceList, announcement)
	announceCount = table.getn(announceList)
	
	--Check where to put the announcememt
	if announceCount > 1 then
		placement = announceList[announceCount-1]:GetPlacementPlain()
		placement.posY = placement.posY - distance
	else
		placement = firstPos
	end
	
	--Show the announcement
	announcement:SetPlacementPlain(placement)
	announcement:Show(true)
	announcement:PlayFadeEffect( 0.0, .999, ANNOUNCE_FADE_IN_TIME, EA_MONOTONOUS_INCREASE)
	
	--Remove the bottom announcement
	if announceCount > config['maxAnnouncements'] then
		if not moving then
			announceList[1]:PlayFadeEffect(1.0, 0.0, ANNOUNCE_FADE_OUT_TIME, EA_MONOTONOUS_INCREASE)
		end
	end
end


function moveAnnouncements ()
	moving = true
	for n, a in announceList do
		local startPos = a:GetPlacementPlain()
		local endPos = startPos
		endPos.posY = endPos.posY + distance
		a:PlayMoveEffect( startPos, endPos, 300, EA_MONOTONOUS_INCREASE )
	end
	moving = false
end


function getColors ()
	for k,v in colorList do
		colorList[k] = toHexConc(config[k..'Color'])
	end
	
	colorList.blue = 'FF3069F0'
	colorList.red = 'FFFF401D'
	colorList.info = 'FFFFFFFF'
end


--Stuff taken from Ciuine's NCT, I'm far too lazy to rewrite all this from scratch
function toHexConc(N)
	local color = ""..toHex(N.a*255)..toHex(N.r*255)..toHex(N.g*255)..toHex(N.b*255)
	return color
end


function toHex(N) --Modified version of someone else's free source C code. CREATES HEX FROM RGBA
	if N==nil then
		return "00"
	elseif N==0 then 
		return "00"
	else
		N=math.max(0,N)
		N=math.min(N,255)
		N=math.ceil(N)
		return string.sub("0123456789ABCDEF", 1 + (N- (N - math.floor(N/16)*16))/16, 1 + (N- (N - math.floor(N/16)*16))/16)..string.sub("0123456789ABCDEF", 1 + (N - math.floor(N/16)*16), 1 + (N - math.floor(N/16)*16))
	end
end


function defaults ()
	config['killedByPlayer'] = true
	config['playerKilled'] = true
	config['killedByFriend'] = true
	config['friendKilled'] = true
	config['maxAnnouncements'] = 4
	config['fontSize'] = 18
	config['announcementDistance'] = 4
	config['visibleTime'] = 4500
	config['killedByPlayerColor'] = {r = 0.86; g = 0.82; b = 0.078; a = 1}
	config['playerKilledColor'] = {r = 0.8; g = 0.06; b = 0.06; a = 1}
	config['killedByFriendColor'] = {r = 0.86; g = 0.82; b = 0.078; a = 1}
	config['friendKilledColor'] = {r = 0.8; g = 0.06; b = 0.06; a = 1}
	
	userMods.SetGlobalConfigSection('KillAnnounce', config)
	getColors()
end


--------------------------------------------------------------------------------
-- ADDON MANAGER
--------------------------------------------------------------------------------

function SCRIPT_ADDON_INFO_REQUEST ( params )
	if params.target == common.GetAddonName() then
	userMods.SendEvent( "SCRIPT_ADDON_INFO_RESPONSE", 
	{
		sender = params.target,
		desc = "Shows a notification when you or someone near you kills a player"
	} )
	end
end

function MemRequest ( params )
    userMods.SendEvent( "U_EVENT_ADDON_MEM_USAGE_RESPONSE", { sender = common.GetAddonName(), memUsage = gcinfo() } )
end


--------------------------------------------------------------------------------
-- CONFIG WINDOW
--------------------------------------------------------------------------------

function ConfigInitEvent ()
	userMods.SendEvent("CONFIG_INIT_EVENT_RESPONSE", { sender = common.GetAddonName() })
end


function ConfigEvent ()
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 0, name = 'killedByPlayer', btnType = "T/F", state = config['killedByPlayer']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 1, name = 'playerKilled', btnType = "T/F", state = config['playerKilled']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 2, name = 'killedByFriend', btnType = "T/F", state = config['killedByFriend']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 3, name = 'friendKilled', btnType = "T/F", state = config['friendKilled']})
	
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 4, name = 'maxAnnouncements', btnType = "EditLine", value = config['maxAnnouncements']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 5, name = 'fontSize', btnType = "EditLine", value = config['fontSize']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 6, name = 'announcementDistance', btnType = "EditLine", value = config['announcementDistance']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 7, name = 'visibleTime', btnType = "EditLine", value = config['visibleTime']})
	
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 8, name = 'killedByPlayerColor', btnType = "Color", color = config['killedByPlayerColor']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 9, name = 'playerKilledColor', btnType = "Color", color = config['playerKilledColor']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 10, name = 'friendKilledColor', btnType = "Color", color = config['friendKilledColor']})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 11, name = 'killedByFriendColor', btnType = "Color", color = config['killedByFriendColor']})
	
	--userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 12, name = "DnD", btnType = "Simple"})
	userMods.SendEvent("CONFIG_EVENT_RESPONSE", {NoB = 13, name = "Defaults", btnType = "Simple"})
end


function ConfigButton (p)
	config[p.name] = p.state
	userMods.SetGlobalConfigSection('KillAnnounce', config)
end


function ConfigSimple (p)
	if  p.name == 'Defaults' then
		defaults() 
	end
	
	--TODO y u not work, DnD
	-- if p.name == 'DnD' then
		-- local form = string.format('<header color="0x%s" alignx="center" fontsize="%s" outline="1" shadow="1"><rs class="class"><r name="value"/></rs></header>', colorList["killedByPlayer"], tostring(config['fontSize']))
		-- AnnounceText:SetFormat(userMods.ToWString(form))
		-- AnnounceText:SetVal("value", userMods.ToWString("First Announcement"))
		-- AnnounceText:SetPlacementPlain(firstPos)
		-- AnnounceText:Show(not AnnounceText:IsVisible())
		
		-- -- if AnnounceText:IsVisible() then
			-- -- DnD:Enable(AnnounceText, true)
		-- -- end
	-- end
end


function ConfigColor (p)
	config[p.name] = p.color
	userMods.SetGlobalConfigSection('KillAnnounce', config)
	getColors()
end


function ConfigEditLine (p)
	config[p.name] = p.text
	userMods.SetGlobalConfigSection('KillAnnounce', config)
end

--------------------------------------------------------------------------------
-- INITIALIZATION
--------------------------------------------------------------------------------
function Init()
	--Initialize widgets
	AnnounceText = mainForm:GetChildChecked( "Announce", false )
	announceDesc = AnnounceText:GetWidgetDesc()
	AnnounceText:SetVal("value", userMods.ToWString("First Announcement"))
	AnnounceText:Show( false )
	
	config = userMods.GetGlobalConfigSection('KillAnnounce')
	
	if not config then
		config = {}
		defaults()
	end
	
	firstPos = AnnounceText:GetPlacementPlain()
	
	getColors()
	distance = config['fontSize'] + config['announcementDistance']
	
	--DnD:Init(653, AnnounceText, AnnounceText)
	
	--Check if the avatar was created
	common.RegisterEventHandler(OnAvatarCreated,"EVENT_AVATAR_CREATED")
	if avatar.IsExist() then OnAvatarCreated() end
	
	--Register AddonManager and ConfigWindow handlers
	common.RegisterEventHandler( SCRIPT_ADDON_INFO_REQUEST, "SCRIPT_ADDON_INFO_REQUEST" )
	common.RegisterEventHandler(MemRequest, "U_EVENT_ADDON_MEM_USAGE_REQUEST")
	
	common.RegisterEventHandler( ConfigInitEvent, "CONFIG_INIT_EVENT" )
	common.RegisterEventHandler( ConfigEvent, "CONFIG_EVENT_"..common.GetAddonName())
	common.RegisterEventHandler( ConfigColor, "CONFIG_COLOR_"..common.GetAddonName())
	common.RegisterEventHandler( ConfigButton, "CONFIG_BUTTON_"..common.GetAddonName())
	common.RegisterEventHandler( ConfigSimple, "CONFIG_SIMPLE_"..common.GetAddonName())
	common.RegisterEventHandler( ConfigEditLine, "CONFIG_EDIT_LINE_"..common.GetAddonName())
	
	--Register the rest of the event handlers
	common.RegisterEventHandler(onEffectFinished, "EVENT_EFFECT_FINISHED")	
end


--------------------------------------------------------------------------------
Init()
--------------------------------------------------------------------------------
