# This file defines a set of methods that are useful for various 
# Relative Keying Set (RKS) related operations, such as: callbacks
# for polling, iterator callbacks, and also generate callbacks. 
# All of these can be used in conjunction with the others. 

import bpy

###########################
# General Utilities

# Append the specified property name on the the existing path
def path_add_property(path, prop):
    if len(path):
        return path + "." + prop;
    else:
        return prop;

###########################
# Poll Callbacks

# selected objects
def RKS_POLL_selected_objects(ksi, context):
    return context.active_object or len(context.selected_objects);
    
# selected bones
def RKS_POLL_selected_bones(ksi, context):
    # we must be in Pose Mode, and there must be some bones selected 
    if (context.active_object) and (context.active_object.mode == 'POSE'):
        if context.active_pose_bone or len(context.selected_pose_bones):
            return True;
    
    # nothing selected 
    return False;


# selected bones or objects
def RKS_POLL_selected_items(ksi, context):
    return RKS_POLL_selected_bones(ksi, context) or RKS_POLL_selected_objects(ksi, context);

###########################
# Iterator Callbacks

# all selected objects or pose bones, depending on which we've got
def RKS_ITER_selected_item(ksi, context, ks):
    if (context.active_object) and (context.active_object.mode == 'POSE'):
        for bone in context.selected_pose_bones:
            ksi.generate(context, ks, bone)
    else:
        for ob in context.selected_objects:
            ksi.generate(context, ks, ob)

###########################
# Generate Callbacks

# 'Available' F-Curves
def RKS_GEN_available(ksi, context, ks, data):
    # try to get the animation data associated with the closest 
    # ID-block to the data (neither of which may exist/be easy to find)
    id_block = data.id_data
    adt = getattr(id_block, "animation_data", None)

    # there must also be an active action...
    if adt is None or adt.action is None:
        return;
        
    # for each F-Curve, include an path to key it
    # NOTE: we don't need to set the group settings here
    for fcu in adt.action.fcurves:
        ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
    
# ------

# get ID block and based ID path for transform generators
def get_transform_generators_base_info(data):
    # ID-block for the data 
    id_block = data.id_data
    
    # get base path and grouping method/name
    if isinstance(data, bpy.types.ID):
        # no path in this case
        path = ""
        
        # data on ID-blocks directly should get grouped by the KeyingSet
        grouping = None
    else:
        # get the path to the ID-block
        path = data.path_from_id()

        # try to use the name of the data element to group the F-Curve
        # else fallback on the KeyingSet name
        grouping = getattr(data, "name", None)
        
    # return the ID-block and the path
    return id_block, path, grouping

# Location 
def RKS_GEN_location(ksi, context, ks, data):
    # get id-block and path info
    id_block, base_path, grouping= get_transform_generators_base_info(data)
    
    # add the property name to the base path
    path = path_add_property(base_path, "location")
    
    # add Keying Set entry for this...
    if grouping:
        ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
    else:
        ks.paths.add(id_block, path)

# Rotation 
def RKS_GEN_rotation(ksi, context, ks, data):
    # get id-block and path info
    id_block, base_path, grouping= get_transform_generators_base_info(data)
    
    # add the property name to the base path
    #   rotation mode affects the property used
    if data.rotation_mode == 'QUATERNION':
        path = path_add_property(base_path, "rotation_quaternion")
    elif data.rotation_mode == 'AXISANGLE':
        path = path_add_property(base_path, "rotation_axis_angle")
    else:
        path = path_add_property(base_path, "rotation_euler")
    
    # add Keying Set entry for this...
    if grouping:
        ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
    else:
        ks.paths.add(id_block, path)

# Scaling 
def RKS_GEN_scaling(ksi, context, ks, data):
    # get id-block and path info
    id_block, base_path, grouping= get_transform_generators_base_info(data)
    
    # add the property name to the base path
    path = path_add_property(base_path, "scale")
    
    # add Keying Set entry for this...
    if grouping:
        ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
    else:
        ks.paths.add(id_block, path)

###########################
# Un-needed stuff which is here to just shut up the warnings...

classes = []

def register():
    register = bpy.types.register
    for cls in classes:
        register(cls)


def unregister():
    unregister = bpy.types.unregister
    for cls in classes:
        unregister(cls)

if __name__ == "__main__":
    register()

###########################
