import zmq

from logging import Logger
from typing import Optional
from messagehandler import MessageHandlerBuilder
from messagebus import Event, MessageBus
from zeromqthreadpool import PullWorkerThread


class HandleEventWorkerThread(PullWorkerThread, MessageBus):
    def __init__(self, context, worker_address, idle_timeout, message_handler_builder, pub_address, logger=None):
        # type: (zmq.Context, str, int, MessageHandlerBuilder, str, Logger) -> None
        super(HandleEventWorkerThread, self).__init__(context, worker_address, idle_timeout)
        self.message_handler_builder = message_handler_builder
        self.logger = logger
        self.pub_socket = context.socket(zmq.PUB)
        self.pub_socket.connect(pub_address)

    def do_work(self, data):
        event = self.parse_event(data)
        if event is None:
            return

        try:
            message_handler = self.message_handler_builder.build_message_handler()
            message_handler.handle_event(self, event)
        except:
            self.logger.exception("Error handling event")

    def dispose(self):
        self.pub_socket.close()

    def publish_event(self, event):
        data = "{} {}\0{}".format(event.subject, event.event_type, event.data)
        self.pub_socket.send(data)

    def send_message(self, component, message):
        pass

    def subscribe(self, subject):
        pass

    def reply_message(self, message, reply_message):
        pass

    def reply_event(self, event, reply_message):
        pass

    def parse_event(self, raw_data):
        # type: (bytes) -> Optional[Event]
        subject = None
        count = 0
        for b in raw_data:
            if b == ord(b" "):
                subject = raw_data[0:count].decode("utf-8")
                break

            count += 1

        if subject is None:
            return None

        type = None
        count += 1
        start = count
        for count in range(count, len(raw_data), 1):
            if raw_data[count] == ord(b"\0"):
                type = raw_data[start:count].decode("utf-8")
                break

        if type is None:
            return None

        count += 1

        data = raw_data[count:].decode("utf-8")

        return Event(subject, type, data)
