#
# 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, rpc):
        """
        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.
        :param rpc: The application level stub on which RPC calls
          are made as result of processing incoming OpenFlow request messages.
        """
        self.datapath_id = datapath_id
        self.device_id = device_id
        self.agent = agent
        self.cxn = cxn
        self.rpc = rpc
        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):
        device_info = yield self.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):
        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 self.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)
        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 self.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)
        try:
            meters = yield self.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):
        if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
           yield self.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):
        if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
           self.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):
        if self.role == ofp.OFPCR_ROLE_MASTER or self.role == ofp.OFPCR_ROLE_EQUAL:
            port = yield self.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:
                    self.rpc.disable_port(self.device_id, port.id)
                else:
                    self.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):
        device_info = yield self.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):
        try:
            flow_stats = yield self.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):
        group_stats = yield self.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):
        group_stats = yield self.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):
        try:
            ports = yield self.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):
        port_list = yield self.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))
