#!/usr/bin/python2

# Dennis Heinze

import binascii
import struct

from pwnlib import log

from internalblue.utils.packing import p16


class L2CAPManager:
    def __init__(self, btconn, mtu=0x30):
        self.connection = btconn

        self.connection.registerACLHandler(self._receptionHandler)

        # cidHandlers is a map from CID -> function array
        self.cidHandlers = {}
        self.handlers = []
        self.mtu = mtu

    def sendData(self, data, cid):
        data_len = len(data)
        # if data_len > mtu
        log.debug("Sent L2CAP data to channel: %d, data: %s", cid, binascii.hexlify(data))
        self.connection.sendACL(p16(data_len) + p16(cid) + data)

    def registerHandler(self, handler):
        self.handlers.append(handler)
        log.debug("Registered L2CAP handler")

    def registerCIDHandler(self, handler, cid):
        if cid not in self.cidHandlers:
            self.cidHandlers[cid] = []

        self.cidHandlers[cid].append(handler)
        log.debug("Registered L2CAP handler for CID %d", cid)

    def _receptionHandler(self, data):
        if len(data) > 5:
            l2cap_data = data[5:]
        else:
            log.debug("Received invalid L2CAP data at handler: %s", data)
            return

        # prioritize specific CID handlers
        (length, cid) = struct.unpack_from("hh", l2cap_data)
        log.debug("Received L2CAP data for cid: %d, %s", cid, binascii.hexlify(l2cap_data))
        if cid in self.cidHandlers:
            for handler in self.cidHandlers[cid]:
                handler(l2cap_data[4:])

        for handler in self.handlers:
            handler(l2cap_data[4:])


class L2CAPSignalChannel:
    def __init__(self, chanman):
        self.chanman = chanman
        self.chanman.registerCIDHandler(0x01, self._receptionHandler)

    def sendCFrameRaw(self, code, identifier, length, data):
        self.chanman.sendData(code + identifier + length + data)

    def sendCFrame(self, code, identifier, data):
        data_len = len(data) / 2
        self.sendCFrameRaw(code, identifier, p16(data_len), data)

    def _receptionHandler(self, data):
        pass
