import numpy as np
from .processor import Processor
from .config import Config
from .robot import Robot, Link, Joint
from .message import info
import fnmatch


class ProcessorBallToEuler(Processor):
    """
    Turn ball joints into euler roll/pitch/yaw joints.
    """

    def __init__(self, config: Config):
        super().__init__(config)

        # Check if it is enabled in configuration
        self.ball_to_euler: bool | list = config.get("ball_to_euler", False)
        self.ball_to_euler_order: bool | list = config.get(
            "ball_to_euler_order",
            "xyz",
            values_list=["xyz", "xzy", "zyx", "zxy", "yxz", "yzx"],
        )

    def should_replace(self, joint: Joint) -> bool:
        if self.ball_to_euler == True:
            return True
        elif isinstance(self.ball_to_euler, list):
            for entry in self.ball_to_euler:
                if fnmatch.fnmatch(entry, joint.name):
                    return True
        return False

    def process(self, robot: Robot):
        if self.ball_to_euler:
            print(info(f"Replacing balls to euler ({self.ball_to_euler})"))
            replaced_joints: list[Joint] = []

            # Searching for ball joints to replace
            for joint in robot.joints:
                if joint.joint_type == Joint.BALL and self.should_replace(joint):
                    parent = joint.parent
                    children = {}
                    for letter in self.ball_to_euler_order[:-1]:
                        body_name = f"{joint.name}_link_{letter}"
                        new_link = Link(body_name)
                        children[letter] = new_link
                        robot.links.append(new_link)
                    children[self.ball_to_euler_order[-1]] = joint.child

                    for letter in self.ball_to_euler_order:
                        if letter == "x":
                            axis = np.array([1.0, 0.0, 0.0])
                        elif letter == "y":
                            axis = np.array([0.0, 1.0, 0.0])
                        elif letter == "z":
                            axis = np.array([0.0, 0.0, 1.0])

                        new_joint = Joint(
                            name=f"{joint.name}_{letter}",
                            joint_type=Joint.REVOLUTE,
                            parent=parent,
                            child=children[letter],
                            T_world_joint=joint.T_world_joint,
                            properties=joint.properties.copy(),
                            axis=axis,
                        )
                        robot.joints.append(new_joint)
                        parent = children[letter]

                    replaced_joints.append(joint)

            # Removing replaced joints
            for joint in replaced_joints:
                robot.joints.remove(joint)
