'Return the modules that directly or indirectly depend on the modules
in `self`, and that satisfy the `exclude_states` filter.'

@api.multi
@api.returns('self')
def downstream_dependencies(self, known_deps=None, exclude_states=('uninstalled', 'uninstallable', 'to    remove')):

    if (not self):
        return self
    known_deps = (known_deps or self.browse())
    query = '    SELECT    DISTINCT    m.id\n                                                                                FROM    ir_module_module_dependency    d\n                                                                                JOIN    ir_module_module    m    ON    (d.module_id=m.id)\n                                                                                WHERE\n                                                                                                d.name    IN    (SELECT    name    from    ir_module_module    where    id    in    %s)    AND\n                                                                                                m.state    NOT    IN    %s    AND\n                                                                                                m.id    NOT    IN    %s    '
    self._cr.execute(query, (tuple(self.ids), tuple(exclude_states), tuple((known_deps.ids or self.ids))))
    new_deps = self.browse([row[0] for row in self._cr.fetchall()])
    missing_mods = (new_deps - known_deps)
    known_deps |= new_deps
    if missing_mods:
        known_deps |= missing_mods.downstream_dependencies(known_deps, exclude_states)
    return known_deps
