import time
import socket
import struct
import zlib


def composeMsg(addr_from: tuple, addr_to: tuple,
               msg_type: int,
               data: bytes,
               fmap: dict,
               timestamp=None):
    """
    Compose a message according to protocol, see CARIBIC@350_CommunicationSpecs_Rev0_20210319.
    """
    if timestamp is None:
        timestamp = int(time.time()*1e9)

    # pack message content to binary string
    packet = (socket.inet_aton(addr_from[0]) + struct.pack(fmap['addr_from_port'], addr_from[1]) +
              socket.inet_aton(addr_to[0]) + struct.pack(fmap['addr_to_port'], addr_to[1]) +
              b'\x00\x00' + # place holder bytes for packet length
              struct.pack(fmap['ts'], timestamp) +
              struct.pack(fmap['type'], msg_type) +
              data)

    # insert packet length, including checksum bytes
    packet = packet[:12] + struct.pack(fmap['len'], len(packet)+4) + packet[14:]

    # add checksum
    packet += struct.pack(fmap['cs'], zlib.crc32(packet)) # zlib.adler32(packet))

    return packet