-- [[ A framework to track GMCP module usage ]] --

module("gmod",package.seeall)

local registeredUsers = registeredUsers or {}
local registeredModules = registeredModules or {}

-- Central text output function for the module.
function print(text)
    cecho(string.format("\n<yellow>[GMCP Tracker] <white>%s\n",text))
end

-- Register a user to the system.
function registerUser(user)
    if registeredUsers[user] then return "user exists"
    else registeredUsers[user] = true
    end

    return "user registered"
end

-- Add a user to a module
local function addUser(user,module)
    registeredModules[module][user] = true

    return "user added"
end

-- Drop a user from a module
local function dropUser(user,module)
    if not registeredModules[module] then return "no registered module" end
    if not registeredModules[module][user] then return "user not linked" end
    registeredModules[module][user] = nil

    return "user dropped"
end

-- Get the user count of a module.
local function getUserCount(module)
    if not registeredModules[module] then return 0 end
    local count = 0
    for i,v in pairs(registeredModules[module]) do count = count + 1 end
    return count
end

-- Check to see if the module is registered. Return a user list if it is.
function isRegisteredModule(mod)
    if not registeredModules[mod] then return false end
    return registeredModules[mod]
end

-- Enable a module that isn't already enabled, and register it's use to a user.
function enableModule(user,module)
    registerUser(user)

    -- Check to see if the module is already enabled.
    if not isRegisteredModule(module) then
        local addString = nil
        local ttlString = ""
        for _,mod in pairs(module:split(".")) do
            if not addString then addString = mod
            else addString = string.format("%s.%s",addString,mod)
            end
            ttlString = string.format("%s\"%s 1\",",ttlString,addString)
        end
        ttlString = string.format("[%s]",ttlString:gsub("(.+),","%1"))
        sendGMCP(string.format([[Core.Supports.Add %s ]],ttlString))
        registeredModules[module] = {}
    end

    -- Add the user to the module's user list.
    addUser(user,module)
end


-- Send the module list again on reconnect, so activated modules stay enabled during
--   a session unless explicitly disabled
function gmod.reenableModules()
    local list = {}
    for module, users in pairs(registeredModules) do
        list[#list+1] = module.." 1"
    end
    sendGMCP("Core.Supports.Set "..yajl.to_string(list))
end
registerAnonymousEventHandler("sysConnectionEvent", "gmod.reenableModules")

-- Remove a user from a module's user list. Disable the module if nobody is using it.
function disableModule(user,module)
    registerUser(user)

    -- Make sure the module is enabled in the first place
    if not isRegisteredModule(module) then return "no registered module" end

    dropUser(user,module)

    -- The user is now removed from the list. Check the user count.
    if getUserCount(module) < 1 then
        sendGMCP(string.format([[Core.Supports.Remove ["%s"] ]],module))
        registeredModules[module] = nil
    end
end

function printModules(user)
    -- If a user is specified, print the name of all associated modules.
    if user then
        if not registeredUsers[user] then
            print(string.format("<cyan>%s <white>is not a registered user.",user))
            return
        end
        cecho(string.format("\n\n<white>Module listing for user: <cyan>%s",user))
        cecho(string.format("\n<white>%s",string.rep("-",45)))
        for i,v in pairs(registeredModules) do
            if v[user] then cecho(string.format("\n<yellow>%s",i)) end
        end
        return
    end

    -- No user specified, print all existing Modules with a user list.
    print("Current modules:")
    for i,v in pairs(registeredModules) do
        cecho(string.format("\n<yellow>%s\n  ",i))
        local doComma = false
        for j,_ in pairs(v) do
            if not doComma then doComma = true else cecho("<white>, ") end
            cecho(string.format("<cyan>%s",j))
        end
    end
end
