import sys
import os
import subprocess
import asyncio
from types import ModuleType

try:
    ensure_future = asyncio.ensure_future
except AttributeError:
    ensure_future = getattr(asyncio, 'async')

abstract_loop = asyncio.AbstractEventLoop

task = None
reload_attempted = False
reload_function = None
files = set()


def start(loop: abstract_loop = None, interval: float = 0.5, func = None) -> asyncio.Task:
    """
    Start the reloader: create the task which is watching
    loaded modules and manually added files via ``watch()``
    and reloading the process in case of modification, and
    attach this task to the loop.

    If ``func`` is provided, it will be called when
    the application goes to reload.
    """
    if loop is None:
        loop = asyncio.get_event_loop()

    global reload_function
    if func is not None:
        reload_function = func

    global task
    if not task:
        modify_times = {}
        task = call_periodically(loop, interval, check_all, modify_times)
    return task


def watch(path: str) -> None:
    """
    Add any file to the watching list.
    """
    files.add(path)


def call_periodically(loop: abstract_loop, interval, callback, *args):
    @asyncio.coroutine
    def wrap():
        while True:
            yield from asyncio.sleep(interval, loop=loop)
            callback(*args)
    return ensure_future(wrap(), loop=loop)


def check_all(modify_times):
    if reload_attempted:
        return
    for module in list(sys.modules.values()):
        if not isinstance(module, ModuleType):
            continue
        path = getattr(module, '__file__', None)
        if not path:
            continue
        check(path, modify_times)
    for path in files:
        check(path, modify_times)


def check(target, modify_times):
    time = os.stat(target).st_mtime
    if target not in modify_times:
        modify_times[target] = time
        return
    if modify_times[target] != time:
        reload()


def reload():
    global reload_attempted
    reload_attempted = True
    
    if reload_function is not None:
        reload_function()

    if sys.platform == 'win32':
        subprocess.Popen([sys.executable] + sys.argv)
        sys.exit(os.EX_OK)
    else:
        try:
            os.execv(sys.executable, [sys.executable] + sys.argv)
        except OSError:
            os.spawnv(
                os.P_NOWAIT,
                sys.executable,
                [sys.executable] + sys.argv,
            )
            os._exit(os.EX_OK)

@@ -281,24 +281,20 @@
 %0Areload_
-function
+hook
  = None%0A
@@ -370,20 +370,20 @@
  = 0.5, 
-func
+hook
  = None)
@@ -629,20 +629,20 @@
    If %60%60
-func
+hook
 %60%60 is pr
@@ -700,22 +700,32 @@
 goes to 
+the 
 reload
+ stage
 .%0A    %22%22
@@ -810,24 +810,20 @@
 oad_
-function
+hook
 %0A    if 
 func
@@ -818,20 +818,20 @@
 %0A    if 
-func
+hook
  is not 
@@ -851,24 +851,20 @@
  reload_
-function
+hook
  = func%0A
@@ -2032,20 +2032,16 @@
  = True%0A
-    
 %0A    if 
@@ -2047,24 +2047,20 @@
  reload_
-function
+hook
  is not 
@@ -2084,16 +2084,12 @@
 oad_
-function
+hook
 ()%0A%0A

change from "function" to "hook"