import pyrfuniverse.attributes as attr


class HumanbodyAttr(attr.BaseAttr):
    """
    Human body Inverse Kinematic class.
    """

    def parse_message(self, data: dict):
        """
        Parse messages. This function is called by internal function.

        Returns:
            Dict: A dict containing useful information of this class.

            self.data['move_done']: Whether the movement has finished.

            self.data['rotate_done']: Whether the rotation has finished.
        """
        super().parse_message(data)

    def HumanIKTargetDoMove(
        self,
        index: int,
        position: list,
        duration: float,
        speed_based: bool = True,
        relative: bool = False,
    ):
        """
        Human body Inverse Kinematics target movement.

        Args:
            index: Int, the target for movement. 0 for left hand, 1 for right hand,2 for left foot, 3 for right foot, 4 for head.
            position: A list of length 3, representing the position.
            duration: Float, if `speed_based` is True, it represents movement duration; otherwise, it represents movement speed.
            speed_based: Bool.
            relative: Bool, if True, `position` is relative; otherwise, `position` is absolute.
        """
        if position is not None:
            assert len(position) == 3, "position length must be 3"
            position = [float(i) for i in position]
        self._send_data(
            "HumanIKTargetDoMove",
            index,
            position,
            float(duration),
            speed_based,
            relative,
        )

    def HumanIKTargetDoRotate(
        self,
        index: int,
        rotation: list,
        duration: float,
        speed_based: bool = True,
        relative: bool = False,
    ):
        """
        Human body Inverse Kinematics target rotation.

        Args:
            index: Int, the target for movement. 0 for left hand, 1 for right hand,2 for left foot, 3 for right foot, 4 for head.
            rotation: A list of length 3, representing the rotation.
            duration: Float, if `speed_based` is True, it represents movement duration; otherwise, it represents movement speed.
            speed_based: Bool.
            relative: Bool, if True, `rotation` is relative; otherwise, `rotation` is absolute.
        """
        if rotation is not None:
            assert len(rotation) == 3, "rotation length must be 3"
            rotation = [float(i) for i in rotation]
        self._send_data(
            "HumanIKTargetDoRotate",
            index,
            rotation,
            float(duration),
            speed_based,
            relative,
        )

    def HumanIKTargetDoRotateQuaternion(
        self,
        index: int,
        quaternion: list,
        duration: float,
        speed_based: bool = True,
        relative: bool = False,
    ):
        """
        Human body Inverse Kinematics target rotation using quaternion.

        Args:
            index: Int, the target for movement. 0 for left hand, 1 for right hand,2 for left foot, 3 for right foot, 4 for head.
            quaternion: A list of length 4, representing the quaternion.
            duration: Float, if `speed_based` is True, it represents movement duration; otherwise, it represents movement speed.
            speed_based: Bool.
            relative: Bool, if True, `quaternion` is relative; otherwise, `quaternion` is absolute.
        """
        if quaternion is not None:
            assert len(quaternion) == 4, "quaternion length must be 4"
            quaternion = [float(i) for i in quaternion]
        self._send_data(
            "HumanIKTargetDoRotateQuaternion",
            index,
            quaternion,
            float(duration),
            speed_based,
            relative,
        )

    def HumanIKTargetDoComplete(self, index: int):
        """
        Make the human body IK target movement / rotation complete directly.

        Args:
            index: Int, the target for movement. 0 for left hand, 1 for right hand,2 for left foot, 3 for right foot, 4 for head.
        """
        self._send_data("HumanIKTargetDoComplete", index)

    def HumanIKTargetDoKill(self, index: int):
        """
        Make the human body IK target movement / rotation stop.

        Args:
            index: Int, the target for movement. 0 for left hand, 1 for right hand,2 for left foot, 3 for right foot, 4 for head.
        """
        self._send_data("HumanIKTargetDoKill", index)

    def WaitDo(self):
        """
        Wait for the human body IK target movement / rotation complete.
        """
        while not self.data["move_done"] or not self.data["rotate_done"]:
            self.env.step()
