
local has_aom_settings = minetest.get_modpath("aom_settings")
function aom_itemframe.try_give_item(self, stack, user)
    -- drop if set by server or by player
    local drop_enabled
    if minetest.get_modpath("aom_settings") then
        drop_enabled = aom_settings.get_setting(user, "gameplay_force_node_drop", true)
        if (drop_enabled == false) then
            drop_enabled = aom_settings.get_setting(user, "gameplay_node_drop", false)
        end
    else
        drop_enabled = minetest.settings:get_bool("aom_node_drops", false)
    end

    if minetest.is_player(user) and (not drop_enabled) then
        stack = user:get_inventory():add_item("main", stack)
    end
    if stack:get_count() > 0 then
        local pos = self.object:get_pos()
        pos = pos + (vector.new(0, 0, 1):rotate(self.object:get_rotation()) * -0.3)
        minetest.add_item(pos, stack)
    end
end

-- dig as if a node
function aom_itemframe.dig_itemframe(self, user)
    if self._itemstring_frame then
        local stack = ItemStack(self._itemstring_frame)
        aom_itemframe.try_give_item(self, stack, user)
    end
    -- reset everything
    self._itemstring = nil
    self._itemstring_frame = nil
    self._disabled = true
    self.object:remove()
end

-- drop item, or if no item then drop the frame
function aom_itemframe.drop_item(self, user)
    -- if there's no item, dig the itemframe instead
    if not self._itemstring then aom_itemframe.dig_itemframe(self, user) end
    local stack = ItemStack(self._itemstring)
    aom_itemframe.try_give_item(self, stack, user)
    self._itemstring = nil
    aom_itemframe.update_visuals(self)
end

function aom_itemframe.update_visuals(self)
    local props = {}
    local old_props = self.object:get_properties()
    local changes = false
    if (self._itemstring == nil) then
        changes = true
        local iname = (self._itemstring_frame and ItemStack(self._itemstring_frame):get_name()) or "aom_itemframe:frame"
        props.textures = {iname}
        props.glow = 0
    elseif self._itemstring and (old_props.textures[1] ~= self._itemstring) then
        changes = true
        local iname = ItemStack(self._itemstring):get_name()
        props.textures = {iname}
        local idef = minetest.registered_items[iname]
        props.glow = math.min(14, idef.light_source or 0)
    end
    if changes then
        self.object:set_properties(props)
    end
end

function aom_itemframe.set_item(self, itemstack, user)
    if self._itemstring then return itemstack end
    itemstack = ItemStack(itemstack)
    local frame_stack = ItemStack(itemstack)

    local iname = frame_stack:get_name()
    if minetest.get_item_group(iname, "not_in_creative_inventory") > 0 then return itemstack end
    if minetest.get_item_group(iname, "disallow_itemframe") > 0 then return itemstack end
    if iname == "" then return itemstack end

    if minetest.is_creative_enabled(user:get_player_name()) then
        frame_stack = itemstack:peek_item(1)
    else
        frame_stack = itemstack:take_item(1)
    end
    self._itemstring = frame_stack:to_string()
    aom_itemframe.update_visuals(self)
    return itemstack
end

function aom_itemframe.has_itemframe_in_node(pos)
    pos = vector.new(
        math.floor(pos.x) - 0.5,
        math.floor(pos.y) - 0.5,
        math.floor(pos.z) - 0.5
    )
    local objects = minetest.get_objects_in_area(pos, vector.offset(pos, 1, 1, 1))
    for i, object in ipairs(objects) do
        local ent = object:get_luaentity()
        if ent and ent._itemframe then
            return true
        end
    end
end

function aom_itemframe.allow_place(itemstack, player, pointed_thing)
    if has_aom_settings then
        local max = aom_settings.get_setting(player, "performance_itemframes_max", 2)
        local pos = pointed_thing.above
        local d = 40
        local objects = minetest.get_objects_in_area(vector.offset(pos,-d,-d,-d), vector.offset(pos, d, d, d))
        local total = 0
        for i, object in pairs(objects) do
            local ent = object:get_luaentity()
            if ent and ent._itemframe then
                total = total + 1
                if total > max - 1 then
                    minetest.chat_send_player(player:get_player_name(), "[server] Too many itemframes placed, remove some first.")
                    return false
                end
            end
        end
    end
    return true
end

function aom_itemframe.new_itemframe(itemstack, player, pointed_thing)
    if aom_itemframe.has_itemframe_in_node(pointed_thing.above) then return itemstack end
    if not aom_itemframe.allow_place(itemstack, player, pointed_thing) then return itemstack end
    itemstack = ItemStack(itemstack)
    local frame_stack = ItemStack(itemstack)
    if minetest.is_creative_enabled(player:get_player_name()) then
        frame_stack = itemstack:peek_item(1)
    else
        frame_stack = itemstack:take_item(1)
    end

    local dir = pointed_thing.under - pointed_thing.above
    local rot = vector.dir_to_rotation(dir)
    local pos = pointed_thing.above + dir * 0.4
    local obj = minetest.add_entity(pos, "aom_itemframe:entity")
    if not obj then return end
    obj:set_rotation(rot)
    local ent = obj:get_luaentity()
    ent._itemstring_frame = frame_stack:to_string()
    aom_itemframe.update_visuals(ent)
    return itemstack
end

aom_itemframe.entity = {
    initial_properties = {
        physical = false,
        visual = "wielditem",
        textures = {"aom_itemframe:frame"},
        visual_size = {x=0.3, y=0.3, z=0.3},
        collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2,},
        use_texture_alpha = true,
        pointable = true,
        glow = 14,
    },
    _itemframe = true,
    _itemstring = nil,
    _itemstring_frame = nil,
    _aom_staticdata_load_list = {
        "_itemstring",
        "_itemstring_frame",
        "_disabled",
    },
    on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
        aom_itemframe.drop_item(self, puncher)
    end,
    on_rightclick = function(self, clicker)
        if not minetest.is_player(clicker) then return end
        local player = clicker
        local stack = player:get_wielded_item()
        local retstack = aom_itemframe.set_item(self, stack, clicker)
        if retstack and retstack:equals(stack) then return end
        player:set_wielded_item(retstack)
        return retstack -- just better code practice
    end,
    on_activate = function(self, staticdata, dtime_s)
        local data = minetest.deserialize(staticdata)
        if not data then return end
        for key, val in pairs(data) do
            self[key] = val
        end
        aom_itemframe.update_visuals(self)
    end,
    get_staticdata = function(self)
        local data = {}
        for k, v in ipairs(self._aom_staticdata_load_list) do
            data[v] = self[v]
        end
        return minetest.serialize(data)
    end,
}

minetest.register_entity("aom_itemframe:entity", aom_itemframe.entity)
