--[[
	Addon: Taos Group Tools
	Author: TProg Taonnor
	Created by @Taonnor
]]--

--[[
	Local variables
]]--
local LOG_ACTIVE = false

local SWIMLANES = 6
local ROWS = 6
local REFRESHRATE = 1000 -- ms; RegisterForUpdate is in miliseconds
local TIMEOUT = 4 -- s; GetTimeStamp() is in seconds

local _logger = nil
local _control = nil
local _isActive = false

--[[
	Table CompactSwimlaneList
]]--
TGT_CompactSwimlaneList = {}
TGT_CompactSwimlaneList.__index = TGT_CompactSwimlaneList

--[[
	Table Members
]]--
TGT_CompactSwimlaneList.Name = "TGT-CompactSwimlaneList"
TGT_CompactSwimlaneList.Swimlanes = {}

--[[
	Sets visibility of labels
]]--
function TGT_CompactSwimlaneList.RefreshList()
	--if (LOG_ACTIVE) then _logger:logTrace("TGT_CompactSwimlaneList.RefreshList") end

    -- Check all swimlanes
    for i,swimlane in ipairs(TGT_CompactSwimlaneList.Swimlanes) do
        TGT_CompactSwimlaneList.ClearPlayersFromSwimlane(swimlane)
	end
end

--[[
	Sorts swimlane
]]--
function TGT_CompactSwimlaneList.SortSwimlane(swimlane)
	if (LOG_ACTIVE) then _logger:logTrace("TGT_CompactSwimlaneList.SortSwimlane") end

    -- Comparer
    function compare(playerLeft, playerRight)
        if (playerLeft.RelativeUltimate == playerRight.RelativeUltimate) then
            return playerLeft.PingTag < playerRight.PingTag
        else
            return playerLeft.RelativeUltimate > playerRight.RelativeUltimate
        end
    end

    table.sort(swimlane.Players, compare)

    -- Sort by name

    -- Update sorted swimlane list
    for i,swimlanePlayer in ipairs(swimlane.Players) do
        TGT_CompactSwimlaneList.UpdateListRow(swimlane.SwimlaneControl:GetNamedChild("Row" .. i), swimlanePlayer)
    end
end

--[[
	Updates list row
]]--
function TGT_CompactSwimlaneList.UpdateListRow(row, player)
	if (LOG_ACTIVE) then
        --_logger:logTrace("TGT_CompactSwimlaneList.UpdateListRow")
    end

    local playerName = player.PlayerName
    local nameLength = string.len(playerName)

    if (nameLength > 6) then
        playerName = string.sub(playerName, 0, 5) .. ".."
    end

    row:GetNamedChild("SenderNameValueLabel"):SetText(playerName)
    row:GetNamedChild("RelativeUltimateStatusBar"):SetValue(player.RelativeUltimate)

	if (player.IsPlayerDead) then
        -- Dead Color
        row:GetNamedChild("SenderNameValueLabel"):SetColor(0.5, 0.5, 0.5, 0.8)
        row:GetNamedChild("RelativeUltimateStatusBar"):SetColor(0.8, 0.03, 0.03, 0.7)
    elseif (player.RelativeUltimate == 100) then
		-- Ready Color
        row:GetNamedChild("SenderNameValueLabel"):SetColor(1, 1, 1, 1)
        row:GetNamedChild("RelativeUltimateStatusBar"):SetColor(0.03, 0.7, 0.03, 0.7)
	else
		-- Inprogress Color
        row:GetNamedChild("SenderNameValueLabel"):SetColor(1, 1, 1, 0.8)
        row:GetNamedChild("RelativeUltimateStatusBar"):SetColor(0.03, 0.03, 0.7, 0.7)
	end

    row:SetHidden(false)
end

--[[
	Updates list row
]]--
function TGT_CompactSwimlaneList.UpdatePlayer(player)
	if (LOG_ACTIVE) then
        --_logger:logTrace("TGT_CompactSwimlaneList.UpdatePlayer")
    end

	if (player) then
        local swimLane = TGT_CompactSwimlaneList.GetSwimLane(player.UltimateGroup.GroupAbilityId)

        if (swimLane) then
            local row = TGT_CompactSwimlaneList.GetSwimLaneRow(swimLane, player.PlayerName)
            local updateNeeded = true

            -- Update timestamp
            if (row ~= nil) then
                for i,swimlanePlayer in ipairs(swimLane.Players) do
		            if (swimlanePlayer.PlayerName == player.PlayerName) then
                        swimlanePlayer.LastMapPingTimestamp = GetTimeStamp()

                        updateNeeded = swimlanePlayer.IsPlayerDead ~= player.IsPlayerDead or swimlanePlayer.RelativeUltimate ~= player.RelativeUltimate

                        if (swimlanePlayer.RelativeUltimate > player.RelativeUltimate) then
                            local sound = TGT_SettingsHandler.SavedVariables.Sound
                            if (sound[1] > 1) then PlaySound(SOUNDS[sound[2]]) end
						end

                        swimlanePlayer.IsPlayerDead = player.IsPlayerDead
                        swimlanePlayer.RelativeUltimate = player.RelativeUltimate
                        break
                    end
	            end
            else
                -- Add new player
                local nextFreeRow = 1

                for i,player in ipairs(swimLane.Players) do
		            nextFreeRow = nextFreeRow + 1
	            end

                if (nextFreeRow <= ROWS) then
                    if (LOG_ACTIVE) then
                        --_logger:logDebug("TGT_CompactSwimlaneList.UpdatePlayer, add player " .. tostring(player.PlayerName) .. " to row " .. tostring(nextFreeRow))
                    end

                    player.LastMapPingTimestamp = GetTimeStamp()
                    swimLane.Players[nextFreeRow] = player
                    row = swimLane.SwimlaneControl:GetNamedChild("Row" .. nextFreeRow)
                else
                    if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.UpdatePlayer, too much players for one swimlane " .. tostring(nextFreeRow)) end
                end
            end

            -- Only update if player in a row
            if (row ~= nil and updateNeeded) then
                if (TGT_SettingsHandler.SavedVariables.IsSortingActive) then
                    -- Sort swimlane with all players
                    TGT_CompactSwimlaneList.SortSwimlane(swimLane)
                else
                    -- Directly update row with player
                    TGT_CompactSwimlaneList.UpdateListRow(row, player)
                end
            end
        else
            if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.UpdatePlayer, swimlane not found for ultimategroup " .. tostring(ultimateGroup.GroupName)) end
        end
	end
end

--[[
	Get swimlane from current SwimLanes
]]--
function TGT_CompactSwimlaneList.GetSwimLane(ultimateGroupId)
    if (LOG_ACTIVE) then
        --_logger:logTrace("TGT_CompactSwimlaneList.GetSwimLane")
        --_logger:logDebug("ultimateGroupId", ultimateGroupId)
    end

    if (ultimateGroupId ~= 0) then
        for i,swimLane in ipairs(TGT_CompactSwimlaneList.Swimlanes) do
		    if (swimLane.UltimateGroupId == ultimateGroupId) then
                return swimLane
            end
	    end

        --if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.GetSwimLane, swimLane not found " .. tostring(ultimateGroupId)) end
        return nil
    else
        _logger:logError("TGT_CompactSwimlaneList.GetSwimLane, ultimateGroupId is 0")
        return nil
    end
end

--[[
	Get Player Row from current players in swimlane
]]--
function TGT_CompactSwimlaneList.GetSwimLaneRow(swimLane, playerName)
    if (LOG_ACTIVE) then
        --_logger:logTrace("TGT_CompactSwimlaneList.GetSwimLaneRow")
        --_logger:logDebug("swimLane ID", swimLane.Id)
    end

    if (swimLane) then
        for i,player in ipairs(swimLane.Players) do
            --if (LOG_ACTIVE) then _logger:logDebug(player.PlayerName .. " == " .. playerName) end
		    if (player.PlayerName == playerName) then
                return swimLane.SwimlaneControl:GetNamedChild("Row" .. i)
            end
	    end

        --if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.GetSwimLane, player not found " .. tostring(playerName)) end
        return nil
    else
        _logger:logError("TGT_CompactSwimlaneList.GetSwimLane, swimLane is nil")
        return nil
    end
end

--[[
	Clears all players in swimlane
]]--
function TGT_CompactSwimlaneList.ClearPlayersFromSwimlane(swimlane)
    if (LOG_ACTIVE) then
        --_logger:logTrace("TGT_CompactSwimlaneList.ClearPlayersFromSwimlane")
        --_logger:logDebug("swimlane ID", swimlane.Id)
    end

    if (swimlane) then
        for i=1, ROWS, 1 do
            local row = swimlane.SwimlaneControl:GetNamedChild("Row" .. i)
            local swimlanePlayer = swimlane.Players[i]

            if (swimlanePlayer ~= nil) then
                local isPlayerNotGrouped = IsUnitGrouped(swimlanePlayer.PingTag) == false
                local isPlayerTimedOut = (GetTimeStamp() - swimlanePlayer.LastMapPingTimestamp) > TIMEOUT
                local isPlayerUltimateNotCorrect = swimlane.UltimateGroupId ~= swimlanePlayer.UltimateGroup.GroupAbilityId

                if (isPlayerNotGrouped or isPlayerTimedOut or isPlayerUltimateNotCorrect) then
                    --if (LOG_ACTIVE) then _logger:logDebug("Player invalid, hide row: " .. tostring(i)) end

                    row:SetHidden(true)
                    table.remove(swimlane.Players, i)
                end
            else
                --if (LOG_ACTIVE) then _logger:logDebug("Row empty, hide: " .. tostring(i)) end

                row:SetHidden(true)
            end
        end
    end
end

--[[
	SetControlScale sets the Scale in UI elements
]]--
function TGT_CompactSwimlaneList.SetControlScale(scale)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetControlScale")
        _logger:logDebug("scale", scale)
    end

    _control:SetScale(scale)
end

--[[
	SetControlMovable sets the Movable and MouseEnabled flag in UI elements
]]--
function TGT_CompactSwimlaneList.SetControlMovable(isMovable)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetControlMovable")
        _logger:logDebug("isMovable", isMovable)
    end

    _control:GetNamedChild("MovableControl"):SetHidden(isMovable == false)

    _control:SetMovable(isMovable)
	_control:SetMouseEnabled(isMovable)
end

--[[
	RestorePosition sets TGT_CompactSwimlaneList on settings position
]]--
function TGT_CompactSwimlaneList.RestorePosition(posX, posY)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.RestorePosition")
        _logger:logDebug("posX, posY", posX, posY)
    end

	_control:ClearAnchors()
	_control:SetAnchor(TOPLEFT, GuiRoot, TOPLEFT, posX, posY)
end

--[[
	OnTGT_CompactSwimlaneListMoveStop saves current TGT_CompactSwimlaneList position to settings
]]--
function TGT_CompactSwimlaneList.OnCompactSwimlaneListMoveStop()
    if (LOG_ACTIVE) then _logger:logTrace("TGT_CompactSwimlaneList.OnCompactSwimlaneListMoveStop") end

	local left = _control:GetLeft()
	local top = _control:GetTop()

    TGT_SettingsHandler.SavedVariables.PosX = left
    TGT_SettingsHandler.SavedVariables.PosY = top

    if (LOG_ACTIVE) then
        _logger:logDebug("PosX, PosY", TGT_SettingsHandler.SavedVariables.PosX, TGT_SettingsHandler.SavedVariables.PosY)
    end
end

--[[
	SetControlHidden sets hidden on control
]]--
function TGT_CompactSwimlaneList.SetControlHidden()
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetControlHidden")
    end

    -- Get isActive from settings
    local isActive = TGT_SettingsHandler.IsCompactSwimlaneListVisible()
    if (LOG_ACTIVE) then _logger:logDebug("isActive", isActive) end

    if (isActive) then
        if (GetIsUnitGrouped() and GetGroupSize() >= TGT_SettingsHandler.SavedVariables.VisibleOffset) then
            _control:SetHidden(CurrentHudHiddenState())
        else
            _control:SetHidden(true)
        end
    else
        _control:SetHidden(true)
    end
end

--[[
	SetSwimlanesVisible sets swimlanes visibility on base of settings
]]--
function TGT_CompactSwimlaneList.SetSwimlanesVisible(visibleSwimlanes)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetSwimlanesVisible")
        _logger:logDebug("visibleSwimlanes", visibleSwimlanes)
    end

    for i=1, SWIMLANES, 1 do
        if (i > visibleSwimlanes) then
            TGT_CompactSwimlaneList.Swimlanes[i].SwimlaneControl:SetHidden(true)
        else
            TGT_CompactSwimlaneList.Swimlanes[i].SwimlaneControl:SetHidden(false)
        end
    end
end

--[[
	SetControlActive sets hidden on control
]]--
function TGT_CompactSwimlaneList.SetControlActive()
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetControlActive")
    end

    TGT_CompactSwimlaneList.SetControlHidden()

    -- Get isActive from settings
    local isActive = TGT_SettingsHandler.IsCompactSwimlaneListVisible()
    if (LOG_ACTIVE) then _logger:logDebug("isActive", isActive) end

    if (_isActive ~= isActive) then
        _isActive = isActive

        if (isActive) then
            if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.SetControlActive RegisterCallbacks") end

            TGT_CompactSwimlaneList.SetControlMovable(TGT_SettingsHandler.SavedVariables.Movable)
            TGT_CompactSwimlaneList.RestorePosition(TGT_SettingsHandler.SavedVariables.PosX, TGT_SettingsHandler.SavedVariables.PosY)
            TGT_CompactSwimlaneList.SetSwimlanesVisible(TGT_SettingsHandler.SavedVariables.Swimlanes)
            TGT_CompactSwimlaneList.SetControlScale(TGT_SettingsHandler.SavedVariables.SwimlaneScaling)

            -- Start timeout timer
	        EVENT_MANAGER:RegisterForUpdate(TGT_CompactSwimlaneList.Name, REFRESHRATE, TGT_CompactSwimlaneList.RefreshList)

            CALLBACK_MANAGER:RegisterCallback(TAO_GROUP_CHANGED, TGT_CompactSwimlaneList.RefreshList)
            CALLBACK_MANAGER:RegisterCallback(TGT_PLAYER_DATA_CHANGED, TGT_CompactSwimlaneList.UpdatePlayer)
            CALLBACK_MANAGER:RegisterCallback(TGT_MOVABLE_CHANGED, TGT_CompactSwimlaneList.SetControlMovable)
            CALLBACK_MANAGER:RegisterCallback(TGT_SWIMLANE_ULTIMATE_GROUP_ID_CHANGED, TGT_CompactSwimlaneList.SetSwimlaneUltimate)
            CALLBACK_MANAGER:RegisterCallback(TAO_HUD_HIDDEN_STATE_CHANGED, TGT_CompactSwimlaneList.SetControlHidden)
            CALLBACK_MANAGER:RegisterCallback(TGT_VISIBLE_OFFSET_CHANGED, TGT_CompactSwimlaneList.SetControlHidden)
            CALLBACK_MANAGER:RegisterCallback(TGT_SWIMLANES_CHANGED, TGT_CompactSwimlaneList.SetSwimlanesVisible)
            CALLBACK_MANAGER:RegisterCallback(TGT_SWIMLANE_SCALING_CHANGED, TGT_CompactSwimlaneList.SetControlScale)
        else
            if (LOG_ACTIVE) then _logger:logDebug("TGT_CompactSwimlaneList.SetControlActive UnregisterCallbacks") end

            -- Start timeout timer
	        EVENT_MANAGER:UnregisterForUpdate(TGT_CompactSwimlaneList.Name)

            CALLBACK_MANAGER:UnregisterCallback(TAO_GROUP_CHANGED, TGT_CompactSwimlaneList.RefreshList)
            CALLBACK_MANAGER:UnregisterCallback(TGT_PLAYER_DATA_CHANGED, TGT_CompactSwimlaneList.UpdatePlayer)
            CALLBACK_MANAGER:UnregisterCallback(TGT_MOVABLE_CHANGED, TGT_CompactSwimlaneList.SetControlMovable)
            CALLBACK_MANAGER:UnregisterCallback(TGT_SWIMLANE_ULTIMATE_GROUP_ID_CHANGED, TGT_CompactSwimlaneList.SetSwimlaneUltimate)
            CALLBACK_MANAGER:UnregisterCallback(TAO_HUD_HIDDEN_STATE_CHANGED, TGT_CompactSwimlaneList.SetControlHidden)
            CALLBACK_MANAGER:UnregisterCallback(TGT_VISIBLE_OFFSET_CHANGED, TGT_CompactSwimlaneList.SetControlHidden)
            CALLBACK_MANAGER:UnregisterCallback(TGT_SWIMLANES_CHANGED, TGT_CompactSwimlaneList.SetSwimlanesVisible)
            CALLBACK_MANAGER:UnregisterCallback(TGT_SWIMLANE_SCALING_CHANGED, TGT_CompactSwimlaneList.SetControlScale)
        end
    else
        if (LOG_ACTIVE) then _logger:logDebug("_isActive == isActive; State not changed, do not update") end
    end
end

--[[
	OnSwimlaneHeaderClicked called on header clicked
]]--
function TGT_CompactSwimlaneList.OnSwimlaneHeaderClicked(button, swimlaneId)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.OnSwimlaneHeaderClicked")
        _logger:logDebug("swimlaneId", swimlaneId)
    end

    if (button ~= nil) then
        CALLBACK_MANAGER:RegisterCallback(TGT_SET_ULTIMATE_GROUP, TGT_CompactSwimlaneList.OnSetUltimateGroup)
        CALLBACK_MANAGER:FireCallbacks(TGT_SHOW_ULTIMATE_GROUP_MENU, button, swimlaneId)
    else
        _logger:logError("TGT_CompactSwimlaneList.OnSwimlaneHeaderClicked, button nil")
    end
end

--[[
	OnSetUltimateGroup called on header clicked
]]--
function TGT_CompactSwimlaneList.OnSetUltimateGroup(group, swimlaneId)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.OnSetUltimateGroup")
        _logger:logDebug("group.GroupName, swimlaneId", group.GroupName, swimlaneId)
    end

    CALLBACK_MANAGER:UnregisterCallback(TGT_SET_ULTIMATE_GROUP, TGT_CompactSwimlaneList.OnSetUltimateGroup)

    if (group ~= nil and swimlaneId ~= nil and swimlaneId >= 1 and swimlaneId <= 6) then
        TGT_SettingsHandler.SetSwimlaneUltimateGroupIdSettings(swimlaneId, group)
    else
        _logger:logError("TGT_UltimateGroupMenu.ShowUltimateGroupMenu, group nil or swimlaneId invalid")
    end
end

--[[
	SetSwimlaneUltimate sets the swimlane header icon in base of ultimateGroupId
]]--
function TGT_CompactSwimlaneList.SetSwimlaneUltimate(swimlaneId, ultimateGroup)
    if (LOG_ACTIVE) then
        _logger:logTrace("TGT_CompactSwimlaneList.SetSwimlaneUltimate")
        _logger:logDebug("ultimateGroup.GroupName, swimlaneId", ultimateGroup.GroupName, swimlaneId)
    end

    local swimlaneObject = TGT_CompactSwimlaneList.Swimlanes[swimlaneId]
    local iconControl = swimlaneObject.SwimlaneControl:GetNamedChild("Header"):GetNamedChild("SelectorButtonControl"):GetNamedChild("Icon")

    if (ultimateGroup ~= nil and iconControl ~= nil) then
        iconControl:SetTexture(GetAbilityIcon(ultimateGroup.GroupAbilityId))

        swimlaneObject.UltimateGroupId = ultimateGroup.GroupAbilityId
        TGT_CompactSwimlaneList.ClearPlayersFromSwimlane(swimlaneObject)
    else
        _logger:logError("TGT_CompactSwimlaneList.SetSwimlaneUltimateIcon, icon is " .. tostring(icon) .. ";" .. tostring(iconControl) .. ";" .. tostring(ultimateGroup))
    end
end

--[[
	CreateCompactSwimlaneListHeaders creates swimlane list headers
]]--
function TGT_CompactSwimlaneList.CreateCompactSwimlaneListHeaders()
    if (LOG_ACTIVE) then _logger:logTrace("TGT_CompactSwimlaneList.CreateCompactSwimlaneListHeaders") end

	for i=1, SWIMLANES, 1 do
        local ultimateGroupId = TGT_SettingsHandler.SavedVariables.SwimlaneUltimateGroupIds[i]
        local ultimateGroup = TGT_UltimateGroupHandler.GetUltimateGroupByAbilityId(ultimateGroupId)

        local swimlaneControlName = "Swimlane" .. tostring(i)
        local swimlaneControl = _control:GetNamedChild(swimlaneControlName)

        -- Add button
        local button = swimlaneControl:GetNamedChild("Header"):GetNamedChild("SelectorButtonControl"):GetNamedChild("Button")
        button:SetHandler("OnClicked", function() TGT_CompactSwimlaneList.OnSwimlaneHeaderClicked(button, i) end)

        local swimLane = {}
        swimLane.Id = i
        swimLane.SwimlaneControl = swimlaneControl
        swimLane.Players = {}

        if (ultimateGroup ~= nil) then
            if (LOG_ACTIVE) then
                _logger:logDebug("Create Swimlane", i)
                _logger:logDebug("ultimateGroup.GroupName", ultimateGroup.GroupName)
                _logger:logDebug("swimlaneControlName", swimlaneControlName)
            end

            local icon = swimlaneControl:GetNamedChild("Header"):GetNamedChild("SelectorButtonControl"):GetNamedChild("Icon")
            icon:SetTexture(GetAbilityIcon(ultimateGroup.GroupAbilityId))

            swimLane.UltimateGroupId = ultimateGroup.GroupAbilityId
        else
            _logger:logError("TGT_CompactSwimlaneList.CreateCompactSwimlaneListHeaders, ultimateGroup nil.")
        end

        TGT_CompactSwimlaneList.CreateCompactSwimlaneListRows(swimlaneControl)
	    TGT_CompactSwimlaneList.Swimlanes[i] = swimLane
	end
end

--[[
	CreateCompactSwimlaneListRows creates swimlane lsit rows
]]--
function TGT_CompactSwimlaneList.CreateCompactSwimlaneListRows(swimlaneControl)
    if (LOG_ACTIVE) then _logger:logTrace("TGT_CompactSwimlaneList.CreateCompactSwimlaneListRows") end

    if (swimlaneControl ~= nil) then
	    for i=1, ROWS, 1 do
		    local row = CreateControlFromVirtual("$(parent)Row", swimlaneControl, "CompactGroupUltimateSwimlaneRow", i)
            if (LOG_ACTIVE) then _logger:logDebug("Row created " .. row:GetName()) end

		    row:SetHidden(true) -- initial not visible

		    if (i == 1) then
                row:SetAnchor(TOPLEFT, swimlaneControl, BOTTOMLEFT, 0, 1)
            else
				row:SetAnchor(TOPLEFT, lastRow, BOTTOMLEFT, 0, 1)
			end

		    lastRow = row
	    end
    else
        _logger:logError("TGT_CompactSwimlaneList.CreateCompactSwimlaneListRows, swimlaneControl nil.")
    end
end

--[[
	Initialize initializes TGT_CompactSwimlaneList
]]--
function TGT_CompactSwimlaneList.Initialize(logger)
    if (LOG_ACTIVE) then
        logger:logTrace("TGT_CompactSwimlaneList.Initialize")
    end

    _logger = logger
    _control = TGT_CompactSwimlaneListControl

    TGT_CompactSwimlaneList.CreateCompactSwimlaneListHeaders()
    TGT_CompactSwimlaneList.SetControlActive()

    CALLBACK_MANAGER:RegisterCallback(TGT_STYLE_CHANGED, TGT_CompactSwimlaneList.SetControlActive)
    CALLBACK_MANAGER:RegisterCallback(TGT_IS_ZONE_CHANGED, TGT_CompactSwimlaneList.SetControlActive)
    CALLBACK_MANAGER:RegisterCallback(TAO_UNIT_GROUPED_CHANGED, TGT_CompactSwimlaneList.SetControlActive)
end