"""Ethernet Flow Control"""
from packetracer import packetracer, triggerlist
from packetracer.structcbs import pack_H, unpack_H

PAUSE_OPCODE = 0x0001  # Pause frame IEEE 802.3x
PFC_OPCODE = 0x0101  # Priority Flow Control IEEE 802.1Qbb


class FlowControl(packetracer.Packet):
    __hdr__ = (
        ("opcode", "H", PAUSE_OPCODE),
    )

    def _dissect(self, buf):
        if buf[:2] == b"\x01\x01":
            self._init_handler(PFC_OPCODE, buf[2:])
        else:
            self._init_handler(PAUSE_OPCODE, buf[2:])
        return 2

    class Pause(packetracer.Packet):
        __hdr__ = (
            ("ptime", "H", 0x0000),
        )

    class PFC(packetracer.Packet):
        __hdr__ = (
            ("ms", "B", 0),  # most significant octet is reserved,set to zero
            ("ls", "B", 0),  # least significant octet indicates time_vector parameter
            ("time", None, triggerlist.TriggerList),
        )

        # Conveniant access to ls field(bit representation via list)
        # e.g. 221 -> [1, 1, 0, 1, 1, 1, 0, 1]
        def __get_ls(self):
            # return [(self.ls >> x) & 1 for x in reversed(range(8))]
            return [int(bstr) for bstr in bin(self.ls)[2:]]

        # e.g. [1, 1, 0, 1, 1, 1, 0, 1] -> 221
        def __set_ls(self, value):
            # self.ls = int("".join(map(str, value)), 2)
            self.ls = int("".join(["%d" % bint for bint in value]), 2)

        ls_list = property(__get_ls, __set_ls)

        # Conveniant access to time field(decimal representation via list)
        def __get_time(self):
            return [unpack_H(x)[0] for x in self.time]

        def __set_time(self, value):
            self.time = [pack_H(x) for x in value]

        time_list = property(__get_time, __set_time)

        def _dissect(self, buf):
            for i in range(2, 18, 2):
                self.time.append(buf[i:i + 2])
            # TODO: find more efficient way, always correct?
            return 2 + len(self.time) * 2

    __handler__ = {
        PAUSE_OPCODE: Pause,
        PFC_OPCODE: PFC
    }
