import datetime
import logging
from abc import abstractmethod

import zmq

from flandre.BusClient import BusClient
import flandre
from flandre.utils.Msg import Msg, KillMsg, NodeOnlineMsg, Msg1, Msg2


class Node:
    fp = BusClient.fp
    bp = BusClient.bp
    topics = []

    def __init__(self, enable_init=True, level=logging.INFO, conflare=False, broker=False, req=None):
        self.enable_init = enable_init
        self.isalive = True
        self.level = level
        self.conflare = conflare
        self.broker = broker
        self.req = req

    def recv(self):
        return self.c.recv()

    def poll(self, timeout: int):
        return self.c.poll(timeout)

    def send(self, msg: Msg):
        return self.c.send(msg)

    @abstractmethod
    def loop(self):
        pass

    def setup(self):
        self.base_setup()
        self.custom_setup()

    def custom_setup(self):
        pass

    def base_setup(self):
        FORMAT = '[%(asctime)s] p%(process)s {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s'
        FORMAT = '"%(pathname)s:%(lineno)d" [%(asctime)s.%(msecs)03d] %(levelname)s - %(message)s'
        logging.basicConfig(level=self.level, format=FORMAT, datefmt='%Y-%m-%d %H:%M:%S', )
        rootLogger = logging.getLogger()

        logFormatter = logging.Formatter(FORMAT, datefmt='%Y-%m-%d %H:%M:%S', )

        log_file = flandre.C.log_folder / datetime.datetime.today().strftime('%Y-%m-%d.log')
        fileHandler = logging.FileHandler(log_file)
        fileHandler.setFormatter(logFormatter)
        rootLogger.addHandler(fileHandler)

        # consoleHandler = logging.StreamHandler()
        # consoleHandler.setFormatter(logFormatter)
        # rootLogger.addHandler(consoleHandler)

        self.context = zmq.Context()
        if self.enable_init:
            self.c = BusClient(*([KillMsg, Msg1, Msg2] + self.topics),
                               poller=True, conflare=self.conflare, req_socket_str=self.req)

    def __call__(self, *args, **kwargs):
        assert 'software_config' in kwargs, self.__class__
        flandre.C.copy_form(kwargs['software_config'])
        self.setup()
        if not self.broker:
            while True:
                msg = self.poll(100)
                if msg is not None:
                    break
            while True:
                self.send(NodeOnlineMsg(self.__class__.__name__))
                msg = self.recv()
                if isinstance(msg, Msg1):
                    break
        self.loop()
        print(self.__class__.__name__, 'exiting')
