# Path: robot_designer_plugin/operators/helpers.py
# def _mat3_to_vec_roll(mat):
#     """
#     Function to convert a 3x3 rotation matrix to a rotation axis and a roll angle along this axis
#     Python port of the C function defined in armature.c
# 
#     Thanks to blenderartists.org user vida_vida
# 
#     :param mat:
#     :return:
#     """
#     from ..properties.globals import global_properties
# 
#     vec = mat.col[1] * global_properties.bone_length.get(bpy.context.scene)
#     vecmat = _vec_roll_to_mat3(mat.col[1], 0)
#     vecmatinv = vecmat.inverted()
#     rollmat = vecmatinv @ mat
#     roll = math.atan2(rollmat[0][2], rollmat[2][2])
#     return vec, roll
# 
# class ModelSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures the armature is selected.
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_object:
#             return (
#                 bpy.context.active_object.type == "ARMATURE",
#                 "Model not selected and active.",
#             )
#         else:
#             return False, "No model selected"
# 
# class SingleSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that a single mesh object (i.e., two selected objects where exactly one is a mesh).
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) == 1, "Single Segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class PoseMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`pose mode` is selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode == "POSE", "Must be in Pose Mode"
#         else:
#             return True, ""
# 
# class AtLeastOneSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that at least one bone of the active object is selected
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) >= 1, "At least one segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class NotEditMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`edit mode` is *not* selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode != "EDIT", "Must not be in Edit Mode"
#         else:
#             return True, ""


from math import degrees, radians
from bpy.props import StringProperty, BoolProperty
from .rigid_bodies import *
from .helpers import (
    _mat3_to_vec_roll,
    ModelSelected,
    SingleSegmentSelected,
    PoseMode,
    AtLeastOneSegmentSelected,
    NotEditMode,
)
import bpy
    :term:`operator` for assigning a parent to a segment.


    """

    bl_idname = config.OPERATOR_PREFIX + "assignparentbone"
    bl_label = "Assign Parent Bone"

    parent_name: StringProperty()

    @classmethod
    def run(cls, parent_name):
        return super().run(**cls.pass_keywords())

    @RDOperator.OperatorLogger
    def execute(self, context):
        # arm = context.active_object
        current_segment_name = context.active_bone.name

        current_mode = bpy.context.object.mode
        bpy.ops.object.mode_set(mode="EDIT", toggle=False)
        new_parent_editbone = context.active_object.data.edit_bones[self.parent_name]
        current_editbone = context.active_object.data.edit_bones[current_segment_name]
        current_editbone.parent = new_parent_editbone
        bpy.ops.object.mode_set(mode=current_mode, toggle=False)

        UpdateSegments.run(segment_name=current_segment_name)
        return {"FINISHED"}



# Path: robot_designer_plugin/operators/helpers.py
# def _mat3_to_vec_roll(mat):
#     """
#     Function to convert a 3x3 rotation matrix to a rotation axis and a roll angle along this axis
#     Python port of the C function defined in armature.c
# 
#     Thanks to blenderartists.org user vida_vida
# 
#     :param mat:
#     :return:
#     """
#     from ..properties.globals import global_properties
# 
#     vec = mat.col[1] * global_properties.bone_length.get(bpy.context.scene)
#     vecmat = _vec_roll_to_mat3(mat.col[1], 0)
#     vecmatinv = vecmat.inverted()
#     rollmat = vecmatinv @ mat
#     roll = math.atan2(rollmat[0][2], rollmat[2][2])
#     return vec, roll
# 
# class ModelSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures the armature is selected.
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_object:
#             return (
#                 bpy.context.active_object.type == "ARMATURE",
#                 "Model not selected and active.",
#             )
#         else:
#             return False, "No model selected"
# 
# class SingleSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that a single mesh object (i.e., two selected objects where exactly one is a mesh).
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) == 1, "Single Segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class PoseMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`pose mode` is selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode == "POSE", "Must be in Pose Mode"
#         else:
#             return True, ""
# 
# class AtLeastOneSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that at least one bone of the active object is selected
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) >= 1, "At least one segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class NotEditMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`edit mode` is *not* selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode != "EDIT", "Must not be in Edit Mode"
#         else:
#             return True, ""


# Path: robot_designer_plugin/operators/segments.py
from math import degrees, radians
from bpy.props import StringProperty, BoolProperty
from .rigid_bodies import *
from .helpers import (
    _mat3_to_vec_roll,
    ModelSelected,
    SingleSegmentSelected,
    PoseMode,
    AtLeastOneSegmentSelected,
    NotEditMode,
)
import bpy

    :term:`operator` for assigning a parent to a segment.


    """

    bl_idname = config.OPERATOR_PREFIX + "assignparentbone"
    bl_label = "Assign Parent Bone"

    parent_name: StringProperty()

    @classmethod
    def run(cls, parent_name):
        return super().run(**cls.pass_keywords())

    @RDOperator.OperatorLogger
    def execute(self, context):
        # arm = context.active_object
        current_segment_name = context.active_bone.name

        current_mode = bpy.context.object.mode
        bpy.ops.object.mode_set(mode="EDIT", toggle=False)
        new_parent_editbone = context.active_object.data.edit_bones[self.parent_name]
        current_editbone = context.active_object.data.edit_bones[current_segment_name]
        current_editbone.parent = new_parent_editbone
        bpy.ops.object.mode_set(mode=current_mode, toggle=False)

        UpdateSegments.run(segment_name=current_segment_name)
        return {"FINISHED"}



@RDOperator.Preconditions(ModelSelected, AtLeastOneSegmentSelected, NotEditMode)