"""
Handles connections to various serial objects.
This is to ensure that a single serial connection
can stay running and not interfere with other
threads.

| author     = "Seth Miers"
| copyright  = "Copyright, Xilinx Inc. All rights reserved."
| credits    = ["Seth Miers"]
| license    = "GPL"
| version    = "3.0"
| maintainer = "Seth Miers"
| email      = "sethm@xilinx.com"
| status     = "Development"


"""

##########################################
#               Imports                  #
##########################################

# --------------Packages---------------- #
import serial       # for stopbit recognition

# --------------Local------------------- #
import serialcomm   # for each serial object

##########################################
#              Main Code                 #
##########################################


class SerialManager():
    '''
    A dictionary is created that keeps track
    of all open serial ports. When a thread wants
    to connect to a serial port, it firsts queries
    the serial manager so that we don't have 2
    threads trying to connect to the same serial
    port at one time.

    Args:
        logger (logging): The logger that is used

    Attributes:
        serial_comms (dict): A dictionary of all the
            serial connections currently being used.

    TODO:
        * Add in lock conditions so a serial port cannot
          be changed
    '''
    # pylint: disable=too-few-public-methods
    # More methods to be added in the future
    def __init__(self, logger):
        self.logger = logger
        self.serial_comms = dict()

    def get_serial_comm(self, timeout=30,
                        port_regex="", baud=115200,
                        stopbits=serial.STOPBITS_ONE):
        '''
        This method is used to request a connection to a
        serial port based on the input arguments. If any
        of the parameters are different, such as baud rate,
        the serial port is forcibly stopped and restarted
        with the given parameters.

        Args:
            timeout (int): How long the serial port should block
                before returning a timeout
            port_regex (string): The regular expression
                used to connect to a particular com/tty serial port
            baud (int): The baud rate of this serial connection.
            stopbits (int): How many stop bits this serial
                connection should use.

        Attributes:
            port: the port that matches the regex
            serial_comm (SerialComm): the serial comm that will be returned
        '''

        port = serialcomm.SerialComm.find_port(self.logger, port_regex).device

        serial_comm = None
        if port in self.serial_comms.keys():
            serial_comm = self.serial_comms.get(port, None)
            if serial_comm.timeout != timeout:
                serial_comm.set_timeout(timeout)
            if serial_comm.stop:
                self.serial_comms.pop(port, None)
                serial_comm = None
            elif (serial_comm.baud != baud) or \
                 (serial_comm.stopbits != stopbits):
                serial_comm.stop_serial()
                serial_comm = None

        if serial_comm is None:
            serial_comm = serialcomm.SerialComm(self.logger, timeout,
                                                port_regex, baud, stopbits)
            serial_comm.start_serial()
            self.serial_comms.update({port: serial_comm})

        return serial_comm
