'''
The MIT License (MIT)

https://github.com/robertchase/spindrift/blob/master/LICENSE.txt
'''
import inspect
import logging


log = logging.getLogger(__name__)


class Task(object):

    def __init__(self, callback, cid=None, cursor=None):
        self._callback = callback
        self.cid = cid
        self.cursor = cursor
        self.is_done = True
        self._cleanup = []

    def __setattr__(self, name, value):
        if name == 'cleanup':
            self._cleanup.append(value)
        else:
            super(Task, self).__setattr__(name, value)

    @property
    def callback(self):
        def cleanup_before_callback(rc, result):
            for cleanup in self._cleanup[::-1]:
                cleanup()
            self._callback(rc, result)
        return cleanup_before_callback

    def call(self, fn, args=None, kwargs=None, on_success=None, on_none=None,
             on_error=None, on_timeout=None):
        self.is_done = False

        def cb(rc, result):
            if rc == 0:
                _callback(self, fn, result, on_success, on_none)
            else:
                _callback_error(self, fn, result, on_error, on_timeout)
            self.is_done = True

        if args is None:
            args = ()
        elif not isinstance(args, (tuple, list)):
            args = (args,)

        if kwargs is None:
            kwargs = {}

        task, cursor = inspect_parameters(fn, kwargs)

        if task:
            cb = Task(cb, self.cid, self.cursor)
        elif cursor:
            kwargs['cursor'] = getattr(self, 'cursor')

        log.debug('task.call fn=%s %s', fn, 'as task' if task else '')
        fn(cb, *args, **kwargs)
        return self


def inspect_parameters(fn, kwargs):

    task = False
    cursor = False

    # get a list of function parameters
    sig = inspect.signature(fn).parameters

    # is the first parameter named 'task'
    if [p for p in sig.values()][0].name == 'task':
        task = True
    else:
        # is 'cursor' one of the parameters (and not already a kwarg)
        if 'cursor' in sig and 'cursor' not in kwargs:
            cursor = True

    return task, cursor


def _callback(task, fn, result, on_success, on_none):
    if on_none and result is None:
        try:
            log.debug('task.callback, cid=%s, on_none fn=%s', task.cid, on_none)
            return on_none(task, result)
        except Exception as e:
            return task.callback(1, 'exception during on_none: %s' % e)
    if on_success:
        try:
            log.debug('task.callback, cid=%s, on_success fn=%s', task.cid,
                      on_success)
            return on_success(task, result)
        except Exception as e:
            return task.callback(1, 'exception during on_success: %s' % e)
    log.debug('task.callback, cid=%s, default success callback', task.cid)
    task.callback(0, result)


def _callback_error(task, fn, result, on_error, on_timeout):
    if on_timeout and result == 'timeout':
        try:
            log.debug('task.callback, cid=%s, on_timeout fn=%s', task.cid,
                      on_timeout)
            return on_timeout(task, result)
        except Exception as e:
            return task.callback(1, 'exception during on_timeout: %s' % e)
    if on_error:
        try:
            log.debug('task.callback, cid=%s, on_error fn=%s', task.cid,
                      on_error)
            return on_error(task, result)
        except Exception as e:
            return task.callback(1, 'exception during on_error: %s' % e)
    log.debug('task.callback, cid=%s, default error callback', task.cid)
    task.callback(1, result)

@@ -1773,33 +1773,8 @@
     
-# get a list of function 
 para
@@ -1783,16 +1783,8 @@
 ters
-%0A    sig
  = i
@@ -1819,28 +1819,12 @@
 ers%0A
-%0A
     
-# is the first 
 para
@@ -1832,62 +1832,106 @@
 eter
- 
+_
 name
-d 'task'%0A    if %5Bp for p in sig.values()%5D%5B0%5D.name
+s = %5Bp.name for p in parameters.values()%5D%0A%0A    if len(parameter_names) and parameter_names%5B0%5D
  == 
@@ -1980,12 +1980,10 @@
     
-# is
+if
  'cu
@@ -1992,18 +1992,10 @@
 or' 
-one of the
+in
  par
@@ -2006,61 +2006,8 @@
 ers 
-(and not already a kwarg)%0A        if 'cursor' in sig 
 and 

cleanup inspection in task