-- 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"

-- Defaults for settings
local defaults = {
    compassEnabled = true,
    mapEnabled = true,
	leaderEnabled = true,
	leaderSymbol = 'Star',
    leaderColor = 'White',
	compassMaxDistance = 1.0,
}

-- Addon data storage
local nameToUnitTagMap = {}
local playerName = nil
local trackers =	{
					['leader'] = {tag=nil, name=nil, symbol='Circle', color='Red', X=0, Y=0},
					}

-- 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)
		--TODO
		InformationTooltip:AddLine("Tracker")
	end,
	tooltip = InformationTooltip,
}

-- Compass and map callbacks
local function MapCallback(pinManager)
	if not db or not db.mapEnabled then
		return
	end
	for k, v in pairs(trackers) do
		if v.tag and v.name and v.symbol and v.color and not (v.X == 0 and v.Y == 0) then
			if k == 'leader' and db.leaderEnabled and v.name ~= playerName then
				pinManager:CreatePin(_G[mapPinType .. v.symbol .. v.color], v.name, v.X, v.Y)
			else
				pinManager:CreatePin(_G[mapPinType .. v.symbol .. v.color], v.name, v.X, v.Y)
			end
		end
	end
end

local function CompassPinCallback(pinManager)
	if COMPASS.container:IsHidden() then
		return
	end
	if not db or not db.compassEnabled then
		return
	end
	for k, v in pairs(trackers) do
		if v.tag and v.name and v.symbol and v.color and not (v.X == 0 and v.Y == 0) then
			if k == 'leader' and db.leaderEnabled and v.name ~= playerName then
				pinManager:CreatePin(compassPinType .. v.symbol .. v.color, v.name, v.X, v.Y)
			else
				pinManager:CreatePin(compassPinType .. v.symbol .. v.color, v.name, v.X, v.Y)
			end
		end
	end
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 CommandHandler(text)
	-- Display help
	if text == nil or string.len(text) <= 0 or string.lower(text) == "help" then
		ChatMessage("GroupLeader Help:")
		ChatMessage("/gl : display help.")
		ChatMessage("    aliases: /groupleader, /gl help")
		ChatMessage("/gl leader : toggle leader tracking")
		ChatMessage("/gl map : toggle map tracking")
		ChatMessage("/gl compass : toggle compass tracking")
		ChatMessage("/gl add [name] -symbol -color : add a custom tracker")
		ChatMessage("    -symbol and -color are optional")
		ChatMessage("    e.g., /gl add adein -circle -red")
		ChatMessage("/gl del [name] : delete a custom tracker")
		ChatMessage("/gl clear : clear all custom trackers")
	elseif text ~= nil and string.len(text) > 0 then
		MapNamesToUnitTags()
		local input = string.lower(text)
		local params = SplitString(input)
		local paramCount = table.getn(params)
		if params[1] == "leader" then
			db.leaderEnabled = not db.leaderEnabled
			local status = nil
			if db.leaderEnabled then
				status = "enabled"
			else
				status = "disabled"
			end
			ChatMessage("Tracking group leader " .. status)
		elseif params[1] == "map" then
			db.mapEnabled = not db.mapEnabled
			local status = nil
			if db.mapEnabled then
				status = "enabled"
			else
				status = "disabled"
			end
			ChatMessage("Map tracking " .. status)
		elseif params[1] == "compass" then
			db.compassEnabled = not db.compassEnabled
			local status = nil
			if db.compassEnabled then
				status = "enabled"
			else
				status = "disabled"
			end
			ChatMessage("Compass tracking " .. status)
		elseif params[1] == "add" then
			local name = nil
			local symbol = 'Circle'
			local color = 'Red'
			for paramCounter = 2, paramCount, 1 do
				param = params[paramCounter]
				if string.sub(param, 1, string.len("-"))=="-" then
					local paramNoDash = string.sub(param, 2, -1)
					if not symbol then
						for tex in textureKeys do
							if paramNoDash == tex then
								symbol = tex
								break
							end
						end
					end
					if not color then
						for col in colorKeys do
							if paramNoDash == col then
								color = col
								break
							end
						end
					end
				else
					if not name then
						name = param
					else
						name = name .. " " .. param
					end
				end
			end
			local unitTag = nameToUnitTagMap[name]
			if unitTag then
				for k, v in pairs(trackers) do
					if v.tag == unitTag then
						ChatMessage("Already tracking that player!")
						return
					end
				end
				table.insert(trackers, {tag=unitTag, name=name, symbol=symbol, color=color, X=0, Y=0})
	            ChatMessage("Now tracking " .. name)
			else
	            ChatMessage("Player not found in group!")
			end
		elseif params[1] == "del" then
			local name = nil
			for paramCounter = 2, paramCounter, 1 do
				param = params[paramCounter]
				if not name then
					name = param
				else
					name = name .. " " .. param
				end
			end
			deleted = false
			for k, v in pairs(trackers) do
				if v.name == name then
					table.remove(trackers, k)
					deleted = true
				end
			end
			if deleted then
				ChatMessage("Deleted " .. name .. " from tracking list")
			else
				ChatMessage("Player not found in tracking list!")
			end
		elseif params[1] == "clear" then
			ChatMessage("Clearing custom trackers")
			local trackerCount = table.getn(trackers) - 1
			for trackerCounter = 1, trackerCount, 1 do
				table.remove(trackerCounter)
			end
		else
			ChatMessage("Unknown GroupLeader command!")
		end
	end
end

-- Event handlers
-- Called when the group is disbanded
local function Disbanded()
	trackers =	{
				['leader'] = {tag=nil, name=nil, symbol=nil, color=nil, X=0, Y=0},
				}
end

-- Called when the group leader changes
local function LeaderUpdate()
	trackers['leader'].tag = GetGroupLeaderUnitTag()
end

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

-- Called when someone leaves the group
local function MemberLeft()
    LeaderUpdate()
    MapNamesToUnitTags()
    for k, v in pairs(trackers) do
    	local newUnitTag = nameToUnitTagMap[v.name]
		if newUnitTag then
			trackers[k].tag = newUnitTag
		else
            table.remove(trackers, k)
        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 RefreshAllPins()
    RefreshMapPins(mapPinType .. 'StarWhite')
    RefreshMapPins(mapPinType .. 'StarBlack')
    RefreshMapPins(mapPinType .. 'StarRed')
    RefreshMapPins(mapPinType .. 'StarGreen')
    RefreshMapPins(mapPinType .. 'StarBlue')
    RefreshMapPins(mapPinType .. 'PlusWhite')
    RefreshMapPins(mapPinType .. 'PlusBlack')
    RefreshMapPins(mapPinType .. 'PlusRed')
    RefreshMapPins(mapPinType .. 'PlusGreen')
    RefreshMapPins(mapPinType .. 'PlusBlue')
    RefreshMapPins(mapPinType .. 'CircleWhite')
    RefreshMapPins(mapPinType .. 'CircleBlack')
    RefreshMapPins(mapPinType .. 'CircleRed')
    RefreshMapPins(mapPinType .. 'CircleGreen')
    RefreshMapPins(mapPinType .. 'CircleBlue')
    COMPASS_PINS:RefreshPins()
end

-- Called on game UI updates
function OnGroupLeaderUpdate(time)
	for k, v in pairs(trackers) do
		if v.tag then
			v.X, v.Y = GetMapPlayerPosition(v.tag)
			v.name = GetUnitName(v.tag)
	    else
	        v.X = nil
	        v.Y = nil
	        v.name = nil
		end
	end

    RefreshAllPins()
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_Map_Enabled", "Enable Map Tracking", "If enabled, the location of the group leader (or custom targets) will be tracked on the map",
				function() return db.mapEnabled end,	--getFunc
				function()							--setFunc
					db.mapEnabled = not db.mapEnabled
				end)
	LAM:AddCheckbox(panel, "Group_Leader_Compass_Enabled", "Enable Compass Tracking", "If enabled, the location of the group leader (or custom targets) 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 tracked players", 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:AddHeader(panel, "GROUP_LEADER_SETTINGS_LEADER", "Leader Settings")
	LAM:AddCheckbox(panel, "Group_Leader_Tracking_Enabled", "Enable Tracking", "If enabled, the location of the group leader will be tracked",
				function() return db.leaderEnabled end,	--getFunc
				function()							--setFunc
					db.leaderEnabled = not db.leaderEnabled
				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
					RefreshAllPins()
				end,	--setFunc
				false,
				nil)
	LAM:AddDropdown(panel, "Group_Leader_Color", "Select Tracking Color", "Select the color to use for the symbol used for tracking the leader",
				colorKeys,
                function() return db.leaderColor end,	--getFunc
				function(text)							--setFunc
					db.leaderColor = text
					RefreshAllPins()
				end,	--setFunc
				false,
				nil)
end

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

	nameToUnitTagMap = {}
	playerName = nil
	trackers =	{
				['leader'] = {tag=nil, name=nil, symbol='Circle', color='Red', X=0, Y=0},
				}

	-- 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()

	trackers['leader'].symbol = db.leaderSymbol
	trackers['leader'].color = db.leaderColor

	local mapPinLayout = nil
	local compassPinLayout = nil

	mapPinLayout = {
		level = 200,
		texture = textures['Star'] .. colors['White'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Star'] .. colors['White'],
	}
	AddMapPin(mapPinType .. 'StarWhite', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'StarWhite', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Star'] .. colors['Black'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Star'] .. colors['Black'],
	}
	AddMapPin(mapPinType .. 'StarBlack', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'StarBlack', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Star'] .. colors['Red'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Star'] .. colors['Red'],
	}
	AddMapPin(mapPinType .. 'StarRed', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'StarRed', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Star'] .. colors['Green'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Star'] .. colors['Green'],
	}
	AddMapPin(mapPinType .. 'StarGreen', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'StarGreen', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Star'] .. colors['Blue'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Star'] .. colors['Blue'],
	}
	AddMapPin(mapPinType .. 'StarBlue', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'StarBlue', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Plus'] .. colors['White'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Plus'] .. colors['White'],
	}
	AddMapPin(mapPinType .. 'PlusWhite', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'PlusWhite', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Plus'] .. colors['Black'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Plus'] .. colors['Black'],
	}
	AddMapPin(mapPinType .. 'PlusBlack', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'PlusBlack', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Plus'] .. colors['Red'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Plus'] .. colors['Red'],
	}
	AddMapPin(mapPinType .. 'PlusRed', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'PlusRed', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Plus'] .. colors['Green'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Plus'] .. colors['Green'],
	}
	AddMapPin(mapPinType .. 'PlusGreen', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'PlusGreen', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Plus'] .. colors['Blue'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Plus'] .. colors['Blue'],
	}
	AddMapPin(mapPinType .. 'PlusBlue', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'PlusBlue', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Circle'] .. colors['White'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Circle'] .. colors['White'],
	}
	AddMapPin(mapPinType .. 'CircleWhite', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'CircleWhite', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Circle'] .. colors['Black'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Circle'] .. colors['Black'],
	}
	AddMapPin(mapPinType .. 'CircleBlack', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'CircleBlack', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Circle'] .. colors['Red'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Circle'] .. colors['Red'],
	}
	AddMapPin(mapPinType .. 'CircleRed', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'CircleRed', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Circle'] .. colors['Green'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Circle'] .. colors['Green'],
	}
	AddMapPin(mapPinType .. 'CircleGreen', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'CircleGreen', CompassPinCallback, compassPinLayout)

	mapPinLayout = {
		level = 200,
		texture = textures['Circle'] .. colors['Blue'],
		size = 40,
	}
	compassPinLayout = {
		maxDistance = db.compassMaxDistance,
		texture =  textures['Circle'] .. colors['Blue'],
	}
	AddMapPin(mapPinType .. 'CircleBlue', MapCallback, nil, mapPinLayout, pinTooltipCreator)
	COMPASS_PINS:AddCustomPin(compassPinType .. 'CircleBlue', CompassPinCallback, compassPinLayout)

	SLASH_COMMANDS["/groupleader"] = CommandHandler
	SLASH_COMMANDS["/gl"] = CommandHandler

    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)