class CallLaterManager(object):
    _callLater = None
    _pendingCallLaters = []

    @classmethod
    def _cancel(cls, call_later):
        """
        :param call_later: DelayedCall
        :return: (callable) canceller function
        """

        def cancel(reason=None):
            """
            :param reason: reason for cancellation, this is returned after cancelling the DelayedCall
            :return: reason
            """

            if call_later.active():
                call_later.cancel()
            cls._pendingCallLaters.remove(call_later)
            return reason
        return cancel

    @classmethod
    def stop(cls):
        """
        Cancel any callLaters that are still running
        """

        from twisted.internet import defer
        while cls._pendingCallLaters:
            canceller = cls._cancel(cls._pendingCallLaters[0])
            try:
                canceller()
            except (defer.CancelledError, defer.AlreadyCalledError):
                pass

    @classmethod
    def call_later(cls, when, what, *args, **kwargs):
        """
        Schedule a call later and get a canceller callback function

        :param when: (float) delay in seconds
        :param what: (callable)
        :param args: (*tuple) args to be passed to the callable
        :param kwargs: (**dict) kwargs to be passed to the callable

        :return: (tuple) twisted.internet.base.DelayedCall object, canceller function
        """

        call_later = cls._callLater(when, what, *args, **kwargs)
        canceller = cls._cancel(call_later)
        cls._pendingCallLaters.append(call_later)
        return call_later, canceller

    @classmethod
    def setup(cls, callLater):
        """
        Setup the callLater function to use, supports the real reactor as well as task.Clock

        :param callLater: (IReactorTime.callLater)
        """
        cls._callLater = callLater