import socket
import logging
import select
import time

logger = logging.getLogger("backseat")


class UdpBase:

    def __init__(self, ip, port):

        self.server_address = (ip, port)
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def close(self):
        logger.info('Closing UDP socket {}:{}.'.format(*self.server_address))
        self.sock.close()


class UdpPublisher(UdpBase):

    def __init__(self, ip='localhost', port=5556):

        # Create a UDP socket
        super().__init__(ip, port)
        logger.info('Creating a UDP publisher on {}:{}.'.format(*self.server_address))

    def send(self, msg):
        try:
            return self.sock.sendto(msg.encode(), self.server_address)
        except OSError as e:
            logger.error(f'Failed to send msg: {e}')


class UdpListener(UdpBase):

    def __init__(self, ip='localhost', port=5556):

        # Create a UDP socket
        super().__init__(ip, port)
        logger.info('Creating a UDP listener on {}:{}.'.format(*self.server_address))

        # Bind the socket to the port
        self.sock.bind(self.server_address)
        self.handle_time = None


    def listen(self, timeout_sec=1.0):

        # listen for incoming UDP messages w/ timeout
        rfds, wfds, efds = select.select([self.sock.fileno()], [], [], timeout_sec)

        if rfds:
            # handle message in queue
            data, server = self.sock.recvfrom(4096)

            logger.info('UDP listener received: {}.'.format(data.decode("utf-8")))
            self.handle_time = time.time()
            return data
        else:
            logger.debug("UDP listener timed out...")
            return None
