--[[

Persistent player attributes

]]

-- change this to inject into other module
local M = sunburn

M.persistent_player_attributes = {}
local PPA = M.persistent_player_attributes

--[[
Helper functions that take care of the conversions *and* the
clamping for us
]]

local function _count_for_val(value, def)
    local count = math.floor((value - def.min) / (def.max - def.min) * 65535)
    if count < 0 then count = 0 end
    if count > 65535 then count = 65535 end
    return count
end
local function _val_for_count(count, def)
    local value = count / 65535 * (def.max - def.min) + def.min
    if value < def.min then value = def.min end
    if value > def.max then value = def.max end
    return value
end
-- end helper functions

-- the stash of registered attributes

PPA.defs = {--[[
    name = {
        name = "mymod_attr1",
        min = 0,
        max = 10,
        default = 5,
    },
]]}

PPA.read_cache = {--[[
    player_name = {
        attr1 = value1,
        attr2 = value2,
    },
]]}

--[[
How to register a new attribute, with named parameters:
    PPA.register({ name = "mymod_attr1", min = 0, ... })
]]

PPA.register = function(def)
    PPA.defs[def.name] = {
        name = def.name,
        min = def.min or 0.0,
        max = def.max or 1.0,
        default = def.default or def.min or 0.0,
    }
end

-- The on_joinplayer handler

PPA.on_joinplayer = function(player)
    local inv = player:get_inventory()
    local player_name = player:get_player_name()
    PPA.read_cache[player_name] = {}
    for name, def in pairs(PPA.defs) do
        inv:set_size(name, 1)
        if inv:is_empty(name) then
            -- set default value
            inv:set_stack(name, 1, ItemStack({ name = ":", count = _count_for_val(def.default, def) }))
            -- cache default value
            PPA.read_cache[player_name][name] = def.default
        end
    end
end

minetest.register_on_joinplayer(PPA.on_joinplayer)


--[[ get an attribute, procedural style:
    local attr1 = PPA.get_value(player, "mymod_attr1")
]]

PPA.get_value = function(player, name)
    local player_name = player:get_player_name()
    if PPA.read_cache[player_name][name] == nil then
        local def = PPA.defs[name]
        local inv = player:get_inventory()
        local count = inv:get_stack(name, 1):get_count()
        PPA.read_cache[player_name][name] = _val_for_count(count, def)
    end
    return PPA.read_cache[player_name][name]
end

--[[ set an attribute, procedural style:
    PPA.set_value(player, "mymod_attr1", attr1)
]]

PPA.set_value = function(player, name, value)
    local def = PPA.defs[name]
    local inv = player:get_inventory()
    local player_name = player:get_player_name()
    if value > def.max then value = def.max end
    if value < def.min then value = def.min end
    PPA.read_cache[player_name][name] = value
    inv:set_stack(name, 1, ItemStack({ name = ":", count = _count_for_val(value, def) }))
end
