from pyModbusTCP.client import ModbusClient
from .utility import Utility, DataType
from pymodbus.payload import BinaryPayloadBuilder, Endian
from enum import Enum

type_register_size = [1, 1, 2, 2, 4, 4, 8, 8]


class Command(Enum):
    MOTOR_SWEEP = 2
    MOTOR_RELEASE = 3
    MOTOR_GOTO_ENCODER_POS = 4
    MOTOR_MOVE_STEP = 7
    MOTOR_MOVE_VELOCITY_MODE_AZ = 8
    MOTOR_MOVE_VELOCITY_MODE_EL = 9
    MOTOR_MOVE_VELOCITY_MODE_POL = 10
    MOTOR_MOVE_VELOCITY_MODE_RAD = 11
    MOTOR_STOP_AZ = 12
    MOTOR_STOP_EL = 13
    MOTOR_STOP_POL = 14
    MOTOR_STOP_RAD = 15
    MOTOR_GOTO_ABSOLUTE_POS_AZ = 16
    MOTOR_GOTO_ABSOLUTE_POS_EL = 17
    MOTOR_GOTO_ABSOLUTE_POS_POL = 18
    MOTOR_GOTO_ABSOLUTE_POS_RAD = 19
    MOTOR_GOTO_ANGLE_POS_AZ = 20
    MOTOR_GOTO_ANGLE_POS_EL = 21
    MOTOR_GOTO_ANGLE_POS_POL = 22
    MOTOR_GOTO_ANGLE_POS_RAD = 23
    START_HOMING = 24


class Modbus:
    def __init__(self, ip, port, id):
        self.client = ModbusClient(host=ip, port=port, unit_id=id, auto_open=True)
        # self.builder = BinaryPayloadBuilder(byteorder=Endian.BIG, wordorder=Endian.LITTLE)
        self.builder = BinaryPayloadBuilder(byteorder=Endian.Big, wordorder=Endian.Little)

    def close(self):
        self.client.close()

    def read_holding_register(self, address, data_type):
        try:
            _result = self.client.read_holding_registers(address - 40001, type_register_size[data_type.value])
        except Exception as e:
            print(str(e))
        return Utility.uint16_to_xx(data_type, _result)

    def read_holding_registers(self, address, reg_nb):
        _result = self.client.read_holding_registers(reg_addr=address - 40001, reg_nb=reg_nb)
        return _result

    def write_holding_registers(self, address, val, data_type):
        self.builder.reset()
        if data_type == DataType.UINT32T:
            self.builder.add_32bit_uint(val)
        elif data_type == DataType.INT32T:
            self.builder.add_32bit_int(val)
        elif data_type == DataType.UINT16T:
            self.builder.add_16bit_uint(val)
        elif data_type == DataType.INT16T:
            self.builder.add_16bit_int(val)

        payload = self.builder.to_registers()
        self.client.write_multiple_registers(
            regs_addr=address - 40001, regs_value=payload
        )
        # self.client.write_single_register(address - 40001, payload[0])

    def read_holding_register_u16(self, address):
        return self.read_holding_register(address, DataType.UINT16T)

    def read_holding_register_u32(self, address):
        return self.read_holding_register(address, DataType.UINT32T)

    def read_holding_register_s32(self, address):
        return self.read_holding_register(address, DataType.INT32T)

    def read_holding_register_u64(self, address):
        return self.read_holding_register(address, DataType.UINT64T)

    def read_holding_registers_u128(self, address):
        return self.read_holding_registers(address, DataType.UINT128T)
    

