<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def drain(self, sid=None):
 """ Drain will put a connection into a drain state. All subscriptions will immediately be put into a drain state. Upon completion, the publishers will be drained and can not publish any additional messages. Upon draining of the publishers, the connection will be closed. Use the `closed_cb' option to know when the connection has moved from draining to closed. If a sid is passed, just the subscription with that sid will be drained without closing the connection. """

        if self.is_draining:
            return

        if self.is_closed:
            raise ErrConnectionClosed

        if self.is_connecting or self.is_reconnecting:
            raise ErrConnectionReconnecting

        # Drain a single subscription
        if sid is not None:
            raise tornado.gen.Return(self._drain_sub(sid))

        # Start draining the subscriptions
        self._status = Client.DRAINING_SUBS

        drain_tasks = []
        for ssid, sub in self._subs.items():
            task = self._drain_sub(ssid)
            drain_tasks.append(task)

        # Wait for subscriptions to stop handling messages.
        drain_is_done = tornado.gen.multi(drain_tasks)
        try:
            yield tornado.gen.with_timeout(
                timedelta(seconds=self.options["drain_timeout"]),
                drain_is_done,
                )
        except tornado.gen.TimeoutError:
            if self._error_cb is not None:
                yield self._error_cb(ErrDrainTimeout())
        finally:
            self._status = Client.DRAINING_PUBS
            yield self.flush()
            yield self.close()