"""
This magical module will rewrite all public methods in the public interface
of the library so they can run the loop on their own if it's not already
running. This rewrite may not be desirable if the end user always uses the
methods they way they should be ran, but it's incredibly useful for quick
scripts and the runtime overhead is relatively low.

Some really common methods which are hardly used offer this ability by
default, such as ``.start()`` and ``.run_until_disconnected()`` (since
you may want to start, and then run until disconnected while using async
event handlers).
"""
import asyncio
import functools
import inspect

from async_generator import isasyncgenfunction

from .client.telegramclient import TelegramClient
from .tl.custom import (
    Draft, Dialog, MessageButton, Forward, Message, InlineResult, Conversation
)
from .tl.custom.chatgetter import ChatGetter
from .tl.custom.sendergetter import SenderGetter


class _SyncGen:
    def __init__(self, gen):
        self.gen = gen

    def __iter__(self):
        return self

    def __next__(self):
        try:
            return asyncio.get_event_loop() \
                .run_until_complete(self.gen.__anext__())
        except StopAsyncIteration:
            raise StopIteration from None


def _syncify_wrap(t, method_name, gen):
    method = getattr(t, method_name)

    @functools.wraps(method)
    def syncified(*args, **kwargs):
        coro = method(*args, **kwargs)
        loop = asyncio.get_event_loop()
        if loop.is_running():
            return coro
        elif gen:
            return _SyncGen(coro)
        else:
            return loop.run_until_complete(coro)

    # Save an accessible reference to the original method
    setattr(syncified, '__tl.sync', method)
    setattr(t, method_name, syncified)


def syncify(*types):
    """
    Converts all the methods in the given types (class definitions)
    into synchronous, which return either the coroutine or the result
    based on whether ``asyncio's`` event loop is running.
    """
    for t in types:
        for name in dir(t):
            if not name.startswith('_') or name == '__call__':
                if inspect.iscoroutinefunction(getattr(t, name)):
                    _syncify_wrap(t, name, gen=False)
                elif isasyncgenfunction(getattr(t, name)):
                    _syncify_wrap(t, name, gen=True)


syncify(TelegramClient, Draft, Dialog, MessageButton,
        ChatGetter, SenderGetter, Forward, Message, InlineResult, Conversation)

@@ -636,56 +636,8 @@
 ct%0A%0A
-from async_generator import isasyncgenfunction%0A%0A
 from
@@ -682,16 +682,16 @@
 mClient%0A
+
 from .tl
@@ -888,342 +888,8 @@
 r%0A%0A%0A
-class _SyncGen:%0A    def __init__(self, gen):%0A        self.gen = gen%0A%0A    def __iter__(self):%0A        return self%0A%0A    def __next__(self):%0A        try:%0A            return asyncio.get_event_loop() %5C%0A                .run_until_complete(self.gen.__anext__())%0A        except StopAsyncIteration:%0A            raise StopIteration from None%0A%0A%0A
 def 
@@ -916,21 +916,16 @@
 hod_name
-, gen
 ):%0A    m
@@ -1159,60 +1159,8 @@
 oro%0A
-        elif gen:%0A            return _SyncGen(coro)%0A
     
@@ -1591,24 +1591,204 @@
 ng.%0A    %22%22%22%0A
+    # Our asynchronous generators all are %60RequestIter%60, which already%0A    # provide a synchronous iterator variant, so we don't need to worry%0A    # about asyncgenfunction's here.%0A
     for t in
@@ -1944,32 +1944,32 @@
 attr(t, name)):%0A
+
                 
@@ -1997,131 +1997,8 @@
 name
-, gen=False)%0A                elif isasyncgenfunction(getattr(t, name)):%0A                    _syncify_wrap(t, name, gen=True
 )%0A%0A%0A

Remove code to syncify async generator functions