from threading import Thread
from time import time, sleep

def inttime():
    return int(time())

class AlreadyCalled(Exception):
    pass

def callInThread(f, *args, **kwargs):
    class FThread(Thread):
        def __init__(self):
            Thread.__init__(self)
            self.d = Deferred()
        def run(self):
            ret = f(*args, **kwargs)
            self.d.callback(ret)
    t = FThread()
    t.start()
    return t.d

class Deferred():
    def __init__(self):
        self.call = []
        self.err = []
        self.result = ()
        self.errresult = ()
    
    def addCallback(self, f, *cargs, **ckwargs):
        self.call.append((f, cargs, ckwargs))
        if self.result:
            args, kwargs = self.result
            args+=tuple(cargs)
            kwargs.update(ckwargs)
            callInThread(f, *args, **kwargs)
    
    def addErrback(self, f, *cargs, **ckwargs):
        self.err.append((f, cargs, ckwargs))
        if self.errresult:
            args, kwargs = self.errresult
            args+=tuple(cargs)
            kwargs.update(ckwargs)
            callInThread(f, *args, **kwargs)
    
    def callback(self, *args, **kwargs):
        if self.result:
            raise AlreadyCalled
        self.result = (args, kwargs)
        for f, cargs, ckwargs in self.call:
            args+=tuple(cargs)
            kwargs.update(ckwargs)
            callInThread(f, *args, **kwargs)
    
    def error(self, *args, **kwargs):
        self.errresult = (args, kwargs)
        for f, cargs, ckwargs in self.err:
            args+=tuple(cargs)
            kwargs.update(ckwargs)
            callInThread(f, *args, **kwargs)

#decorator
def threaded(f):
    def ret(*args, **kwargs):
        return callInThread(f, *args, **kwargs)
    return ret

def waitFor(d):
    class Waiter():
        waiting = True
        args = ()
        err = None
        
        def wait(self):
            d.addCallback(self.callb)
            d.addErrback(self.errb)
            while self.waiting:
                sleep(0.5)
            if self.err:
                raise Exception(self.err)
            return self.args
        
        def callb(self, *args, **kwargs):
            self.waiting = False
            self.args = (args, kwargs)
        
        def errb(self, *args, **kwargs):
            self.waiting = False
            self.err = (args, kwargs)
    w = Waiter()
    return w.wait()

class DeferredGroup(Deferred):
    def __init__(self, group=[]):
        Deferred.__init__(self)
        self.group = group
        self.done = 0
        
        for d in self.group:
            d.addCallback(self._cb)
            d.addErrback(self.error)
    
    def addDeferred(self, d):
        d.addCallback(self._cb)
        d.addErrback(self.error)
        self.group.append(d)
    
    def _cb(self, *args, **kwargs):
        self.done += 1
        if len(self.group) == self.done:
            self.callback()