""" event handler. """

import logging
import obj
import obj.loader
import obj.tasks
import obj.utils
import queue
import sys
import time
import threading
import types

handlers = {}

class Handler(obj.loader.Loader):

    def __init__(self):
        super().__init__()
        self._queue = queue.Queue()
        self._ready = threading.Event()
        self._stopped = False
        self._threaded = True
        self._thrs = []
        self.state = obj.Object()
        self.verbose = False

    def dispatch(self, event):
        event.parse(event.txt)
        event._func = self.get_cmd(event)
        event.verbose = self.verbose
        if event._func:
            logging.warn("dispatch %s" % event.txt)
            try:
                event._func(event)
            except Exception as ex:
                logging.error(obj.get_exception())
        event.show()
        event.ready()
        return event

    def get_cmd(self, event):
        return self.get_handler(event.cmd)

    def get_event(self):
        return self._queue.get()

    def get_handler(self, cmd):
        val = handlers.get(cmd, None)
        if not val:
            modname = obj.names.get(cmd, None)
            if modname:
                self.load_mod(modname)
            val = handlers.get(cmd, None)
        return val

    def load_mod(self, name, mod=None):
        mod = super().load_mod(name, mod)
        for key, func, modname in self.scan_commands(mod):
            handlers[key] = func
        return mod

    def loop(self):
        while not self._stopped:
            try:
                event = self.get_event()
            except EOFError:
                break
            if not event:
                continue
            thr = obj.launch(self.dispatch, event)
            event._thrs.append(thr)

    def put(self, event):
        self._queue.put_nowait(event)

    def ready(self):
        self._ready.set()

    def register(self, cmd, handler):
        handlers[cmd] = handler

    def start(self):
        obj.launch(self.loop)

    def stop(self):
        self._stopped = True
        self._queue.put(None)

    def walk(self, modname, init=False):
        thrs = []
        mod = self.load_mod(modname)
        if init and "init" in dir(mod):
            thrs.append(obj.launch(mod.init))
        for m in dir(mod):
            module = getattr(mod, m)
            if type(module) != types.ModuleType:
                continue
            self.load_mod(module.__name__, module)
            if init and "init" in dir(module):
                thrs.append(obj.launch(module.init))
        return thrs

    def wait(self):
        return self._ready.wait()

class Worker(Handler):

    def loop(self):
        while not self._stopped:
            try:
                event = self._queue.get()
            except EOFError:
                break
            if not event:
                continue
            thr = obj.launch(self.dispatch, event)
            event._thrs.append(thr)
