import ctypes
from Grifo_E_1553lib.data_types.enums import (
    ParameterTransferEnabled, ReceiveTransmitSelector, ParamIdCode, DataRecordingValue
)
import Grifo_E_1553lib.data_types.enum_map as em


em.ENUM_MAP.update({
    "parameter_transfer_enable" : ParameterTransferEnabled,
    "receive_transmit_selector" : ReceiveTransmitSelector,
    "parameter_identifier" : ParamIdCode,
    "data_rec" : DataRecordingValue
})


class AntennaHarmonizationAngleYaw(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("yaw", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]
    
class AntennaHarmonizationAnglePitch(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("pitch", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]

class AntennaHarmonizationAngleRoll(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("roll", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]

class BulkheadXDisplacement(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("x", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]

class BulkheadYDisplacement(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("y", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]

class BulkheadZDisplacement(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("z", ctypes.c_int16),
        ("spare", ctypes.c_uint16)
        
    ]

class SymbolIntensityA(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("intensity", ctypes.c_uint16, 4),
        ("spare_1", ctypes.c_uint16, 12),
        ("spare_2", ctypes.c_uint16)
        
        
    ]

class SymbolIntensityB(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("intensity", ctypes.c_uint16, 4),
        ("spare_1", ctypes.c_uint16, 12),
        ("spare_2", ctypes.c_uint16)
        
    ]

class SymbolIntensityC(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("intensity", ctypes.c_uint16, 4),
        ("spare_1", ctypes.c_uint16, 12),
        ("spare_2", ctypes.c_uint16)
        
    ]

class WhiteLevelForSARImages(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("level", ctypes.c_uint16),
        ("spare", ctypes.c_uint16)
        
    ]

class BlackLevelForSARImages(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("level", ctypes.c_uint16),
        ("spare", ctypes.c_uint16)
        
    ]

class PreCompressionFactorForSARImages(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("factor", ctypes.c_uint16),
        ("spare", ctypes.c_uint16)
        
    ]

class DataRecording(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("data_rec", ctypes.c_uint16, 4),
        ("spare_1", ctypes.c_uint16, 12),
        ("spare_2", ctypes.c_uint16)
        
    ]

class PresentPosition(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("present", ctypes.c_uint16, 1),
        ("spare_1", ctypes.c_uint16, 15),
        ("spare_2", ctypes.c_uint16)
        
    ]

#TODO: union tra raw e ogni singolo param struct, da implementare
class ParamValue(ctypes.Union):
    _fields_ = [
        ("raw", ctypes.c_uint32),  
        ("antenna_harmonization_yaw", AntennaHarmonizationAngleYaw),
        ("antenna_harmonization_pitch", AntennaHarmonizationAnglePitch),
        ("antenna_harmonization_roll", AntennaHarmonizationAngleYaw),
        ("bulkhead_x_displacement", BulkheadXDisplacement),
        ("bulkhead_y_displacement", BulkheadYDisplacement),
        ("bulkhead_z_displacement", BulkheadZDisplacement),
        ("symbol_intensity_a", SymbolIntensityA),
        ("symbol_intensity_b", SymbolIntensityB),
        ("symbol_intensity_c", SymbolIntensityC),
        ("waveform_command", ctypes.c_uint32),
        ("cut_off_velocity", ctypes.c_uint32),
        ("range_threshold_for_aws", ctypes.c_uint32),
        ("test_01_for_new_modes", ctypes.c_uint32),
        ("test_02_for_new_modes", ctypes.c_uint32),
        ("test_03_for_new_modes", ctypes.c_uint32),
        ("test_04_for_new_modes", ctypes.c_uint32),
        ("white_level_for_sar_images", WhiteLevelForSARImages),
        ("black_level_for_sar_images", BlackLevelForSARImages),
        ("pre_compression_factor_for_sar_images", PreCompressionFactorForSARImages),
        ("data_recording", DataRecording),
        ("present_position", PresentPosition)
        
    ]

    def get_ivalue(self):
        return self.raw

    def set_ivalue(self, value):
        self.raw = value

    #TODO: Implementare la gestione di param_angle_t
    def get_angle(self):
        return 0.0 #segnaposto

    def set_angle(self, value):
        pass #segnaposto
    
    
class _ParamIdStr(ctypes.LittleEndianStructure):
    _pack_ = 1
    _fields_ = [
        
        ("spare", ctypes.c_uint16,1),
        ("spare", ctypes.c_uint16,1),
        ("spare", ctypes.c_uint16,1),
        ("spare", ctypes.c_uint16,1),
        ("spare", ctypes.c_uint16,1),
        ("spare", ctypes.c_uint16,1),
        ("parameter_identifier", ctypes.c_uint16,8),
        ("receive_transmit_selector", ctypes.c_uint16,1),
        ("parameter_transfer_enable", ctypes.c_uint16,1),
        
        
    ]
class ParamId(ctypes.Union):
    _pack_ = 1  # Forza l'allineamento a 1 byte
    _fields_ = [
        ("raw", ctypes.c_uint16),
        ("str", _ParamIdStr)
        
        ]

    def __init__(self):
        super().__init__()
        self.raw = ctypes.c_uint16(0)  # Inizializza raw a 0

    def get_enable(self):
        return ParameterTransferEnabled((self.raw >> 15) & 0x01)

    def set_enable(self, value):
        self.raw &= ~(0x01 << 15)
        self.raw |= (value << 15)

    def get_tx(self):
        return ReceiveTransmitSelector((self.raw >> 14) & 0x01)

    def set_tx(self, value):
        self.raw &= ~(0x01 << 14)
        self.raw |= (value << 14)

    def get_num(self):
        return (self.raw >> 7) & 0xFF

    def set_num(self, value):
        self.raw &= ~(0xFF << 7)
        self.raw |= (value << 7)

    def get_spare(self):
        return (self.raw >> 0) & 0x3F

    def set_spare(self, value):
        self.raw &= ~(0x3F << 0)
        self.raw |= (value << 0)
        
        

