#!/usr/bin/env python
#
# Copyright 2017 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""
A gateway between the internal event bus and the Kafka publisher proxy
to publish select topics and messages posted to the Voltha-internal event
bus toward the external world.
"""
from __future__ import absolute_import
import structlog
from google.protobuf.json_format import MessageToDict
from google.protobuf.message import Message
from simplejson import dumps

from pyvoltha.common.event_bus import EventBusClient
import six

log = structlog.get_logger()


class EventBusPublisher(object):

    def __init__(self, kafka_proxy, config):
        self.kafka_proxy = kafka_proxy
        self.config = config
        self.topic_mappings = config.get('topic_mappings', {})
        self.event_bus = EventBusClient()
        self.subscriptions = None

    def start(self):
        log.debug('starting')
        self.subscriptions = list()
        self._setup_subscriptions(self.topic_mappings)
        log.info('started')
        return self

    def stop(self):
        try:
            log.debug('stopping-event-bus')
            if self.subscriptions:
                for subscription in self.subscriptions:
                    self.event_bus.unsubscribe(subscription)
            log.info('stopped-event-bus')
        except Exception as e:
            log.exception('failed-stopping-event-bus', e=e)
            return

    def _setup_subscriptions(self, mappings):

        for event_bus_topic, mapping in six.iteritems(mappings):

            kafka_topic = mapping.get('kafka_topic', None)

            if kafka_topic is None:
                log.error('no-kafka-topic-in-config',
                          event_bus_topic=event_bus_topic,
                          mapping=mapping)
                continue

            self.subscriptions.append(self.event_bus.subscribe(
                event_bus_topic,
                # to avoid Python late-binding to the last registered
                # kafka_topic, we force instant binding with the default arg
                lambda _, m, k=kafka_topic: self.forward(k, m)))

            log.info('event-to-kafka', kafka_topic=kafka_topic,
                     event_bus_topic=event_bus_topic)

    def forward(self, kafka_topic, msg):
        try:
            # convert to JSON string if msg is a protobuf msg
            if isinstance(msg, Message):
                msg = dumps(MessageToDict(msg, True, True))
            log.debug('forward-event-bus-publisher')
            self.kafka_proxy.send_message(kafka_topic, msg)
        except Exception as e:
            log.exception('failed-forward-event-bus-publisher', e=e)

