
-- pushed by water
aom_item_entity.LISTEN("on_step", function(self, dtime, moveresult, ...)
    local push_vel = aom_item_entity.get(nil, "item_water_push_vel", 4)
    if push_vel == 0 then return end
    self._is_pushed_by_water = aom_fluidapi.push_by_liquid(self.object, dtime, push_vel)
end)

aom_item_entity.LISTEN("should_sleep", function(self, dtime, moveresult)
    if not aom_item_entity.get(nil, "item_float_in_water", false) then return end
    if (self._is_pushed_by_water or self._floating) and not self._on_surface_water then
        return false
    end
end)

-- floating on water
aom_item_entity.LISTEN("should_sleep", function(self, dtime, moveresult)
    if not aom_item_entity.get(nil, "item_float_in_water", false) then return end
    if self._on_surface_water then
        return true
    end
end)

local function ndef(p)
    local node = minetest.get_node(p)
    return node, minetest.registered_nodes[node.name]
end

function aom_item_entity.is_on_water_surface(pos)
    local p = vector.offset(pos, 0, 0.0, 0)
    local n, def = ndef(vector.offset(pos, 0, 0.2, 0))
    if (def.liquidtype == "source") or (def.liquidtype == "flowing") then return false end
    local bn, bdef = ndef(p)
    if (bdef.liquidtype == "source") or (bdef.liquidtype == "flowing") then return true end
    return false
end

aom_item_entity.LISTEN("on_enter_water", function(self)
    aom_item_entity.SIGNAL("enable_gravity", self, 0.5)
end)
aom_item_entity.LISTEN("on_leave_water", function(self)
    aom_item_entity.SIGNAL("enable_gravity", self)
end)

aom_item_entity.LISTEN("should_float", function(self)
    local iname = ItemStack(self.itemstring):get_name()
    local all_items = not aom_item_entity.get(nil, "item_float_only_if_set", true)
    if all_items or (minetest.get_item_group(iname, "floats") > 0)
    or (minetest.get_item_group(iname, "wood") > 0) then
        return true
    end
end)

aom_item_entity.LISTEN("on_step", function(self, dtime, moveresult, ...)
    if not aom_item_entity.get(nil, "item_float_in_water", false) then return end

    local pos = self.object:get_pos()
    local vel = self.object:get_velocity()

    local is_surface = aom_item_entity.is_on_water_surface(pos)

    if is_surface and (vector.length(vel) < 0.5) then
        self._on_surface_water = true
        self.object:set_velocity(vector.new(0,0,0))
        pos.y = math.floor(pos.y) + 0.4
        self.object:set_pos(pos)
    else
        self._on_surface_water = false
    end

    local was_in_water = self._is_in_water

    local node = minetest.get_node(pos)
    local liquidtype = minetest.registered_nodes[node.name].liquidtype
    self._is_in_water = (liquidtype == "source") or (liquidtype == "flowing")
    self._floating = (liquidtype == "source")
    self._floating = self._floating and not self._on_surface_water
    if not aom_item_entity.CONDITIONAL("should_float", self) then
        self._floating = false
    end

    if self._is_in_water then
        vel = vel * aom_item_entity.get(nil, "item_water_deceleration", 0.98)
        self.object:set_velocity(vel)
        if not was_in_water then
            aom_item_entity.SIGNAL("on_enter_water", self)
        end
    elseif was_in_water then
        aom_item_entity.SIGNAL("on_leave_water", self)
    end

    if self._floating then
        local factor = 1 - math.min(1, math.max(0, vel.y / 5))
        local add = 8 * dtime * factor
        self.object:add_velocity(vector.new(0, add, 0))
    end
end)
