from asyncio import Future, CancelledError, TimeoutError, sleep, gather

from .consts import MAX_ASYNC_WHILE
from .access import (
    get_event_loop, LOGGER, ensure_future, create_future
)


def return_false():
    return False


def chain_future(future, callback=None, errback=None, next=None):
    '''Chain a :class:`~asyncio.Future` to an existing ``future``.

    This function `chain` the ``next`` future to an existing ``future``.
    When the input ``future`` receive a result the optional
    ``callback`` is executed and its result set as the results of ``next``.
    If an exception occurs the optional ``errback`` is executed.

    :param future: the original :class:`~asyncio.Future` (can be a coroutine)
    :param callback: optional callback to execute on the result of ``future``
    :param errback: optional callback to execute on the exception of ``future``
    :param next: optional :class:`~asyncio.Future` to chain.
        If not provided a new future is created
    :return: the future ``next``
    '''
    loop = next._loop if next else None
    future = ensure_future(future, loop=loop)
    if next is None:
        next = create_future(future._loop)

    def _callback(fut):