"""LCM type definitions
This file automatically generated by lcm.
DO NOT MODIFY BY HAND!!!!
"""


from io import BytesIO
import struct

import drake

class lcmt_point_cloud(object):
    """
    Generic point cloud with runtime typing.
    
    Modeled after PCL and ROS conventions:
    https://pointclouds.org/documentation/structpcl_1_1_p_c_l_point_cloud2.html
    https://docs.ros.org/en/api/sensor_msgs/html/msg/PointCloud2.html
    
    """

    __slots__ = ["utime", "frame_name", "width", "height", "num_fields", "fields", "flags", "point_step", "row_step", "filler_size", "filler", "data_size", "data"]

    __typenames__ = ["int64_t", "string", "int64_t", "int64_t", "int32_t", "drake.lcmt_point_cloud_field", "int64_t", "int32_t", "int64_t", "int16_t", "byte", "int64_t", "byte"]

    __dimensions__ = [None, None, None, None, None, ["num_fields"], None, None, None, None, ["filler_size"], None, ["data_size"]]

    IS_BIGENDIAN = 1
    """
    === Constants for the flags bits ===
    Set iff data is big-endian.
    """
    IS_STRICTLY_FINITE = 2
    """
    Set iff data contains only finite values.  (ROS sometimes uses "is_dense"
    to refer to this concept, but not all implementations agree on whether
    "dense" means "strictly finite" or "provides full width x height matrix
    with possibly infinite values", so we use a less ambiguous term here.)
    """

    def __init__(self):
        self.utime = 0
        """
        Timestamp in microseconds.
        LCM Type: int64_t
        """

        self.frame_name = ""
        """
        The name of a frame this data is associated with.
        LCM Type: string
        """

        self.width = 0
        """
        If the cloud is structured, this is the 2D width.
        If the cloud is unstructured, this is the number of points in the cloud.
        LCM Type: int64_t
        """

        self.height = 0
        """
        If the cloud is structured, this is the 2D height.
        If the cloud is unstructured, this is set to 1.
        LCM Type: int64_t
        """

        self.num_fields = 0
        """
        Descriptions of the fields.
        LCM Type: int32_t
        """

        self.fields = []
        """ LCM Type: drake.lcmt_point_cloud_field[num_fields] """
        self.flags = 0
        """
        Bitfield of flags describing this.  See the "IS_..." constants below.
        LCM Type: int64_t
        """

        self.point_step = 0
        """
        Number of bytes between each successive point.  This is always at least the
        sum of all field sizes, but may be larger if the data has internal padding.
        LCM Type: int32_t
        """

        self.row_step = 0
        """
        Number of bytes between each successive row.
        LCM Type: int64_t
        """

        self.filler_size = 0
        """
        Optional filler bytes to allow the raw point data to be aligned in memory.
        LCM Type: int16_t
        """

        self.filler = b""
        """ LCM Type: byte[filler_size] """
        self.data_size = 0
        """
        The raw point data.
        LCM Type: int64_t
        """

        self.data = b""
        """ LCM Type: byte[data_size] """

    def encode(self):
        buf = BytesIO()
        buf.write(lcmt_point_cloud._get_packed_fingerprint())
        self._encode_one(buf)
        return buf.getvalue()

    def _encode_one(self, buf):
        buf.write(struct.pack(">q", self.utime))
        __frame_name_encoded = self.frame_name.encode('utf-8')
        buf.write(struct.pack('>I', len(__frame_name_encoded)+1))
        buf.write(__frame_name_encoded)
        buf.write(b"\0")
        buf.write(struct.pack(">qqi", self.width, self.height, self.num_fields))
        for i0 in range(self.num_fields):
            assert self.fields[i0]._get_packed_fingerprint() == drake.lcmt_point_cloud_field._get_packed_fingerprint()
            self.fields[i0]._encode_one(buf)
        buf.write(struct.pack(">qiqh", self.flags, self.point_step, self.row_step, self.filler_size))
        buf.write(bytearray(self.filler[:self.filler_size]))
        buf.write(struct.pack(">q", self.data_size))
        buf.write(bytearray(self.data[:self.data_size]))

    @staticmethod
    def decode(data: bytes):
        if hasattr(data, 'read'):
            buf = data
        else:
            buf = BytesIO(data)
        if buf.read(8) != lcmt_point_cloud._get_packed_fingerprint():
            raise ValueError("Decode error")
        return lcmt_point_cloud._decode_one(buf)

    @staticmethod
    def _decode_one(buf):
        self = lcmt_point_cloud()
        self.utime = struct.unpack(">q", buf.read(8))[0]
        __frame_name_len = struct.unpack('>I', buf.read(4))[0]
        self.frame_name = buf.read(__frame_name_len)[:-1].decode('utf-8', 'replace')
        self.width, self.height, self.num_fields = struct.unpack(">qqi", buf.read(20))
        self.fields = []
        for i0 in range(self.num_fields):
            self.fields.append(drake.lcmt_point_cloud_field._decode_one(buf))
        self.flags, self.point_step, self.row_step, self.filler_size = struct.unpack(">qiqh", buf.read(22))
        self.filler = buf.read(self.filler_size)
        self.data_size = struct.unpack(">q", buf.read(8))[0]
        self.data = buf.read(self.data_size)
        return self

    @staticmethod
    def _get_hash_recursive(parents):
        if lcmt_point_cloud in parents: return 0
        newparents = parents + [lcmt_point_cloud]
        tmphash = (0xb996d33b5fb6120b+ drake.lcmt_point_cloud_field._get_hash_recursive(newparents)) & 0xffffffffffffffff
        tmphash  = (((tmphash<<1)&0xffffffffffffffff) + (tmphash>>63)) & 0xffffffffffffffff
        return tmphash
    _packed_fingerprint = None

    @staticmethod
    def _get_packed_fingerprint():
        if lcmt_point_cloud._packed_fingerprint is None:
            lcmt_point_cloud._packed_fingerprint = struct.pack(">Q", lcmt_point_cloud._get_hash_recursive([]))
        return lcmt_point_cloud._packed_fingerprint

    def get_hash(self):
        """Get the LCM hash of the struct"""
        return struct.unpack(">Q", lcmt_point_cloud._get_packed_fingerprint())[0]

