"""
Handles connections to various ethernet objects.
This is to ensure that a single ethernet 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"
| maintainer = "Seth Miers"
| email      = "sethm@xilinx.com"
| status     = "Development"

"""

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

# --------------Packages---------------- #

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

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


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

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

    Attributes:
        ethernet_comms (dict): A dictionary of all the
            serial connections currently being used.
    '''
    # pylint: disable=too-few-public-methods
    # More methods to be added in the future
    def __init__(self, logger):
        self.logger = logger
        self.ethernet_comms = dict()

    def get_ethernet_comm(self, max_number_of_connections,
                          broadcast_port, connection_port,
                          client_or_server):
        '''
        This method is used to request a connection to a
        tcp/udp port, where udp is used for broadcasts
        and discovery, and tcp is the conneciton.
        If the broadcast_port and connection_port are the
        same as an existing ethernet_comm then this
        function will return that ethernet_comm.
        If client_or_server is not the same, a new
        ethernetcomm will also be returned.
        If the max_number_of_connections is not equal
        to the current, then a warning will be returned.
        If the broadcast_port or connection_port are different
        then this function will create a new ethernet_comm
        and return that.

        Args:
            max_number_of_connections (int): How many clients that can
                connect to this tcp port.
            broadcast_port (string): The port number for the udp broadcast
            connection_port (int): The port number for the tcp connection

        Attributes:
            port: the port that matches the regex
            ethernet_comm (EthernetComm): the ethernet comm that will be returned
        '''

        if client_or_server not in ['client', 'server']:
            self.logger.warning("The client_or_server variable was not " +
                                "set to 'client' or 'server' " +
                                "defaulting to 'client'")
            client_or_server = 'client'

        port = (broadcast_port, connection_port, client_or_server)

        ethernet_comm = None
        if port in self.ethernet_comms.keys():
            ethernet_comm = self.ethernet_comms.get(port)
            if ethernet_comm.max_number_of_connections != \
                    max_number_of_connections:
                self.logger.warning("The max_number_of_connections" +
                                    " does not equal the requested value.")
            if ethernet_comm.stop:
                self.ethernet_comms.pop(port)
                ethernet_comm = None

        if ethernet_comm is None:
            ethernet_comm = \
                    ethernetcomm.EthernetComm(self.logger,
                                              max_number_of_connections,
                                              broadcast_port,
                                              connection_port)
            if client_or_server == 'server':
                ethernet_comm.start_server()
            else:
                ethernet_comm.start_client()
            self.ethernet_comms.update({port: ethernet_comm})

        return ethernet_comm
