# -*- coding: utf-8 -*-

import sys
import threading
import functools
import click

from ._compat import reraise

try:
    import queue
except ImportError:
    import Queue as queue

__version__ = '0.1.2'


def _is_main_thread(thread=None):
    thread = thread or threading.current_thread()
    return type(thread).__name__ == '_MainThread'


class Thread(threading.Thread):
    '''A thread that automatically pushes the parent thread's context in the
    new thread.'''

    def __init__(self, *args, **kwargs):
        self._click_context = click.get_current_context()
        super(Thread, self).__init__(*args, **kwargs)

    def run(self):
        with self._click_context:
            return super(Thread, self).run()


class UiWorker(object):
    SHUTDOWN = object()

    def __init__(self):
        if not _is_main_thread():
            raise RuntimeError('The UiWorker can only run on the main thread.')

        self.tasks = queue.Queue()
        self.results = queue.Queue()

    def shutdown(self):
        self.put(self.SHUTDOWN, wait=False)

    def run(self):
        while True:
            func, need_result = self.tasks.get()
            if func is self.SHUTDOWN:
                return

            try:
                result = func()
                exc_info = None
            except BaseException:
                exc_info = sys.exc_info()
                result = None

            if need_result:
                self.results.put((func, result, exc_info))

    def put(self, func, wait=True):
        self.tasks.put((func, wait))
        if not wait:
            return
        orig_func, result, exc_info = self.results.get()

        if orig_func is not func:
            raise RuntimeError('Got the wrong result.')

        if exc_info is not None:
            reraise(*exc_info)

        return result

    def patch_click(self):
        from .monkey import patch_ui_functions

        def wrapper(f, info):
            @functools.wraps(f)
            def inner(*a, **kw):
                return self.put(lambda: f(*a, **kw), wait=info.interactive)
            return inner

        return patch_ui_functions(wrapper)

@@ -63,16 +63,34 @@
 nctools%0A
+import contextlib%0A
 import c
@@ -217,16 +217,58 @@
 0.1.2'%0A%0A
+_CTX_WORKER_KEY = __name__ + '.uiworker'%0A%0A
 %0Adef _is
@@ -1885,16 +1885,47 @@
 result%0A%0A
+    @contextlib.contextmanager%0A
     def 
@@ -2109,20 +2109,54 @@
  return 
-self
+get_ui_worker() %5C%0A                    
 .put(lam
@@ -2234,39 +2234,449 @@
     
-return patch_ui_functions(wrapper
+ctx = click.get_current_context()%0A        with patch_ui_functions(wrapper):%0A            ctx.meta%5B_CTX_WORKER_KEY%5D = self%0A            try:%0A                yield%0A            finally:%0A                assert ctx.meta.pop(_CTX_WORKER_KEY) is self%0A%0A%0Adef get_ui_worker():%0A    try:%0A        ctx = click.get_current_context()%0A        return ctx.meta%5B_CTX_WORKER_KEY%5D%0A    except (RuntimeError, KeyError):%0A        raise RuntimeError('UI worker not found.'
 )%0A

Put UI worker onto click context