#
# 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.
#
import structlog
from twisted.internet.defer import inlineCallbacks, returnValue

import loxi.of13 as ofp
from converter import to_loxi, pb2dict, to_grpc
from binascii import hexlify

log = structlog.get_logger()


class OpenFlowProtocolError(Exception): pass


class OpenFlowProtocolHandler(object):

    ofp_version = [4]  # OFAgent supported versions

    MAX_METER_IDS = 4294967295
    MAX_METER_BANDS = 255
    MAX_METER_COLORS = 255

    def __init__(self, datapath_id, device_id, agent, cxn):
        """
        The upper half of the OpenFlow protocol, focusing on message
        exchanges.
        :param agent: Reference to the Agent() instance, can be used to
          indicate critical errors to break the connection.
        :param cxn: The lower level message serdes part of the OF protocol.
        """
        self.datapath_id = datapath_id
        self.device_id = device_id
        self.agent = agent
        self.cxn = cxn
        self.role = None

    @inlineCallbacks
    def start(self):
        """A new call is made after a fresh reconnect"""

        log.debug('starting')

        try:
            support = False
            # send initial hello message
            self.cxn.send(ofp.message.hello(elements=[ofp.common.hello_elem_versionbitmap(
                bitmaps = [ofp.common.hello_elem_bitmap(self.ofp_version)])]))
            # expect to receive a hello message
            msg = yield self.cxn.recv_class(ofp.message.hello)
            # supports only ofp_versions till 31 and single bitmap.
            if msg:
                support = ofp.util.verify_version_support(msg,self.ofp_version)
                if not support:
                    self.cxn.send(ofp.message.hello_failed_error_msg(
                        xid=msg.xid, code=ofp.OFPHFC_INCOMPATIBLE,
                        data='i support only 1.3'))
                    log.error('peer-do-not-support-OpenFlow-version',self.ofp_version)

            while support:
                req = yield self.cxn.recv_any()
                handler = self.main_handlers.get(req.type, None)
                if handler:
                    handler(self, req)
                else:
                    log.error('cannot-handle',
                              request=req, xid=req.xid, type=req.type)

        except Exception, e:
            log.exception('exception', e=e)

        log.info('started')
        returnValue(self)

    def stop(self):
        log.debug('stopping')
        pass  # nothing to do yet
        log.info('stopped')

    def handle_echo_request(self, req):
        self.cxn.send(ofp.message.echo_reply(xid=req.xid))

    @inlineCallbacks
    def handle_feature_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            device_info = yield rpc.get_device_info(self.device_id)
            kw = pb2dict(device_info.switch_features)
            self.cxn.send(ofp.message.features_reply(
                xid=req.xid,
                datapath_id=self.datapath_id,
                **kw))

    def handle_stats_request(self, req):
        handler = self.stats_handlers.get(req.stats_type, None)
        if handler:
            handler(self, req)
        else:
            raise OpenFlowProtocolError(
                'Cannot handle stats request type "{}"'.format(req.stats_type))

    def handle_barrier_request(self, req):
        # not really doing barrier yet, but we respond
        # see https://jira.opencord.org/browse/CORD-823
        self.cxn.send(ofp.message.barrier_reply(xid=req.xid))

    def handle_experimenter_request(self, req):
        raise NotImplementedError()

    def handle_flow_mod_request(self, req):
        log.debug('flow mod request')
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
               try:
                  grpc_req = to_grpc(req)
               except Exception, e:
                  log.exception('failed-to-convert', e=e)
               else:
                  return rpc.update_flow_table(self.device_id, grpc_req)

            elif self.role == ofp.OFPCR_ROLE_SLAVE:
               self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPBRC_IS_SLAVE))


    def handle_meter_mod_request(self, req):
        log.info('Received  handle_meter_mod_request', request=req)
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
                try:
                    grpc_req = to_grpc(req)
                except Exception, e:
                    log.exception('failed-to-convert-meter-mod-request', e=e)
                else:
                    return rpc.update_meter_mod_table(self.device_id, grpc_req)

            elif self.role == ofp.OFPCR_ROLE_SLAVE:
                self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPBRC_IS_SLAVE))

    @inlineCallbacks
    def handle_meter_stats_request(self, req):
        log.info('Received  handle_meter_stats_request', request=req)
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            try:
                meters = yield rpc.list_meters(self.device_id)
                self.cxn.send(ofp.message.meter_stats_reply(
                    xid=req.xid, entries=[to_loxi(m.stats) for m in meters]))
            except Exception, e:
                log.exception("failed-meter-stats-request", req=req, e=e)

    def handle_get_async_request(self, req):
        raise NotImplementedError()

    def handle_get_config_request(self, req):
        self.cxn.send(ofp.message.get_config_reply(
            xid=req.xid,
            miss_send_len=ofp.OFPCML_NO_BUFFER
        ))

    @inlineCallbacks
    def handle_group_mod_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
               yield rpc.update_group_table(self.device_id, to_grpc(req))
            elif self.role == ofp.OFPCR_ROLE_SLAVE:
               self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPBRC_IS_SLAVE))

    def handle_role_request(self, req):
        if req.role == ofp.OFPCR_ROLE_MASTER or req.role == ofp.OFPCR_ROLE_SLAVE:
            if self.agent.generation_is_defined and (
                    ((req.generation_id - self.agent.cached_generation_id) & 0xffffffffffffffff) if abs(
                    req.generation_id - self.agent.cached_generation_id) > 0x7fffffffffffffff else (
                    req.generation_id - self.agent.cached_generation_id)) < 0:
                self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPRRFC_STALE))
            else:
                self.agent.generation_is_defined = True
                self.agent.cached_generation_id = req.generation_id
                self.role = req.role
                self.cxn.send(ofp.message.role_reply(
                 xid=req.xid, role=req.role, generation_id=req.generation_id))
        elif req.role == ofp.OFPCR_ROLE_EQUAL:
            self.role = req.role
            self.cxn.send(ofp.message.role_reply(
             xid=req.xid, role=req.role))

    def handle_packet_out_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
               rpc.send_packet_out(self.device_id, to_grpc(req))

            elif self.role == ofp.OFPCR_ROLE_SLAVE:
               self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPBRC_IS_SLAVE))

    def handle_set_config_request(self, req):
        # Handle set config appropriately
        # https://jira.opencord.org/browse/CORD-826
        pass

    @inlineCallbacks
    def handle_port_mod_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
                port = yield rpc.get_port(self.device_id, str(req.port_no))

                if port.ofp_port.config & ofp.OFPPC_PORT_DOWN != \
                        req.config & ofp.OFPPC_PORT_DOWN:
                    if req.config & ofp.OFPPC_PORT_DOWN:
                        rpc.disable_port(self.device_id, port.id)
                    else:
                        rpc.enable_port(self.device_id, port.id)

            elif self.role == ofp.OFPCR_ROLE_SLAVE:
                self.cxn.send(ofp.message.bad_request_error_msg(code=ofp.OFPBRC_IS_SLAVE))

    def handle_table_mod_request(self, req):
        raise NotImplementedError()

    def handle_queue_get_config_request(self, req):
        raise NotImplementedError()

    def handle_set_async_request(self, req):
        raise NotImplementedError()

    def handle_aggregate_request(self, req):
        raise NotImplementedError

    @inlineCallbacks
    def handle_device_description_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            device_info = yield rpc.get_device_info(self.device_id)
            kw = pb2dict(device_info.desc)
            self.cxn.send(ofp.message.desc_stats_reply(xid=req.xid, **kw))

    def handle_experimenter_stats_request(self, req):
        raise NotImplementedError()

    @inlineCallbacks
    def handle_flow_stats_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            try:
                flow_stats = yield rpc.list_flows(self.device_id)
                self.cxn.send(ofp.message.flow_stats_reply(
                    xid=req.xid, entries=[to_loxi(f) for f in flow_stats]))
            except Exception, e:
                log.exception('failed-flow-stats-request', req=req)

    @inlineCallbacks
    def handle_group_stats_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            group_stats = yield rpc.list_groups(self.device_id)
            self.cxn.send(ofp.message.group_stats_reply(
                xid=req.xid, entries=[to_loxi(g.stats) for g  in group_stats]))

    @inlineCallbacks
    def handle_group_descriptor_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            group_stats = yield rpc.list_groups(self.device_id)
            self.cxn.send(ofp.message.group_desc_stats_reply(
                xid=req.xid, entries=[to_loxi(g.desc) for g  in group_stats]))

    def handle_group_features_request(self, req):
        raise NotImplementedError()

    def handle_meter_config_request(self, req):
        raise NotImplementedError()

    def handle_meter_features_request(self, req):
        feature = ofp.meter_features(max_meter=OpenFlowProtocolHandler.MAX_METER_IDS,
                                     band_types=ofp.OFPMBT_DROP,
                                     capabilities=ofp.OFPMF_KBPS,
                                     max_bands=OpenFlowProtocolHandler.MAX_METER_BANDS,
                                     max_color=OpenFlowProtocolHandler.MAX_METER_COLORS)
        self.cxn.send(ofp.message.meter_features_stats_reply(xid=req.xid, flags=None,
                                                             features=feature))

    @inlineCallbacks
    def handle_port_stats_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            try:
                ports = yield rpc.list_ports(self.device_id)
                port_stats = [to_loxi(p.ofp_port_stats) for p in ports]
                of_message = ofp.message.port_stats_reply(
                    xid=req.xid,entries=port_stats)
                self.cxn.send(of_message)
            except:
                log.exception('failed-port_stats-request', req=req)

    @inlineCallbacks
    def handle_port_desc_request(self, req):
        rpc = self.agent.connection_manager.get_rpc_client()
        if rpc is not None:
            port_list = yield rpc.get_port_list(self.device_id)
            try:
                self.cxn.send(ofp.message.port_desc_stats_reply(
                    xid=req.xid,
                    #flags=None,
                    entries=[to_loxi(port.ofp_port) for port in port_list]
                ))
            except Exception as err:
                log.exception('failed-port-desc-reply', err=err)

    def handle_queue_stats_request(self, req):
        raise NotImplementedError()

    def handle_table_stats_request(self, req):
        table_stats = []  # see https://jira.opencord.org/browse/CORD-825
        self.cxn.send(ofp.message.table_stats_reply(
            xid=req.xid, entries=table_stats))

    def handle_table_features_request(self, req):
        raise NotImplementedError()

    stats_handlers = {
        ofp.OFPST_AGGREGATE: handle_aggregate_request,
        ofp.OFPST_DESC: handle_device_description_request,
        ofp.OFPST_EXPERIMENTER: handle_experimenter_stats_request,
        ofp.OFPST_FLOW: handle_flow_stats_request,
        ofp.OFPST_GROUP: handle_group_stats_request,
        ofp.OFPST_GROUP_DESC: handle_group_descriptor_request,
        ofp.OFPST_GROUP_FEATURES: handle_group_features_request,
        ofp.OFPST_METER: handle_meter_stats_request,
        ofp.OFPST_METER_CONFIG: handle_meter_config_request,
        ofp.OFPST_METER_FEATURES: handle_meter_features_request,
        ofp.OFPST_PORT: handle_port_stats_request,
        ofp.OFPST_PORT_DESC: handle_port_desc_request,
        ofp.OFPST_QUEUE: handle_queue_stats_request,
        ofp.OFPST_TABLE: handle_table_stats_request,
        ofp.OFPST_TABLE_FEATURES: handle_table_features_request
    }

    main_handlers = {
        ofp.OFPT_BARRIER_REQUEST: handle_barrier_request,
        ofp.OFPT_ECHO_REQUEST: handle_echo_request,
        ofp.OFPT_FEATURES_REQUEST: handle_feature_request,
        ofp.OFPT_EXPERIMENTER: handle_experimenter_request,
        ofp.OFPT_FLOW_MOD: handle_flow_mod_request,
        ofp.OFPT_GET_ASYNC_REQUEST: handle_get_async_request,
        ofp.OFPT_GET_CONFIG_REQUEST: handle_get_config_request,
        ofp.OFPT_GROUP_MOD: handle_group_mod_request,
        ofp.OFPT_METER_MOD: handle_meter_mod_request,
        ofp.OFPT_PACKET_OUT: handle_packet_out_request,
        ofp.OFPT_PORT_MOD: handle_port_mod_request,
        ofp.OFPT_QUEUE_GET_CONFIG_REQUEST: handle_queue_get_config_request,
        ofp.OFPT_ROLE_REQUEST: handle_role_request,
        ofp.OFPT_SET_ASYNC: handle_set_async_request,
        ofp.OFPT_SET_CONFIG: handle_set_config_request,
        ofp.OFPT_STATS_REQUEST: handle_stats_request,
        ofp.OFPT_TABLE_MOD: handle_table_mod_request,
    }

    def forward_packet_in(self, ofp_packet_in):
        if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
           log.info('sending-packet-in', ofp_packet_in=ofp_packet_in, packet=hexlify(ofp_packet_in.data))
           self.cxn.send(to_loxi(ofp_packet_in))

    def forward_port_status(self, ofp_port_status):
        self.cxn.send(to_loxi(ofp_port_status))
