-- Addon settings
local db

-- Texture settings
local textures ={
				['Star'] = "GroupLeader/Textures/star_",
				['Plus'] = "GroupLeader/Textures/plus_",
				['Circle'] = "GroupLeader/Textures/circle_",
				}
local colors =	{
				['White'] = "w.dds",
				['Black'] = "bl.dds",
				['Red'] = "r.dds",
				['Green'] = "g.dds",
				['Blue'] = "b.dds",
				}
local textureKeys = GetTableKeys(textures)
local colorKeys = GetTableKeys(colors)
local mapPinType = "GroupLeaderMap"
local compassPinType = "GroupLeaderCompass"

-- Addon data storage
local leaderTag = nil
local leaderName = nil
local leaderX = nil
local leaderY = nil
local playerName = nil
local nameToUnitTagMap = {}
local customLeaderTag = nil
local customLeaderName = nil

-- Defaults for settings
local defaults = {
	trackingEnabled = true,
    compassEnabled = true,
    mapEnabled = true,
	leaderSymbol = 'Star',
	compassMaxDistance = 1.0,
    compassColor = 'White',
    mapColor = 'White',
}

-- Misc functions
-- Map group member names to unit tags in a table
local function MapNamesToUnitTags()
	nameToUnitTagMap = {}
	size = GetGroupSize()
    if size > 0 then
        for i=1, size, 1 do
            local unitTag = GetGroupUnitTagByIndex(i)
            if unitTag then
                local name = GetUnitName(unitTag)
                if name then
                    local lowername = string.lower(name)
                    nameToUnitTagMap[lowername]=unitTag
                end
            end
        end
    end
end

-- Tooltip creator
local pinTooltipCreator = {
	creator = function(pin)
		InformationTooltip:AddLine("Leader: " .. leaderName)
	end,
	tooltip = InformationTooltip,
}

-- Compass and map callbacks
local function MapCallback(pinManager)
	if not db or not db.trackingEnabled or not db.mapEnabled then
		return
	end
	if not leaderName or not leaderX or not leaderY then
        return
    elseif leaderName == playerName then
        return
    end
	pinManager:CreatePin(_G[mapPinType], leaderName, leaderX, leaderY)
end

local function CompassPinCallback(pinManager)
	if COMPASS.container:IsHidden() then
		return
	end
	if not db or not db.trackingEnabled or not db.compassEnabled then
		return
	end
	if not leaderName or not leaderX or not leaderY then
        return
    elseif leaderName == playerName then
        return
    end
	pinManager:CreatePin(compassPinType, leaderName, leaderX, leaderY)
end

-- Map specific functions
local function RefreshMapPins(pinType)
	ZO_WorldMap_RefreshCustomPinsOfType(_G[pinType])
end

local function AddMapPin(pinType, pinTypeAddCallback, pinTypeOnResizeCallback, pinLayoutData, pinTooltipCreator)
	ZO_WorldMap_AddCustomPin(pinType, pinTypeAddCallback, pinTypeOnResizeCallback, pinLayoutData, pinTooltipCreator)
	ZO_WorldMap_SetCustomPinEnabled(_G[pinType], true)
	RefreshMapPins(pinType)
end

-- Slash command handlers
local function SetLeader(text)
	MapNamesToUnitTags()
	if text ~= nil and string.len(text) > 0 then
		local input = string.lower(text)
		local newLeaderTag = nameToUnitTagMap[input]
		if newLeaderTag then
			customLeaderTag = newLeaderTag
			customLeaderName = input
            ChatMessage("Now tracking " .. text)
		else
            ChatMessage("Player not found in group!")
		end
	else
        ChatMessage("Clearing custom leader tracking")
		customLeaderTag = nil
	end
end

-- Event handlers
-- Called when the group is disbanded
local function Disbanded()
	leaderTag = nil
    customLeaderTag = nil
    customLeaderName = nil
    leaderX = nil
    leaderY = nil
	leaderName = nil
end

-- Called when the group leader changes
local function LeaderUpdate()
	leaderTag = GetGroupLeaderUnitTag()
end

-- Called when someone joins the group
local function MemberJoined()
    LeaderUpdate()
end

-- Called when someone leaves the group
local function MemberLeft()
    LeaderUpdate()
    if customLeaderTag then
	    MapNamesToUnitTags()
		local newLeaderTag = nameToUnitTagMap[customLeaderName]
		if newLeaderTag then
			customLeaderTag = newLeaderTag
		else
            Disbanded()
        end
    end
end

-- Called when someone in the group connects/disconnects
local function ConnectedStatus()
    LeaderUpdate()
end

-- Refresh the compass and map with the chosen texture
local function UpdateTexture()
    ZO_MapPin.PIN_DATA[_G[mapPinType]].texture = textures[db.leaderSymbol] .. colors[db.mapColor]
    RefreshMapPins(mapPinType)
    COMPASS_PINS.pinLayouts[compassPinType].texture = textures[db.leaderSymbol] .. colors[db.compassColor]
    COMPASS_PINS:RefreshPins()
end

-- Called on game UI updates
function OnGroupLeaderUpdate(time)
    local unitTag = nil
	if customLeaderTag then
        unitTag = customLeaderTag
	elseif leaderTag then
        unitTag = leaderTag
	end

    if unitTag then
        leaderX, leaderY = GetMapPlayerPosition(unitTag)
        leaderName = GetUnitName(unitTag)
    else
        leaderX = nil
        leaderY = nil
        leaderName = nil
    end

    COMPASS_PINS:RefreshPins()
    RefreshMapPins(mapPinType)
end

-- Create the settings menu
local function CreateSettings()
	local LAM = LibStub("LibAddonMenu-1.0")
	local panel = LAM:CreateControlPanel("GROUP_LEADER_SETTINGS", "Group Leader")
	LAM:AddHeader(panel, "GROUP_LEADER_SETTINGS_GENERAL", "General Settings")
	LAM:AddCheckbox(panel, "Group_Leader_Tracking_Enabled", "Enable Tracking", "If enabled, the location of the group leader (or custom target using /leader name) will be tracked",
				function() return db.trackingEnabled end,	--getFunc
				function()							--setFunc
					db.trackingEnabled = not db.trackingEnabled
				end)
	LAM:AddDropdown(panel, "Group_Leader_Symbol", "Select Tracking Symbol", "Select the symbol to use for tracking the leader",
				textureKeys,
                function() return db.leaderSymbol end,	--getFunc
				function(text)							--setFunc
					db.leaderSymbol = text
					UpdateTexture()
				end,	--setFunc
				false,
				nil)

	LAM:AddHeader(panel, "GROUP_LEADER_SETTINGS_COMPASS", "Compass Settings")
	LAM:AddCheckbox(panel, "Group_Leader_Compass_Enabled", "Enable Compass Tracking", "If enabled, the location of the group leader (or custom target using /leader name) will be tracked on the compass",
				function() return db.compassEnabled end,	--getFunc
				function()							--setFunc
					db.compassEnabled = not db.compassEnabled
				end)
	LAM:AddSlider(panel, "Group_Leader_Compass_MaxDistance", "Max Distance", "The maximum distance (in normalized map units) to show the group leader", 1, 100, 1,
		function() return db.compassMaxDistance * 100 end,
		function(maxDistance)
			db.compassMaxDistance = maxDistance / 100
			COMPASS_PINS.pinLayouts[compassPinType].maxDistance = maxDistance / 100
			COMPASS_PINS:RefreshPins()
		end)
	LAM:AddDropdown(panel, "Group_Leader_Compass_Color", "Select Tracking Color", "Select the color to use for the symbol used for tracking the leader",
				colorKeys,
                function() return db.compassColor end,	--getFunc
				function(text)							--setFunc
					db.compassColor = text
					UpdateTexture()
				end,	--setFunc
				false,
				nil)

	LAM:AddHeader(panel, "GROUP_LEADER_SETTINGS_MAP", "Map Settings")
	LAM:AddCheckbox(panel, "Group_Leader_Map_Enabled", "Enable Map Tracking", "If enabled, the location of the group leader (or custom target using /leader name) will be tracked on the map",
				function() return db.mapEnabled end,	--getFunc
				function()							--setFunc
					db.mapEnabled = not db.mapEnabled
				end)
	LAM:AddDropdown(panel, "Group_Leader_Map_Color", "Select Tracking Color", "Select the color to use for the symbol used for tracking the leader",
				colorKeys,
                function() return db.mapColor end,	--getFunc
				function(text)							--setFunc
					db.mapColor = text
					UpdateTexture()
				end,	--setFunc
				false,
				nil)
end

-- AddOn setup
local function AddonSetup(eventCode, addOnName)
	if addOnName ~= "GroupLeader" then
		return
	end

	leaderTag = nil
	leaderName = nil
	leaderX = nil
	leaderY = nil
	playerName = nil
	nameToUnitTagMap = {}
	customLeaderTag = nil
	customLeaderName = nil

	-- Populate the settings DB
	Group_LeaderDB = Group_LeaderDB or {}
	for k,v in pairs(defaults) do
	    if type(Group_LeaderDB[k]) == "nil" then
	        Group_LeaderDB[k] = v
	    end
	end
	db = Group_LeaderDB

    playerName = GetUnitName('player')
	LeaderUpdate()

	local mapPinLayout = {
		level = 200,
		texture = textures[db.leaderSymbol] .. colors[db.mapColor],
		size = 40,
	}

	local compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures[db.leaderSymbol] .. colors[db.compassColor],
	}

	AddMapPin(mapPinType, MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType, CompassPinCallback, compassPinLayout)

	SLASH_COMMANDS["/leader"] = SetLeader

    EVENT_MANAGER:RegisterForEvent("GroupLeaderDisbanded", EVENT_GROUP_DISBANDED, Disbanded)
    EVENT_MANAGER:RegisterForEvent("GroupLeaderLeaderUpdate", EVENT_LEADER_UPDATE, LeaderUpdate)
    EVENT_MANAGER:RegisterForEvent("GroupLeaderMemberJoined", EVENT_GROUP_MEMBER_JOINED, MemberJoined)
    EVENT_MANAGER:RegisterForEvent("GroupLeaderMemberLeft", EVENT_GROUP_MEMBER_LEFT, MemberLeft)
    EVENT_MANAGER:RegisterForEvent("GroupLeaderMemberConnected", EVENT_GROUP_MEMBER_CONNECTED_STATUS, ConnectedStatus)

	CreateSettings()
end

-- Register for addon loaded event
EVENT_MANAGER:RegisterForEvent("GroupLeader", EVENT_ADD_ON_LOADED, AddonSetup)