import logging
from threading import Thread, Timer
import collections
import sys
from SKFClient.core.utils.log import log

if sys.version_info[0] < 3:
    from Queue import Queue, Empty
else:
    from queue import Queue, Empty

Msg = collections.namedtuple('Msg', ['event', 'arg'])


class RepeatedTimer(object):
    def __init__(self, interval, function, first_interval=None):
        self._timer = None
        self.interval = interval
        if first_interval is not None:
            self.current_interval = first_interval
        else:
            self.current_interval = self.interval
        self.function = function
        self.is_running = False
        self.start()

    def _run(self):
        self.is_running = False
        self.start()
        self.function()

    def start(self):
        if not self.is_running:
            self._timer = Timer(self.current_interval, self._run)
            self.current_interval = self.interval
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False


class BaseThread(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.timer = None
        self.queue = Queue()
        self.running = False
        self.app_context = None
        self.timeout = None
        self.first_time_timeout = None

    def _send(self, event, arg):
        msg = Msg(event, arg)
        self.queue.put(msg)

    def dispatch(self, msg):
        event, arg = msg
        handler = getattr(self, "on_%s" % event, None)
        if not handler:
            raise NotImplementedError("Class has no handler for [%s]" % event)
        handler(arg)

    def incoming_msg(self, arg):
        self._send('message', arg)

    def incoming_msg(self, msg_type, arg):
        self._send(msg_type, arg)

    def init(self, app_context):
        self.app_context = app_context

    def set_timeout(self, timeout, first_time_timeout = None):
        self.timeout = timeout
        self.first_time_timeout = first_time_timeout

    def stop(self):
        self.running = False
        if self.timer is not None:
            self.timer.stop()

    def timer_fn(self):
        if self.timer is not None:
            self._send('timer', {})

    def run(self):
        self.running = True

        if self.timeout and self.timeout > 0:
            self.timer = RepeatedTimer(interval=self.timeout, function=self.timer_fn, first_interval=self.first_time_timeout)
            self.timer.start()

        while self.running:
            try:
                msg = self.queue.get(timeout=0.5)
                self.dispatch(msg)
            except Empty:
                continue
            except Exception as ex:
                log.error(ex, exc_info=True)
                continue
