import threading
import json
from fnmatch import fnmatch

from pymoku import log
from pymoku.network import FrameTimeout


PORT = 27183


class NotificationLogger(object):
    def __init__(self, moku):
        self.moku = moku
        self.skt = None
        self._running = None
        self.listeners = []
        self._lock = threading.RLock()

    def _recv(self):
        data = self.skt.get_data()
        evt = json.loads(data.decode('utf8'))
        event = (evt['id'], evt['event'], evt['data'])
        log.debug("{:6d}: {}".format(evt['id'], evt['event']))
        return event

    def _run(self):
        self._running = True
        self.skt = self.moku.socket_factory.get_notification_socket()

        log.debug("Start notification")
        while self._running:
            try:
                event = self._recv()
                with self._lock:
                    for k, l in self.listeners:
                        if fnmatch(event[1], k):
                            try:
                                l(*event)
                            except Exception:
                                log.exception('Listener Error')
            except FrameTimeout:
                pass
        self.skt.close()

    def stop(self):
        self._running = False
        self._t.join(timeout=1.0)

    def start(self):
        self._t = threading.Thread(target=self._run, daemon=True)
        self._t.start()

    def subscribe(self, name, callback):
        with self._lock:
            self.listeners.append((name, callback))

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.stop()
