# automatically generated by the FlatBuffers compiler, do not modify

# namespace: Example

import flatbuffers
from flatbuffers.compat import import_numpy
from typing import Any
from MyGame.Example.NestedStruct import NestedStruct
np = import_numpy()

class LargeArrayStruct(object):
    __slots__ = ['_tab']

    @classmethod
    def SizeOf(cls) -> int:
        return 2496

    # LargeArrayStruct
    def Init(self, buf: bytes, pos: int):
        self._tab = flatbuffers.table.Table(buf, pos)

    # LargeArrayStruct
    def D(self, j = None):
        if j is None:
            return [self._tab.Get(flatbuffers.number_types.Uint8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0 + i * 1)) for i in range(self.DLength())]
        elif j >= 0 and j < self.DLength():
            return self._tab.Get(flatbuffers.number_types.Uint8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0 + j * 1))
        else:
            return None

    # LargeArrayStruct
    def DAsNumpy(self):
        return self._tab.GetArrayAsNumpy(flatbuffers.number_types.Uint8Flags, self._tab.Pos + 0, self.DLength())

    # LargeArrayStruct
    def DLength(self) -> int:
        return 64

    # LargeArrayStruct
    def DIsNone(self) -> bool:
        return False

    # LargeArrayStruct
    def E(self, j = None):
        if j is None:
            return [self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(64 + i * 4)) for i in range(self.ELength())]
        elif j >= 0 and j < self.ELength():
            return self._tab.Get(flatbuffers.number_types.Float32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(64 + j * 4))
        else:
            return None

    # LargeArrayStruct
    def EAsNumpy(self):
        return self._tab.GetArrayAsNumpy(flatbuffers.number_types.Float32Flags, self._tab.Pos + 64, self.ELength())

    # LargeArrayStruct
    def ELength(self) -> int:
        return 64

    # LargeArrayStruct
    def EIsNone(self) -> bool:
        return False

    # LargeArrayStruct
    def F(self, j = None):
        if j is None:
            return [self._tab.Get(flatbuffers.number_types.BoolFlags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(320 + i * 1)) for i in range(self.FLength())]
        elif j >= 0 and j < self.FLength():
            return self._tab.Get(flatbuffers.number_types.BoolFlags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(320 + j * 1))
        else:
            return None

    # LargeArrayStruct
    def FAsNumpy(self):
        return self._tab.GetArrayAsNumpy(flatbuffers.number_types.BoolFlags, self._tab.Pos + 320, self.FLength())

    # LargeArrayStruct
    def FLength(self) -> int:
        return 64

    # LargeArrayStruct
    def FIsNone(self) -> bool:
        return False

    # LargeArrayStruct
    def G(self, i: int) -> NestedStruct:
        obj = NestedStruct()
        obj.Init(self._tab.Bytes, self._tab.Pos + 384 + i * 32)
        return obj

    # LargeArrayStruct
    def GLength(self) -> int:
        return 64

    # LargeArrayStruct
    def GIsNone(self) -> bool:
        return False

    # LargeArrayStruct
    def H(self, j = None):
        if j is None:
            return [self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(2432 + i * 1)) for i in range(self.HLength())]
        elif j >= 0 and j < self.HLength():
            return self._tab.Get(flatbuffers.number_types.Int8Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(2432 + j * 1))
        else:
            return None

    # LargeArrayStruct
    def HAsNumpy(self):
        return self._tab.GetArrayAsNumpy(flatbuffers.number_types.Int8Flags, self._tab.Pos + 2432, self.HLength())

    # LargeArrayStruct
    def HLength(self) -> int:
        return 64

    # LargeArrayStruct
    def HIsNone(self) -> bool:
        return False


def CreateLargeArrayStruct(builder, d, e, f, g_a, g_b, g_c, g_d, h):
    builder.Prep(8, 2496)
    for _idx0 in range(64 , 0, -1):
        builder.PrependInt8(h[_idx0-1])
    for _idx0 in range(64 , 0, -1):
        builder.Prep(8, 32)
        for _idx1 in range(2 , 0, -1):
            builder.PrependInt64(g_d[_idx0-1][_idx1-1])
        builder.Pad(5)
        for _idx1 in range(2 , 0, -1):
            builder.PrependInt8(g_c[_idx0-1][_idx1-1])
        builder.PrependInt8(g_b[_idx0-1])
        for _idx1 in range(2 , 0, -1):
            builder.PrependInt32(g_a[_idx0-1][_idx1-1])
    for _idx0 in range(64 , 0, -1):
        builder.PrependBool(f[_idx0-1])
    for _idx0 in range(64 , 0, -1):
        builder.PrependFloat32(e[_idx0-1])
    for _idx0 in range(64 , 0, -1):
        builder.PrependUint8(d[_idx0-1])
    return builder.Offset()

import MyGame.Example.NestedStruct
try:
    from typing import List
except:
    pass

class LargeArrayStructT(object):

    # LargeArrayStructT
    def __init__(
        self,
        d = None,
        e = None,
        f = None,
        g = None,
        h = None,
    ):
        self.d = d  # type: Optional[List[int]]
        self.e = e  # type: Optional[List[float]]
        self.f = f  # type: Optional[List[bool]]
        self.g = g  # type: Optional[List[MyGame.Example.NestedStruct.NestedStructT]]
        self.h = h  # type: Optional[List[int]]

    @classmethod
    def InitFromBuf(cls, buf, pos):
        largeArrayStruct = LargeArrayStruct()
        largeArrayStruct.Init(buf, pos)
        return cls.InitFromObj(largeArrayStruct)

    @classmethod
    def InitFromPackedBuf(cls, buf, pos=0):
        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, pos)
        return cls.InitFromBuf(buf, pos+n)

    @classmethod
    def InitFromObj(cls, largeArrayStruct):
        x = LargeArrayStructT()
        x._UnPack(largeArrayStruct)
        return x

    # LargeArrayStructT
    def _UnPack(self, largeArrayStruct):
        if largeArrayStruct is None:
            return
        if not largeArrayStruct.DIsNone():
            if np is None:
                self.d = []
                for i in range(largeArrayStruct.DLength()):
                    self.d.append(largeArrayStruct.D(i))
            else:
                self.d = largeArrayStruct.DAsNumpy()
        if not largeArrayStruct.EIsNone():
            if np is None:
                self.e = []
                for i in range(largeArrayStruct.ELength()):
                    self.e.append(largeArrayStruct.E(i))
            else:
                self.e = largeArrayStruct.EAsNumpy()
        if not largeArrayStruct.FIsNone():
            if np is None:
                self.f = []
                for i in range(largeArrayStruct.FLength()):
                    self.f.append(largeArrayStruct.F(i))
            else:
                self.f = largeArrayStruct.FAsNumpy()
        if not largeArrayStruct.GIsNone():
            self.g = []
            for i in range(largeArrayStruct.GLength()):
                if largeArrayStruct.G(i) is None:
                    self.g.append(None)
                else:
                    nestedStruct_ = MyGame.Example.NestedStruct.NestedStructT.InitFromObj(largeArrayStruct.G(i))
                    self.g.append(nestedStruct_)
        if not largeArrayStruct.HIsNone():
            if np is None:
                self.h = []
                for i in range(largeArrayStruct.HLength()):
                    self.h.append(largeArrayStruct.H(i))
            else:
                self.h = largeArrayStruct.HAsNumpy()

    # LargeArrayStructT
    def Pack(self, builder):
        return CreateLargeArrayStruct(builder, self.d, self.e, self.f, self.g.a, self.g.b, self.g.c, self.g.d, self.h)
