# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.


from twisted.internet import defer
from twisted.python import failure
import cancellable_defer


if not hasattr(defer.Deferred(), 'cancel'):
    Deferred = cancellable_defer.CancellableDeferred
    CancelledError = cancellable_defer.CancelledError
else:
    Deferred = defer.Deferred
    CancelledError = defer.CancelledError


def succeed(result):
    """
    see L{twisted.internet.defer.succeed}.

    @rtype: L{Deferred}
    """
    d = Deferred()
    d.callback(result)
    return d

def fail(result=None):
    """
    see L{twisted.internet.defer.fail}. The biggest difference is that the
    twisted API allows you to call this without any parameters, which leads to
    an error. See http://twistedmatrix.com/trac/ticket/3145.

    @rtype: L{Deferred}
    """
    d = Deferred()
    d.errback(result)
    return d

def execute(callable, *args, **kw):
    """
    see L{twisted.internet.defer.execute}.

    @rtype: L{Deferred}
    """
    try:
        result = callable(*args, **kw)
    except Exception, exc:
        return fail(exc)
    else:
        return succeed(result)


def timeout(deferred):
    # old and new API compatible
    if hasattr(deferred, 'cancel'):
        deferred.cancel()
    else:
        msg = 'Callback timed out'
        deferred.errback(failure.Failure(defer.TimeoutError(msg)))

def deferred_accumulator(invocation_hint, return_accu, handler_return):
    """
    Accumulator to use with gobject signals where callbacks are supposed to
    return a Deferred. With this, emit() will return a list of all the
    Deferred returned by the connected callbacks. It ignores callback return
    values that are not Deferreds.

    @param invocation_hint: (signal_id, detail, run_type) (this parameter is
    ignored)
    @type invocation_hint: C{tuple}
    @param return_accu: a list of Deferred (or possibly None)
    @type return_accu: C{list}
    @param handler_return: The return value of the signal handler
    @type handler_return: C{elisa.core.utils.Deferred}

    @return: a tuple containing True and a list of deferreds.
    @rtype: C{tuple}
    """
    accu = return_accu
    if accu == None:
        accu = []
    if not isinstance(handler_return, Deferred):
        return True, accu
    return True, accu + [handler_return]

# for compability with twisted.internet.defer:
DeferredList = defer.DeferredList

FAILURE = defer.FAILURE
SUCCESS = defer.SUCCESS
TimeoutError = defer.TimeoutError
AlreadyCalledError = defer.AlreadyCalledError

gatherResults = defer.gatherResults
maybeDeferred = defer.maybeDeferred
waitForDeferred = defer.waitForDeferred
deferredGenerator = defer.deferredGenerator
inlineCallbacks = defer.inlineCallbacks

DeferredLock = defer.DeferredLock
DeferredSemaphore = defer.DeferredSemaphore
DeferredQueue = defer.DeferredQueue

# these classes are new since 8.1
try:
    DeferredFilesystemLock = defer.DeferredFilesystemLock
    AlreadyTryingToLockError = defer.AlreadyTryingToLockError
except AttributeError:
    pass
