import ctypes

class UDP1553Header(ctypes.Structure):
    """
    Represents the proprietary UDP header wrapping the MIL-STD-1553 frames.
    Standard ctypes.Structure uses host endianness (Little Endian on x86/x64).
    """
    _pack_ = 1
    _fields_ = [
        ("marker1553", ctypes.c_uint16),
        ("vmajor", ctypes.c_uint8),
        ("vminor", ctypes.c_uint8),
        ("otype", ctypes.c_uint16),
        ("ta", ctypes.c_uint8),
        ("flags", ctypes.c_uint8),
        ("fcounter", ctypes.c_uint32),
        ("mcounter", ctypes.c_uint32),
        ("scounter", ctypes.c_uint32),
        ("mmiss", ctypes.c_uint32),
        ("smiss", ctypes.c_uint32),
        ("ltt", ctypes.c_uint32),
        ("errors", ctypes.c_uint32),
        ("bc_reserved", ctypes.c_uint32 * 2),
        ("rt_reserved", ctypes.c_uint32 * 2),
        ("spare", ctypes.c_uint32 * 3)
    ]

    # Constants identifying the packet structure
    MARKER_1553 = 0x1553
    MARKER_END_1553 = 0x5315
    OTYPE_BC = 0x4342
    OTYPE_RT = 0x5452
    
    # Error codes
    ERR_UNSUPPORTED_VERSION = 1
    ERR_INVALID_SOURCE = 2
    ERR_INVALID_LEN = 3
    ERR_MISSED_MSG_MARKER = 4

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        if "marker1553" not in kwargs:
            self.marker1553 = self.MARKER_1553
        if "otype" not in kwargs:
            self.otype = self.OTYPE_BC


class CommandWordStruct(ctypes.Structure):
    """
    Bit-field representation of a 1553 Command Word.
    Standard Little Endian packing: LSB is first in the bitfield.
    Matches C++ struct: wc:5, sa:5, tr:1, rt:5
    """
    _pack_ = 1
    _fields_ = [
        ("word_count", ctypes.c_uint16, 5),      # Bits 0-4
        ("subaddress", ctypes.c_uint16, 5),      # Bits 5-9
        ("tr_bit", ctypes.c_uint16, 1),          # Bit 10
        ("remote_terminal", ctypes.c_uint16, 5)  # Bits 11-15
    ]


class CommandWordUnion(ctypes.Union):
    """
    Union to access Command Word as raw integer or bit-fields.
    """
    _pack_ = 1
    _fields_ = [
        ("raw", ctypes.c_uint16),
        ("struct", CommandWordStruct)
    ]

    def __init__(self, rt_addr=0, sub_addr=0, word_count=0, transmit=False):
        super().__init__()
        self.struct.remote_terminal = rt_addr
        self.struct.subaddress = sub_addr
        self.struct.word_count = word_count & 0x1F
        self.struct.tr_bit = 1 if transmit else 0

class UDP1553MessageHeader(ctypes.Structure):
    """
    Header for a single 1553 Message inside the UDP packet payload.
    """
    _pack_ = 1
    _fields_ = [
        ("marker", ctypes.c_uint16),
        ("command_word", CommandWordUnion),
        ("status_word", ctypes.c_uint16),
        ("error_code", ctypes.c_uint16)
    ]

    MARKER_BEGIN = 0x3C3C
    MARKER_END = 0x3E3E

    def __init__(self, command_word_union=None):
        super().__init__()
        self.marker = self.MARKER_BEGIN
        if command_word_union:
            self.command_word = command_word_union
        self.error_code = 0