#!/usr/bin/env python3

# interface generated by gen_dbc_interface.py
# post-edited manually.

import asyncio
from typing import Optional
from abc import ABC, abstractmethod


class DbcInterface(ABC):
    """translation of DBC file to python interface"""

    def __init__(self) -> None:
        self.setpoint: float = 0.0  # keep track of setpoint

    @property
    @abstractmethod
    def axis_state(self) -> str:
        pass

    @abstractmethod
    async def _request(self, msg_name: str, timeout: float = 0.5) -> dict:
        pass

    @abstractmethod
    def _send_message(
        self, msg_name: str, msg_dict: Optional[dict] = None, rtr: bool = False
    ):
        pass

    # -------manage axis
    def clear_errors(self):
        self._send_message("Clear_Errors")

    def reboot(self):
        self._send_message("Reboot")

    # -------getters

    async def get_motor_error(self) -> dict:
        return await self._request("Get_Motor_Error")

    async def get_encoder_error(self) -> dict:
        return await self._request("Get_Encoder_Error")

    async def get_sensorless_error(self) -> dict:
        return await self._request("Get_Sensorless_Error")

    async def get_encoder_estimates(self) -> dict:
        return await self._request("Get_Encoder_Estimates")

    async def get_encoder_count(self) -> dict:
        return await self._request("Get_Encoder_Count")

    async def get_iq(self) -> dict:
        return await self._request("Get_Iq")

    async def get_sensorless_estimates(self) -> dict:
        return await self._request("Get_Sensorless_Estimates")

    async def get_bus_voltage_current(self) -> dict:
        return await self._request("Get_Bus_Voltage_Current")

    async def get_adc_voltage(self) -> dict:
        return await self._request("Get_ADC_Voltage")

    async def get_controller_error(self) -> dict:
        return await self._request("Get_Controller_Error")

    # -------setters

    def set_axis_node_id(self, axis_node_id: int):
        self._send_message("Set_Axis_Node_ID", {"Axis_Node_ID": axis_node_id})

    async def set_axis_state(self, axis_requested_state: str | int):
        """request axis state and wait for it to be reached"""
        self._send_message(
            "Set_Axis_State", {"Axis_Requested_State": axis_requested_state}
        )
        while self.axis_state != axis_requested_state:
            await asyncio.sleep(0.1)

    def set_controller_mode(self, control_mode: str | int, input_mode: str | int):
        self._send_message(
            "Set_Controller_Mode",
            {"Control_Mode": control_mode, "Input_Mode": input_mode},
        )

    def set_input_pos(
        self, input_pos: float, vel_ff: float = 0.0, torque_ff: float = 0.0
    ):
        self._send_message(
            "Set_Input_Pos",
            {"Input_Pos": input_pos, "Vel_FF": vel_ff, "Torque_FF": torque_ff},
        )
        self.setpoint = input_pos

    def set_input_vel(self, input_vel: float, input_torque_ff: float = 0.0):
        self._send_message(
            "Set_Input_Vel",
            {"Input_Vel": input_vel, "Input_Torque_FF": input_torque_ff},
        )
        self.setpoint = input_vel

    def set_input_torque(self, input_torque: float):
        self._send_message("Set_Input_Torque", {"Input_Torque": input_torque})
        self.setpoint = input_torque

    def set_limits(self, velocity_limit: float, current_limit: float):
        self._send_message(
            "Set_Limits",
            {"Velocity_Limit": velocity_limit, "Current_Limit": current_limit},
        )

    def set_traj_vel_limit(self, traj_vel_limit: float):
        self._send_message("Set_Traj_Vel_Limit", {"Traj_Vel_Limit": traj_vel_limit})

    def set_traj_accel_limits(self, traj_accel_limit: float, traj_decel_limit: float):
        self._send_message(
            "Set_Traj_Accel_Limits",
            {
                "Traj_Accel_Limit": traj_accel_limit,
                "Traj_Decel_Limit": traj_decel_limit,
            },
        )

    def set_traj_inertia(self, traj_inertia: float):
        self._send_message("Set_Traj_Inertia", {"Traj_Inertia": traj_inertia})

    def set_linear_count(self, position: int):
        self._send_message("Set_Linear_Count", {"Position": position})

    def set_pos_gain(self, pos_gain: float):
        self._send_message("Set_Pos_Gain", {"Pos_Gain": pos_gain})

    def set_vel_gains(self, vel_gain: float, vel_integrator_gain: float):
        self._send_message(
            "Set_Vel_Gains",
            {"Vel_Gain": vel_gain, "Vel_Integrator_Gain": vel_integrator_gain},
        )
