import re
from enum import Enum


class AmqpElementConfiguration:
    """
    Clase base de configuracion de un elemento amqp
    como un exchange o una cola
    """
    def __init__(self):
        self.name = None
        self.create = True


class ExhangeType(Enum):
    DIRECT = "direct"
    TOPIC = "topic"


class ExchangeConfiguration(AmqpElementConfiguration):
    """
    Configuracion de un exchange
    """
    def __init__(self):
        AmqpElementConfiguration.__init__(self)
        self.type = ExhangeType.TOPIC

    def set_exchange_direct(self):
        """
        Establece el exchange de tipo direct
        """
        self.type = ExhangeType.DIRECT

    def set_exchange_topic(self):
        """
        Establece el exchange de tipo topic
        """
        self.type = ExhangeType.TOPIC


class QueueConfiguration(AmqpElementConfiguration):
    """
    Configuracion de una cola
    """
    def __init__(self):
        AmqpElementConfiguration.__init__(self)
        self._routingKeys = list()

    def add_routing_key(self, key):
        """
        Añade una clave de enrutamiento de la cola amqp
        :param key: Clave de enrutamiento
        """
        self._routingKeys.append(key)

    def get_routing_keys(self) -> list:
        """
        Devuelve la lista de claves de enrutamiento de la cola
        :return: Lista de claves
        :rtype: list
        """
        return self._routingKeys


class ConnectionParameters:
    """
    Contiene los parametros de conexion al servidor AMQP
    """
    @classmethod
    def create_from_uri(cls, uri: str):
        """
        Factory Method, crea extrae los parametros de la conexion a partir
        de una uri amqp://guest:guest@localhost:5672/
        :param uri: Url de conexion a AMQP
        :return: Propiedades de la conexion
        :rtype: clitellum.channels.configuration.ConnectionParameters
        """
        params = ConnectionParameters()
        m = re.search('^amqp:\/\/((\w*):(\w*))?@?(([\w\.]*)(:(\d*))?)\/([\w%]*)', uri)
        params.host = m.group(5)

        if m.group(7) is not None and m.group(7) is not '':
            params.port = int(m.group(7))

        if m.group(2) is not None and m.group(2) is not '':
            params.userid = m.group(2)

        if m.group(3) is not None and m.group(3) is not '':
            params.password = m.group(3)

        if m.group(8) is not None and m.group(8) is not '':
            params.virtual_host = m.group(8)

        return params

    def __init__(self):
        self.host = 'localhost'
        self.userid = 'guest'
        self.password = 'guest'
        self.login_method = 'AMQPLAIN'
        self.virtual_host = '/'
        self.port = 5672


class ChannelConfiguration:
    """
    Congiguracion de un canal de comunicacion amqp
    """
    def __init__(self):
        self.uri = None
        self.exchange = ExchangeConfiguration()
        self.queue = QueueConfiguration()
        self.max_threads = 4

    def get_connection_parameters(self) -> ConnectionParameters:
        """
        Devuelve los parametros de la conexion
        :return: Parametros de la conexion
        :rtype: clitellum.channels.configuration.ConnectionParameters
        """
        return ConnectionParameters.create_from_uri(self.uri)
