# coding=utf-8

"""
Output the collected values to RabitMQ Topic Exchange
This allows for 'subscribing' to messages based on the routing key, which is
the metric path
"""

from diamond.handler.Handler import Handler

try:
    import pika
except ImportError:
    pika = None


class rmqHandler(Handler):
    """
    Implements the abstract Handler class
    Sending data to a RabbitMQ topic exchange.
    The routing key will be the full name of the metric being sent.

    Based on the rmqHandler and zmpqHandler code.
    """

    def __init__(self, config=None):
        """
        Create a new instance of rmqHandler class
        """

        # Initialize Handler
        Handler.__init__(self, config)

        # Initialize Data
        self.connection = None
        self.channel = None

        # Initialize Options
        self.server = self.config.get("server", "127.0.0.1")
        self.port = int(self.config.get("port", 5672))
        self.topic_exchange = self.config.get("topic_exchange", "diamond")
        self.vhost = self.config.get("vhost", "")
        self.user = self.config.get("user", "guest")
        self.password = self.config.get("password", "guest")
        self.routing_key = self.config.get("routing_key", "metric")
        self.custom_routing_key = self.config.get("custom_routing_key", "diamond")

        if not pika:
            self.log.error("pika import failed. Handler disabled")
            self.enabled = False
            return

        # Create rabbitMQ topic exchange and bind
        try:
            self._bind()
        except pika.exceptions.AMQPConnectionError:
            self.log.error("Failed to bind to rabbitMQ topic exchange")

    def get_default_config_help(self):
        """
        Returns the help text for the configuration options for this handler
        """
        config = super(rmqHandler, self).get_default_config_help()

        config.update(
            {
                "server": "",
                "topic_exchange": "",
                "vhost": "",
                "user": "",
                "password": "",
                "routing_key": "",
                "custom_routing_key": "",
            }
        )

        return config

    def get_default_config(self):
        """
        Return the default config for the handler
        """
        config = super(rmqHandler, self).get_default_config()

        config.update(
            {
                "server": "127.0.0.1",
                "topic_exchange": "diamond",
                "vhost": "/",
                "user": "guest",
                "password": "guest",
                "port": "5672",
            }
        )

        return config

    def _bind(self):
        """
        Create  socket and bind
        """

        credentials = pika.PlainCredentials(self.user, self.password)
        params = pika.ConnectionParameters(
            credentials=credentials,
            host=self.server,
            virtual_host=self.vhost,
            port=self.port,
        )

        self.connection = pika.BlockingConnection(params)
        self.channel = self.connection.channel()

        # NOTE : PIKA version uses 'exchange_type' instead of 'type'

        self.channel.exchange_declare(
            exchange=self.topic_exchange, exchange_type="topic"
        )

    def __del__(self):
        """
        Destroy instance of the rmqHandler class
        """
        try:
            self.connection.close()
        except AttributeError:
            pass

    def process(self, metric):
        """
        Process a metric and send it to RabbitMQ topic exchange
        """

        # Send the data as ......
        if not pika:
            return

        routing_key_dic = {
            "metric": lambda: metric.path,
            "custom": lambda: self.custom_routing_key,
            # These option and the below are really not needed because
            #  with Rabbitmq you can use regular expressions to indicate
            #  what routing_keys to subscribe to. But I figure this is
            #  a good example of how to allow more routing keys
            "host": lambda: metric.host,
            "metric.path": metric.getMetricPath,
            "path.prefix": metric.getPathPrefix,
            "collector.path": metric.getCollectorPath,
        }

        try:
            self.channel.basic_publish(
                exchange=self.topic_exchange,
                routing_key=routing_key_dic[self.routing_key](),
                body="%s" % metric,
            )

        except Exception:  # Rough connection re-try logic.
            self.log.info("Failed publishing to rabbitMQ. Attempting reconnect")
            self._bind()
