--[[
Filename: GuildCharNames.lue
Author: Sasky
Version: 1.0.0

Released under GPLv2. See libraries for their individual licenses
]]--
local LC = LibStub('libChat-1.0')

GuildCharInfo = {}

--[[ GuildCharInfo:init()
	@post change events registered
	@post lookup table initialized
]]--
GuildCharInfo.init = function()
	local emptyDefault = {}
    GuildCharInfo.lut = ZO_SavedVars:NewAccountWide('GuildCharacterInfo', 0.9, "cache", emptyDefault)
    GuildCharInfo.createLUT()
    GuildCharInfo.player = GetDisplayName()
	-- register for guild events
	EVENT_MANAGER:RegisterForEvent("GuildMemberLeveled", EVENT_GUILD_MEMBER_CHARACTER_LEVEL_CHANGED, GuildCharInfo.guildUpdateEvent)
	EVENT_MANAGER:RegisterForEvent("GuildMemberLoginout", EVENT_GUILD_MEMBER_PLAYER_STATUS_CHANGED, GuildCharInfo.guildUpdateEvent)
	EVENT_MANAGER:RegisterForEvent("GuildMemberAdded", EVENT_GUILD_MEMBER_ADDED, GuildCharInfo.guildUpdateEvent)
	EVENT_MANAGER:UnregisterForEvent("GuildCharacterInfo", EVENT_PLAYER_ACTIVATED, GuildCharInfo.init)
    LINK_HANDLER:RegisterCallback(LINK_HANDLER.LINK_CLICKED_EVENT, GuildCharInfo.linkHandler)

    LC:registerName(GuildCharInfo.getFormattedNameLink)

    --UI init: create close button
    --From AI research grid
    GuildCharInfo.uiClose = WINDOW_MANAGER:CreateControl("GCINameBoxCloseButton", GCINameBox, CT_BUTTON)
    GuildCharInfo.uiClose:SetDimensions(15, 15)
    GuildCharInfo.uiClose:SetAnchor(TOPRIGHT, GCINameBox, TOPRIGHT, 0 , 0)
    GuildCharInfo.uiClose:SetState(BSTATE_NORMAL)
    GuildCharInfo.uiClose:SetMouseOverBlendMode(0)
    GuildCharInfo.uiClose:SetEnabled(true)
    GuildCharInfo.uiClose:SetNormalTexture("/esoui/art/buttons/clearslot_down.dds")
    GuildCharInfo.uiClose:SetMouseOverTexture("/esoui/art/buttons/clearslot_up.dds")
    GuildCharInfo.uiClose:SetHandler("OnClicked", function(_) GCINameBox:SetHidden(true) end)
end

--[[ GuildCharInfo:createLUT()
	@post lookup table initialized
]]--
GuildCharInfo.createLUT = function()
	local g, guild, acctName, hasChar, charName, lvl, vr, _
	for g=1,GetNumGuilds() do
		guild = GetGuildId(g)
		for i=1,GetNumGuildMembers(guild) do
			acctName = GetGuildMemberInfo(guild,i)
			hasChar, charName, _, _, _, lvl, vr = GetGuildMemberCharacterInfo(guild,i)
			if hasChar then
				GuildCharInfo.PutToLUT(acctName, charName, lvl, vr, guild, i)
			end
		end
	end
end

--[[GuildCharInfo:PutToLUT(acctName, charName, charLevel, charVR)
	@param acctName - name of player account (@foo)
	@param charName - name of current character. String stripping optional
	@param charLevel - level of current character
	@param charVR - veteran rank of current character

	@post Character added to LUT. If account already exists and charLevel > level in LUT,
		will replace main character
]]--
GuildCharInfo.PutToLUT = function(acctName, charName, charLevel, charVR, guild, index)
	if charLevel == nil then charLevel = 0 end
	if charVR == nil then charVR = 0 end

	charName = charName:gsub("%^.+", "")

	--Init if first time with this character
	if GuildCharInfo.lut[acctName] == nil then
		GuildCharInfo.lut[acctName] = {}
		GuildCharInfo.lut[acctName].level = 0 -- forces main update
	end
	--Always update charName and index
	GuildCharInfo.lut[acctName].name = charName
    GuildCharInfo.lut[acctName].guild = guild
    GuildCharInfo.lut[acctName].index = index
	--Update main if on higher level char
	if GuildCharInfo.lut[acctName].level < (charLevel + charVR) then
		GuildCharInfo.lut[acctName].main = charName
		GuildCharInfo.lut[acctName].level = charLevel + charVR
	end

	--d(acctName ..",".. charName ..",".. charLevel ..",".. charVR)
end

--[[GuildCharInfo:guildUpdateEvent(eventCode, guildId, acctName)
	@param eventCode - not used (but needed for callback signature)
	@param guildId - guild for the event
	@param acctName - account name that was updated
	Loops through the guild (guildId) until finds acctName. Updates that entry and exits
	@post LUT entry for <acctName> updated
]]--
GuildCharInfo.guildUpdateEvent = function(_, guildId, acctName)
	--Do a full rescan if relevant to current player
	if GuildCharInfo.player == acctName then
		GuildCharInfo.createLUT()
		return
	end

	local aName, _
	--d(eventCode .. "," .. guildId .. "," .. acctName)
	for i=1,GetNumGuildMembers(guildId) do
		aName = GetGuildMemberInfo(guildId,i)
		if aName == acctName then
			local hasChar, charName, _, _, _, lvl, vr = GetGuildMemberCharacterInfo(guildId,i)
			if hasChar then
				--d("Found update: " .. acctName .. ", " .. charName .. ", " .. lvl .. "+" .. vr)
				GuildCharInfo.PutToLUT(acctName, charName, lvl, vr, guildId, i)
			end
			return
		end
	end
	d("No update found for " .. acctName)
end
--[[ GuildCharInfo:getCharName(acctName)
	@return current character name for acctName
	If no entry, will passthrough acctName unaltered
]]--
GuildCharInfo.getCharName = function(acctName)
	if GuildCharInfo.lut[acctName] ~= nil and GuildCharInfo.lut[acctName].name ~= nil then
		return GuildCharInfo.lut[acctName].name
	end
	return acctName
end

--[[ GuildCharInfo:getCharName(acctName)
	@return main character name for acctName
	If no entry, will passthrough acctName unaltered
]]--
GuildCharInfo.getMainCharName = function(acctName)
	if GuildCharInfo.lut[acctName] ~= nil and GuildCharInfo.lut[acctName].main ~= nil then
		return GuildCharInfo.lut[acctName].main
	end
	return acctName
end

--[[
	@param acctName - account name or text
	@param info - info object from receiveMessage
	@param includeMain - (boolean) whether to show main character name.
		Will not show if current matches main. Default: true
	@param includeAcct - (boolean) whether to show the account name.
		Will not show if name is not in lookup table. Default: false
	@return name link of format [CurrentCharacter] (Main character) @account
]]--

GuildCharInfo.generateLink = function(acctName)
	local data = acctName
	data = data .. "," .. GuildCharInfo.lut[acctName].guild
    data = data .. "," .. GuildCharInfo.lut[acctName].index
    local link = "|HEEEEEE:playerDetail:" .. data .. "|h[*]|h"
    return link
end

--[[
    Function for libChat hook
    @param channel - chat channel code
    @param acctName - sender of chat message
    @return formatted name link [Character] (Main) [*]
 ]]
GuildCharInfo.getFormattedNameLink = function(channel, acctName, _)
    local ChanInfoArray = ZO_ChatSystem_GetChannelInfo()
    local info = ChanInfoArray[channel]

    local includeMain, includeAcct = true, false

	--Short-circuit if not in LUT
	if GuildCharInfo.lut[acctName] == nil then
		if info.playerLinkable then
			return ZO_LinkHandler_CreatePlayerLink(acctName:gsub("%^.*x$",""))
		else
			return acctName
		end
	end

	--Parameter defaults
	if includeMain == nil then includeMain = true end
	if includeAcct == nil then includeAcct = false end

	local name, main = GuildCharInfo.lut[acctName].name, GuildCharInfo.lut[acctName].main

	if main == name then includeMain = false end

	if info.playerLinkable and acctName ~= GuildCharInfo.player then
		name = ZO_LinkHandler_CreatePlayerLink(name)
	end

	if includeMain then
		name = name .. " (" .. main .. ")"
	end

	if includeAcct then
		name = name .. " " .. acctName
	end

	--Add info tag link
	name = name .. " " .. GuildCharInfo.generateLink(acctName)

	return name
end

--Utility function to kill NIL values
local function nn(val)
	if val == nil then return "" end
	return val
end

GuildCharInfo.classLookup = {}
GuildCharInfo.classLookup[1] = "dragonknight"
GuildCharInfo.classLookup[2] = "sorcerer"
GuildCharInfo.classLookup[3] = "nightblade"
GuildCharInfo.classLookup[6] = "templar"

--[[
    Handler function for more info on links (the [*] next to char names)
    @param linkType - string for what type of link was clicked.
        we handle playerDetail only
    @param varargs - string concatenation of args.
        Format: accountName,guildID,guildIndex
    @post shows UI box with player info
 ]]
GuildCharInfo.linkHandler = function(_, _, _, _, linkType, varargs)
	if linkType ~= "playerDetail" then return false end

    local acct, guild, index = SplitString(",", varargs)
    local _, name, zone, class, _, level, vr = GetGuildMemberCharacterInfo(guild, index)
    --local main = GuildCharInfo.lut[acct].main

	level = tonumber(level)
	if level >= 50 then
		level = "VR " .. vr
	end
    GCINameBoxName:SetText(nn(name):gsub("%^.*x$",""))
    GCINameBoxLevel:SetText(nn(level))
    GCINameBoxClassIcon:SetTexture( "/esoui/art/contacts/social_classicon_" .. nn(GuildCharInfo.classLookup[class]) .. ".dds" )
	GCINameBoxZone:SetText(nn(zone))
    GCINameBoxAccount:SetText(nn(acct))
    --GCINameBoxMain:SetText(nn("(" .. main .. ")"))

    --Resize box
    local line1 = GCINameBoxName:GetStringWidth(name) + 25 + 20
    --local line2 = GCINameBoxLevel:GetWidth() + GCINameBoxAccount:GetWidth() + 10
    --local line3 = GCINameBoxZone:GetWidth()
    local lineWidth = line1
    GCINameBox:SetWidth(lineWidth)

    GCINameBox:SetHidden(false)
	return true
end

EVENT_MANAGER:RegisterForEvent("GuildCharacterInfo", EVENT_PLAYER_ACTIVATED, GuildCharInfo.init)