
local flat_node_types = {
    signlike = true,
    raillike = true,
    torchlike = true,
    plantlike = true,
}

function aom_item_entity.is_node(itemname)
    local idef = minetest.registered_items[itemname]
    if not idef then return false end
    if idef.type ~= "node" then return false end
    if flat_node_types[idef.drawtype] ~= nil then return false end
    if idef.wield_image ~= "" then return false end
    return true
end

function aom_item_entity.try_stick(self)
    local pos = self.object:get_pos()
    -- prevent unloaded nil errors just in case
    if not pos then return end
    local vel = self.object:get_velocity()
    -- if it's not moving, stick
    -- items lay flat while sliding, nodes don't
    if not self._is_node then vel.x = 0; vel.z = 0; end
    local should_stick = (vector.length(vel) < 0.1)
    if should_stick and not self._is_stuck then
        aom_item_entity.SIGNAL("item_stick", self)
    elseif self._is_stuck and not should_stick then
        aom_item_entity.SIGNAL("item_unstick", self)
    end
end

aom_item_entity.LISTEN("on_step", function(self, dtime, moveresult, ...)
    if not aom_item_entity.get(nil, "item_lay_flat", true) then
        if self._is_stuck then
            aom_item_entity.SIGNAL("item_unstick", self)
        end
        return
    end
    aom_item_entity.try_stick(self)
    if self._sleep_state then return end
    aom_item_entity.SIGNAL("do_idle_rotation", self, dtime)
end)

aom_item_entity.LISTEN("item_stick", function(self)
    self._is_stuck = true
    if (not self._is_node) then
        local rot = self.object:get_rotation()
        rot = vector.new(math.pi*0.5, rot.y, 0)
        self.object:set_rotation(rot)
    end
end)

aom_item_entity.LISTEN("item_unstick", function(self)
    self._is_stuck = false
    local rot = self.object:get_rotation()
    rot = vector.new(0, rot.y, 0)
    self.object:set_rotation(rot)
end)

aom_item_entity.LISTEN("enable_physics", function(self)
    if not aom_item_entity.get(nil, "item_lay_flat", true) then return end
    aom_item_entity.SIGNAL("item_unstick", self)
end)

aom_item_entity.LISTEN("disable_physics", function(self)
    if not aom_item_entity.get(nil, "item_lay_flat", true) then return end
    aom_item_entity.SIGNAL("item_stick", self)
end)

aom_item_entity.LISTEN("get_properties", function(self, props)
    if not aom_item_entity.get(nil, "item_lay_flat", true) then return end

    local stack = ItemStack(self.itemstring)
    local itemname = stack:get_name()
    self._is_node = aom_item_entity.is_node(itemname)

    if not props.collisionbox then
        props.collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3}
    end
    -- allow custom size
    if aom_item_entity.get(nil, "item_scale", 0.2) then
        local s = aom_item_entity.get(nil, "item_scale", 0.2)
        local c = s - 0.1
        props.collisionbox = {-c,-c,-c, c, c, c}
        props.visual_size = vector.new(s,s+math.random()*0.001,s)
    else
        -- use the other sizes as a reference to make it compat with more things
        props.collisionbox[2] = props.collisionbox[1] * 0.6
    end
    -- items lie flat
    if (not self._is_node) then
        props.collisionbox[2] = -0.03
    end
    props.automatic_rotate = 0
    props.collisionbox = props.collisionbox
    props.visual_size = props.visual_size
end)

aom_item_entity.LISTEN("set_item", function(self, item, ...)
    if not aom_item_entity.get(nil, "item_lay_flat", true) then return end

    if aom_item_entity.get(nil, "item_initial_rotation", true) then
        self.object:set_rotation(vector.new(0,math.random()*math.pi*2, 0))
    end
    aom_item_entity.try_stick(self)
    if self._is_stuck then
        aom_item_entity.SIGNAL("item_stick", self)
    else
        aom_item_entity.SIGNAL("item_unstick", self)
    end
end)

aom_item_entity.LISTEN("do_idle_rotation", function(self, dtime)
    -- choose a spin dir if not set yet
    if not self._spin_dir then
        self._spin_dir = math.random(0,1)*2-1
    end
    local spin_speed = 0
    local vel = self.object:get_velocity()
    local rot_speed = aom_item_entity.get(nil, "item_rotation", 2)
    if (not self._is_stuck) and (rot_speed > 0) then
        spin_speed = math.min(0.3, dtime * vel:length() * (rot_speed/2))
    else return end

    local rot = self.object:get_rotation()
    if not rot then return end
    rot = vector.new(0, rot.y - spin_speed * self._spin_dir, 0)
    self.object:set_rotation(rot)
end)

