#
# Copyright 2016 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.
#

"""
Simple PON Simulator which would not be needed if openvswitch could do
802.1ad (QinQ), which it cannot (the reason is beyond me), or if CPQD could
handle 0-tagged packets (no comment).
"""
import structlog
from scapy.layers.inet import IP, UDP
from scapy.layers.l2 import Ether, Dot1Q
from scapy.packet import Packet

from voltha.protos import third_party
from voltha.protos.ponsim_pb2 import PonSimMetrics, PonSimPortMetrics, \
    PonSimPacketCounter
from voltha.core.flow_decomposer import *
from twisted.internet.task import LoopingCall

_ = third_party


def ipv4int2str(ipv4int):
    return '{}.{}.{}.{}'.format(
        (ipv4int >> 24) & 0xff,
        (ipv4int >> 16) & 0xff,
        (ipv4int >> 8) & 0xff,
        ipv4int & 0xff
    )


class _FlowMatchMask(object):
    """
    Enum of mask values based on flow match priority. For instance, a port
    match has higher priority when match that a UDP match.
    """
    UDP_DST = 1
    UDP_SRC = 2
    IPV4_DST = 4
    VLAN_PCP = 8
    VLAN_VID = 16
    IP_PROTO = 34
    ETH_TYPE = 64
    IN_PORT = 128


class FrameIOCounter(object):
    class SingleFrameCounter(object):
        def __init__(self, name, min, max):
            # Currently there are 2 values, one for the PON interface (port 1)
            # and one for the Network Interface (port 2). This can be extended if
            # the virtual devices extend the number of ports. 
            self.value = [0, 0]  # {PON,NI}
            self.name = name
            self.min = min
            self.max = max

    def __init__(self, device):
        self.device = device
        self.tx_counters = dict(
            tx_64=self.SingleFrameCounter("tx_64", 1, 64),
            tx_65_127=self.SingleFrameCounter("tx_65_127", 65, 127),
            tx_128_255=self.SingleFrameCounter("tx_128_255", 128, 255),
            tx_256_511=self.SingleFrameCounter("tx_256_511", 256, 511),
            tx_512_1023=self.SingleFrameCounter("tx_512_1023", 512, 1024),
            tx_1024_1518=self.SingleFrameCounter("tx_1024_1518", 1024, 1518),
            tx_1519_9k=self.SingleFrameCounter("tx_1519_9k", 1519, 9216),
        )
        self.rx_counters = dict(
            rx_64=self.SingleFrameCounter("rx_64", 1, 64),
            rx_65_127=self.SingleFrameCounter("rx_65_127", 65, 127),
            rx_128_255=self.SingleFrameCounter("rx_128_255", 128, 255),
            rx_256_511=self.SingleFrameCounter("rx_256_511", 256, 511),
            rx_512_1023=self.SingleFrameCounter("rx_512_1023", 512, 1024),
            rx_1024_1518=self.SingleFrameCounter("rx_1024_1518", 1024, 1518),
            rx_1519_9k=self.SingleFrameCounter("rx_1519_9k", 1519, 9216)
        )

    def count_rx_frame(self, port, size):
        log.info("counting-rx-frame", size=size, port=port)
        for k, v in self.rx_counters.iteritems():
            if size >= v.min and size <= v.max:
                self.rx_counters[k].value[port - 1] += 1
                return
        log.warn("unsupported-packet-size", size=size)

    def count_tx_frame(self, port, size):
        for k, v in self.tx_counters.iteritems():
            if size >= v.min and size <= v.max:
                self.tx_counters[k].value[port - 1] += 1
                return
        log.warn("unsupported-packet-size", size=size)

    def log_counts(self):
        rx_ct_list = [(v.name, v.value[0], v.value[1]) for v in
                      self.rx_counters.values()]
        tx_ct_list = [(v.name, v.value[0], v.value[1]) for v in
                      self.tx_counters.values()]
        log.info("rx-counts", rx_ct_list=rx_ct_list)
        log.info("tx-counts", tx_ct_list=tx_ct_list)

    def make_proto(self):
        sim_metrics = PonSimMetrics(
            device=self.device
        )
        pon_port_metrics = PonSimPortMetrics(
            port_name="pon"
        )
        ni_port_metrics = PonSimPortMetrics(
            port_name="nni"
        )
        for c in sorted(self.rx_counters):
            ctr = self.rx_counters[c]
            pon_port_metrics.packets.extend([
                PonSimPacketCounter(name=ctr.name, value=ctr.value[0])
            ])
            # Since they're identical keys, save some time and cheat
            ni_port_metrics.packets.extend([
                PonSimPacketCounter(name=ctr.name, value=ctr.value[1])
            ])

        for c in sorted(self.tx_counters):
            ctr = self.tx_counters[c]
            pon_port_metrics.packets.extend([
                PonSimPacketCounter(name=ctr.name, value=ctr.value[0])
            ])
            # Since they're identical keys, save some time and cheat
            ni_port_metrics.packets.extend([
                PonSimPacketCounter(name=ctr.name, value=ctr.value[1])
            ])
        sim_metrics.metrics.extend([pon_port_metrics])
        sim_metrics.metrics.extend([ni_port_metrics])

        return sim_metrics


class SimDevice(object):
    def __init__(self, name, logical_port_no):
        self.name = name
        self.logical_port_no = logical_port_no
        self.links = dict()
        self.flows = list()
        self.log = structlog.get_logger(name=name,
                                        logical_port_no=logical_port_no)
        self.counter = FrameIOCounter(name)

    def link(self, port, egress_fun):
        self.links.setdefault(port, []).append(egress_fun)

    def ingress(self, port, frame):
        self.log.debug('ingress', ingress_port=port, name=self.name)
        self.counter.count_rx_frame(port, len(frame["Ether"].payload))
        outcome = self.process_frame(port, frame)
        if outcome is not None:
            egress_port, egress_frame = outcome
            forwarded = 0
            links = self.links.get(egress_port)
            if links is not None:
                self.counter.count_tx_frame(egress_port,
                                            len(egress_frame["Ether"].payload))
                for fun in links:
                    forwarded += 1
                    self.log.debug('forwarding', egress_port=egress_port)
                    fun(egress_port, egress_frame)
            if not forwarded:
                self.log.debug('no-one-to-forward-to', egress_port=egress_port)
        else:
            self.log.debug('dropped')

    def install_flows(self, flows):
        # store flows in precedence order so we can roll down on frame arrival
        self.flows = sorted(flows, key=lambda fm: fm.priority, reverse=True)

    def process_frame(self, ingress_port, ingress_frame):
        matched_mask = 0
        matched_flow = None
        for flow in self.flows:
            current_mask = self.is_match(flow, ingress_port, ingress_frame)
            if current_mask > matched_mask:
                matched_mask = current_mask
                matched_flow = flow

        if matched_flow:
            egress_port, egress_frame = self.process_actions(
                matched_flow, ingress_frame)
            return egress_port, egress_frame
        return None

    @staticmethod
    def is_match(flow, ingress_port, frame):
        matched_mask = 0

        def get_non_shim_ether_type(f):
            if f.haslayer(Dot1Q):
                f = f.getlayer(Dot1Q)
            return f.type

        def get_vlan_pcp(f):
            if f.haslayer(Dot1Q):
                return f.getlayer(Dot1Q).prio

        def get_ip_proto(f):
            if f.haslayer(IP):
                return f.getlayer(IP).proto

        def get_ipv4_dst(f):
            if f.haslayer(IP):
                return f.getlayer(IP).dst

        def get_udp_src(f):
            if f.haslayer(UDP):
                return f.getlayer(UDP).sport

        def get_udp_dst(f):
            if f.haslayer(UDP):
                return f.getlayer(UDP).dport

        for field in get_ofb_fields(flow):

            if field.type == IN_PORT:
                if field.port != ingress_port:
                    return 0
                matched_mask |= _FlowMatchMask.IN_PORT

            elif field.type == ETH_TYPE:
                if field.eth_type != get_non_shim_ether_type(frame):
                    return 0
                matched_mask |= _FlowMatchMask.ETH_TYPE

            elif field.type == IP_PROTO:
                if field.ip_proto != get_ip_proto(frame):
                    return 0
                matched_mask |= _FlowMatchMask.IP_PROTO

            elif field.type == VLAN_VID:
                expected_vlan = field.vlan_vid
                tagged = frame.haslayer(Dot1Q)
                if bool(expected_vlan & 4096) != bool(tagged):
                    return 0
                if tagged:
                    actual_vid = frame.getlayer(Dot1Q).vlan
                    if actual_vid != expected_vlan & 4095:
                        return 0
                matched_mask |= _FlowMatchMask.VLAN_VID

            elif field.type == VLAN_PCP:
                if field.vlan_pcp != get_vlan_pcp(frame):
                    return 0
                matched_mask |= _FlowMatchMask.VLAN_PCP

            elif field.type == IPV4_DST:
                if ipv4int2str(field.ipv4_dst) != get_ipv4_dst(frame):
                    return 0
                matched_mask |= _FlowMatchMask.IPV4_DST

            elif field.type == UDP_SRC:
                if field.udp_src != get_udp_src(frame):
                    return 0
                matched_mask |= _FlowMatchMask.UDP_SRC

            elif field.type == UDP_DST:
                if field.udp_dst != get_udp_dst(frame):
                    return 0
                matched_mask |= _FlowMatchMask.UDP_DST

            elif field.type == METADATA:
                pass  # safe to ignore

            else:
                raise NotImplementedError('field.type=%d' % field.type)

        return matched_mask

    @staticmethod
    def process_actions(flow, frame):
        egress_port = None
        for action in get_actions(flow):

            if action.type == OUTPUT:
                egress_port = action.output.port

            elif action.type == POP_VLAN:
                if frame.haslayer(Dot1Q):
                    shim = frame.getlayer(Dot1Q)
                    frame = Ether(
                        src=frame.src,
                        dst=frame.dst,
                        type=shim.type) / shim.payload

            elif action.type == PUSH_VLAN:
                frame = (
                    Ether(src=frame.src, dst=frame.dst,
                          type=action.push.ethertype) /
                    Dot1Q(type=frame.type) /
                    frame.payload
                )

            elif action.type == SET_FIELD:
                assert (action.set_field.field.oxm_class ==
                        ofp.OFPXMC_OPENFLOW_BASIC)
                field = action.set_field.field.ofb_field

                if field.type == VLAN_VID:
                    shim = frame.getlayer(Dot1Q)
                    shim.vlan = field.vlan_vid & 4095

                elif field.type == VLAN_PCP:
                    shim = frame.getlayer(Dot1Q)
                    shim.prio = field.vlan_pcp

                else:
                    raise NotImplementedError('set_field.field.type=%d'
                                              % field.type)

            else:
                raise NotImplementedError('action.type=%d' % action.type)

        return egress_port, frame


class PonSim(object):
    def __init__(self, onus, egress_fun):
        self.egress_fun = egress_fun

        self.log = structlog.get_logger()
        # Create OLT and hook NNI port up for egress
        self.olt = SimDevice('olt', 0)
        self.olt.link(2, lambda _, frame: self.egress_fun(0, frame))
        self.devices = dict()
        self.devices[0] = self.olt
        # TODO: This can be removed, it's for debugging purposes
        self.lc = LoopingCall(self.olt.counter.log_counts)
        self.lc.start(90)  # To correlate with Kafka

        # Create ONUs of the requested number and hook them up with OLT
        # and with egress fun
        def mk_egress_fun(port_no):
            return lambda _, frame: self.egress_fun(port_no, frame)

        def mk_onu_ingress(onu):
            return lambda _, frame: onu.ingress(1, frame)

        for i in range(onus):
            port_no = 128 + i
            onu = SimDevice('onu%d' % i, port_no)
            onu.link(1, lambda _, frame: self.olt.ingress(1,
                                                          frame))  # Send to the OLT
            onu.link(2,
                     mk_egress_fun(port_no))  # Send from the ONU to the world
            self.olt.link(1, mk_onu_ingress(onu))  # Internal send to the ONU
            self.devices[port_no] = onu
        for d in self.devices:
            self.log.info("pon-sim-init", port=d, name=self.devices[d].name,
                          links=self.devices[d].links)

    def get_ports(self):
        return sorted(self.devices.keys())

    def get_stats(self):
        return self.olt.counter.make_proto()

    def olt_install_flows(self, flows):
        self.olt.install_flows(flows)

    def onu_install_flows(self, onu_port, flows):
        self.devices[onu_port].install_flows(flows)

    def ingress(self, port, frame):
        if not isinstance(frame, Packet):
            frame = Ether(frame)
        self.devices[port].ingress(2, frame)
