import math
import struct

from .. import helpers


def bind(uuid, version):
    """
    Generate the data necessary to bind to the specified interface.
    """

    major, minor = version.split(".")

    major = struct.pack("<H", int(major))
    minor = struct.pack("<H", int(minor))

    bind_request = b"\x05\x00"  # version 5.0
    bind_request += b"\x0b"  # packet type = bind (11)
    bind_request += b"\x03"  # packet flags = last/first flag set
    bind_request += b"\x10\x00\x00\x00"  # data representation
    bind_request += b"\x48\x00"  # frag length: 72
    bind_request += b"\x00\x00"  # auth length
    bind_request += b"\x00\x00\x00\x00"  # call id
    bind_request += b"\xb8\x10"  # max transmit frag (4280)
    bind_request += b"\xb8\x10"  # max recv frag (4280)
    bind_request += b"\x00\x00\x00\x00"  # assoc group
    bind_request += b"\x01"  # number of ctx items (1)
    bind_request += b"\x00\x00\x00"  # padding
    bind_request += b"\x00\x00"  # context id (0)
    bind_request += b"\x01"  # number of trans items (1)
    bind_request += b"\x00"  # padding
    bind_request += helpers.uuid_str_to_bin(uuid)  # abstract syntax
    bind_request += major  # interface version
    bind_request += minor  # interface version minor

    # transfer syntax 8a885d04-1ceb-11c9-9fe8-08002b104860 v2.0
    bind_request += b"\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60"
    bind_request += b"\x02\x00\x00\x00"

    return bind_request


def bind_ack(data):
    """
    Ensure the data is a bind ack and that the
    """

    # packet type == bind ack (12)?
    if data[2] != b"\x0c":
        return False

    # ack result == acceptance?
    if data[36:38] != b"\x00\x00":
        return False

    return True


def request(opnum, data):
    """
    Return a list of packets broken into 5k fragmented chunks necessary to make the RPC request.
    """

    frag_size = 1000  # max frag size = 5840?
    frags = []

    num_frags = int(math.ceil(float(len(data)) / float(frag_size)))

    for i in range(num_frags):
        chunk = data[i * frag_size : (i + 1) * frag_size]
        frag_length = struct.pack("<H", len(chunk) + 24)
        alloc_hint = struct.pack("<L", len(chunk))

        flags = 0
        if i == 0:
            flags |= 0x1  # first frag
        if i == num_frags - 1:
            flags |= 0x2  # last frag

        request_buffer = b"\x05\x00"  # version 5.0
        request_buffer += b"\x00"  # packet type = request (0)
        request_buffer += struct.pack("B", flags)  # packet flags
        request_buffer += b"\x10\x00\x00\x00"  # data representation
        request_buffer += frag_length  # frag length
        request_buffer += b"\x00\x00"  # auth length
        request_buffer += b"\x00\x00\x00\x00"  # call id
        request_buffer += alloc_hint  # alloc hint
        request_buffer += b"\x00\x00"  # context id (0)
        request_buffer += struct.pack("<H", opnum)  # opnum
        request_buffer += chunk

        frags.append(request_buffer)

    # you don't have to send chunks out individually. so make life easier for the user and send them all at once.
    return b"".join(frags)
