#
# frm_payload: appnonce(3) netid(3) devaddr(4) dlsettings(1) rxdelay(1) cflist(0..16)
#
from .MalformedPacketException import MalformedPacketException
from .AES_CMAC import AES_CMAC
import ucryptolib
MODE_ECB = 1

class JoinAcceptPayload:

    def read(self, payload):
        if len(payload) < 12:
            raise MalformedPacketException("Invalid join accept")
        self.encrypted_payload = payload

    def create(self, args):
        pass

    def length(self):
        return len(self.encrypted_payload)

    def to_raw(self):
        return self.encrypted_payload

    def to_clear_raw(self):
        return self.payload

    def get_appnonce(self):
        return self.appnonce

    def get_netid(self):
        return self.netid

    def get_devaddr(self):
        return list(map(int, reversed(self.devaddr)))

    def get_dlsettings(self):
        return self.dlsettings

    def get_rxdelay(self):
        return self.rxdelay

    def get_cflist(self):
        return self.cflist

    def compute_mic(self, key, direction, mhdr):
        mic = []
        mic += [mhdr.to_raw()]
        mic += self.to_clear_raw()

        cmac = AES_CMAC()
        computed_mic = cmac.encode(bytes(key), bytes(mic))[:4]
        return list(map(int, computed_mic))

    def decrypt_payload(self, key, direction, mic):
        a = []
        a += self.encrypted_payload
        a += mic

        cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
        self.payload = cipher.encrypt(bytes(a))[:-4]

        self.appnonce = self.payload[:3]
        self.netid = self.payload[3:6]
        self.devaddr = self.payload[6:10]
        self.dlsettings = self.payload[10]
        self.rxdelay = self.payload[11]
        self.cflist = None
        if self.payload[12:]:
            self.cflist = self.payload[12:]

        return list(map(int, self.payload))

    def encrypt_payload(self, key, direction, mhdr):
        a = []
        a += self.to_clear_raw()
        a += self.compute_mic(key, direction, mhdr)

        cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
        return list(map(int, cipher.decrypt(bytes(a))))

    def derive_nwskey(self, key, devnonce):
        a = [0x01]
        a += self.get_appnonce()
        a += self.get_netid()
        a += devnonce
        a += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

        cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
        return list(map(int, cipher.encrypt(bytes(a))))

    def derive_appskey(self, key, devnonce):
        a = [0x02]
        a += self.get_appnonce()
        a += self.get_netid()
        a += devnonce
        a += [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

        cipher = ucryptolib.aes(bytearray(key), MODE_ECB)
        return list(map(int, cipher.encrypt(bytes(a))))
