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

from io import BytesIO
import struct
import sys

from lcm_msgs import std_msgs
from . import *
from .PointField import PointField


class PointCloud2(object):
    msg_name = "sensor_msgs.PointCloud2"

    __slots__ = [
        "fields_length",
        "data_length",
        "header",
        "height",
        "width",
        "fields",
        "is_bigendian",
        "point_step",
        "row_step",
        "data",
        "is_dense",
    ]

    __typenames__ = [
        "int32_t",
        "int32_t",
        "std_msgs.Header",
        "int32_t",
        "int32_t",
        "PointField",
        "boolean",
        "int32_t",
        "int32_t",
        "byte",
        "boolean",
    ]

    __dimensions__ = [
        None,
        None,
        None,
        None,
        None,
        ["fields_length"],
        None,
        None,
        None,
        ["data_length"],
        None,
    ]

    fields_length: "int32_t"
    data_length: "int32_t"
    header: std_msgs.Header
    height: "int32_t"
    width: "int32_t"
    fields: PointField
    is_bigendian: "boolean"
    point_step: "int32_t"
    row_step: "int32_t"
    data: "byte"
    is_dense: "boolean"

    def __init__(
        self,
        fields_length=0,
        data_length=0,
        header=std_msgs.Header(),
        height=0,
        width=0,
        fields=[],
        is_bigendian=False,
        point_step=0,
        row_step=0,
        data=b"",
        is_dense=False,
    ):
        # LCM Type: int32_t
        self.fields_length = fields_length
        # LCM Type: int32_t
        self.data_length = data_length
        # LCM Type: std_msgs.Header
        self.header = header
        # LCM Type: int32_t
        self.height = height
        # LCM Type: int32_t
        self.width = width
        # LCM Type: PointField[fields_length]
        self.fields = fields
        # LCM Type: boolean
        self.is_bigendian = is_bigendian
        # LCM Type: int32_t
        self.point_step = point_step
        # LCM Type: int32_t
        self.row_step = row_step
        # LCM Type: byte[data_length]
        self.data = data
        # LCM Type: boolean
        self.is_dense = is_dense

    def lcm_encode(self):
        buf = BytesIO()
        buf.write(PointCloud2._get_packed_fingerprint())
        self._encode_one(buf)
        return buf.getvalue()

    def _encode_one(self, buf):
        buf.write(struct.pack(">ii", self.fields_length, self.data_length))
        assert (
            self.header._get_packed_fingerprint()
            == std_msgs.Header._get_packed_fingerprint()
        )
        self.header._encode_one(buf)
        buf.write(struct.pack(">ii", self.height, self.width))
        for i0 in range(self.fields_length):
            assert (
                self.fields[i0]._get_packed_fingerprint()
                == PointField._get_packed_fingerprint()
            )
            self.fields[i0]._encode_one(buf)
        buf.write(
            struct.pack(">bii", self.is_bigendian, self.point_step, self.row_step)
        )
        buf.write(bytearray(self.data[: self.data_length]))
        buf.write(struct.pack(">b", self.is_dense))

    @classmethod
    def lcm_decode(cls, data: bytes):
        if hasattr(data, "read"):
            buf = data
        else:
            buf = BytesIO(data)
        if buf.read(8) != cls._get_packed_fingerprint():
            raise ValueError("Decode error")
        return cls._decode_one(buf)

    @classmethod
    def _decode_one(cls, buf):
        self = cls()
        self.fields_length, self.data_length = struct.unpack(">ii", buf.read(8))
        self.header = cls._get_field_type("header")._decode_one(buf)
        self.height, self.width = struct.unpack(">ii", buf.read(8))
        self.fields = []
        for i0 in range(self.fields_length):
            self.fields.append(cls._get_field_type("fields")._decode_one(buf))
        self.is_bigendian = bool(struct.unpack("b", buf.read(1))[0])
        self.point_step, self.row_step = struct.unpack(">ii", buf.read(8))
        self.data = buf.read(self.data_length)
        self.is_dense = bool(struct.unpack("b", buf.read(1))[0])
        return self

    @classmethod
    def _get_field_type(cls, field_name):
        """Get the type for a field from annotations."""
        annotation = cls.__annotations__.get(field_name)
        if annotation is None:
            return None
        if isinstance(annotation, str):
            module = sys.modules[cls.__module__]
            if hasattr(module, annotation):
                return getattr(module, annotation)
            return None
        return annotation

    @classmethod
    def _get_hash_recursive(cls, parents):
        if cls in parents:
            return 0
        newparents = parents + [cls]
        tmphash = (
            0xEABE7183C4D74215
            + std_msgs.Header._get_hash_recursive(newparents)
            + PointField._get_hash_recursive(newparents)
        ) & 0xFFFFFFFFFFFFFFFF
        tmphash = (
            ((tmphash << 1) & 0xFFFFFFFFFFFFFFFF) + (tmphash >> 63)
        ) & 0xFFFFFFFFFFFFFFFF
        return tmphash

    _packed_fingerprint = None

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

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