
local adjacent = {
    vector.new(0, 0, 1),
    vector.new(0, 0,-1),
    vector.new(1, 0, 0),
    vector.new(-1,0, 0),
    vector.new(0, 1, 0),
    vector.new(0,-1, 0),
}

local function shuffle()
    for i = 1, #adjacent-2 do
        local idest = math.random(1, #adjacent-2)
        adjacent[i], adjacent[idest] = adjacent[idest], adjacent[i]
    end
end

function aom_item_entity.is_inside_node(self)
    local pos = self.object:get_pos()
    pos.y = pos.y + 0.1
    local pointed_thing = aom_item_entity.raycast(pos, -0.05)
    if pointed_thing and pointed_thing.type == "node" then
        self._node = minetest.get_node_or_nil(pointed_thing.under)
    else
        self._node = nil
    end
    if not self._node then return false end
    return minetest.registered_nodes[self._node.name].walkable ~= false
end

function aom_item_entity.get_adjacent_nonwalkable_dir(pos)
    shuffle()
    for i, d in ipairs(adjacent) do
        local p = d + pos
        local node = minetest.get_node_or_nil(p)
        if node and minetest.registered_nodes[node.name].walkable == false then
            return d
        end
    end
    return vector.new(0, 1, 0)
end

function aom_item_entity.push_out_node(self, dtime)
    if (not self._push_out_pos) or (not self._push_out_dir) then return end -- nothing pushing out
    if not self._collisionbox then return end
    local pos = self.object:get_pos()
    local s = math.abs(self._collisionbox[1] - self._collisionbox[4])
    local sdist = aom_item_entity.squaredist(pos, self._push_out_pos)
    if (sdist > (s + 0.5) ^ 2) then
        self._push_out_pos = nil
        self._push_out_dir = nil
        aom_item_entity.SIGNAL("enable_physics", self)
        aom_item_entity.debug("Push out finished")
    else
        local vel = self._push_out_dir * 2
        vel.y = vel.y + 0.1
        self.object:set_velocity(vel)
    end
end

aom_item_entity.LISTEN("on_step", function(self, dtime, moveresult, ...)
    local pos = self.object:get_pos()
    if not pos then return false end

    if (self.physical_state) and aom_item_entity.is_inside_node(self) then
        self._push_out_pos = vector.round(pos)
        self._push_out_dir = aom_item_entity.get_adjacent_nonwalkable_dir(pos)
        aom_item_entity.SIGNAL("disable_physics", self)
        aom_item_entity.debug("Push out STARTED")
    end
    aom_item_entity.push_out_node(self, dtime)
end)
