/**
 * Award an achievement to a user
 *
 * @since  1.0.0
 * @param  integer $achievement_id The given achievement ID to award
 * @param  integer $user_id        The given user's ID
 * @param  string $this_trigger    The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args             The triggered args
 * @return mixed                   False on not achievement, void otherwise
 */
function badgeos_award_achievement_to_user($achievement_id = 0, $user_id = 0, $this_trigger = '', $site_id = 0, $args = array())
{
    global $wp_filter, $wp_version;
    // Sanity Check: ensure we're working with an achievement post
    if (!badgeos_is_achievement($achievement_id)) {
        return false;
    }
    // Use the current user ID if none specified
    if ($user_id == 0) {
        $user_id = wp_get_current_user()->ID;
    }
    // Get the current site ID none specified
    if (!$site_id) {
        $site_id = get_current_blog_id();
    }
    // Setup our achievement object
    $achievement_object = badgeos_build_achievement_object($achievement_id);
    // Update user's earned achievements
    badgeos_update_user_achievements(array('user_id' => $user_id, 'new_achievements' => array($achievement_object)));
    // Log the earning of the award
    badgeos_post_log_entry($achievement_id, $user_id);
    // Available hook for unlocking any achievement of this achievement type
    do_action('badgeos_unlock_' . $achievement_object->post_type, $user_id, $achievement_id, $this_trigger, $site_id, $args);
    // Patch for WordPress to support recursive actions, specifically for badgeos_award_achievement
    // Because global iteration is fun, assuming we can get this fixed for WordPress 3.9
    $is_recursed_filter = 'badgeos_award_achievement' == current_filter();
    $current_key = null;
    // Get current position
    if ($is_recursed_filter) {
        $current_key = key($wp_filter['badgeos_award_achievement']);
    }
    // Available hook to do other things with each awarded achievement
    do_action('badgeos_award_achievement', $user_id, $achievement_id, $this_trigger, $site_id, $args);
    if ($is_recursed_filter) {
        reset($wp_filter['badgeos_award_achievement']);
        while (key($wp_filter['badgeos_award_achievement']) !== $current_key) {
            next($wp_filter['badgeos_award_achievement']);
        }
    }
}
/**
 * Update the stored data for an active achievement
 *
 * @since  1.2.0
 *
 * @param  integer $user_id        User ID
 * @param  integer $achievement_id Achievement post ID
 * @param  object  $achievement    Achievement object to insert into user meta
 * @return object                  The final updated achievement object
 */
function badgeos_user_update_active_achievement($user_id = 0, $achievement_id = 0, $achievement = null)
{
    // If achievement is a step, bail here
    if ('step' == get_post_type($achievement_id)) {
        return false;
    }
    // If we weren't passed an object, get the latest version from meta
    if (!is_object($achievement)) {
        $achievement = badgeos_user_get_active_achievement($user_id, $achievement_id);
    }
    // If we still don't have an object, build one
    if (!is_object($achievement)) {
        $achievement = badgeos_build_achievement_object($achievement_id, 'started');
    }
    // Update our last activity date
    $achievement->last_activity_date = time();
    // Available filter for manipulating the achievement object
    $achievement = apply_filters('badgeos_user_update_active_achievement', $achievement, $user_id, $achievement_id);
    // Update the user's active achievements
    badgeos_user_update_active_achievements($user_id, array($achievement_id => $achievement), true);
    // Return the updated achievement object
    return $achievement;
}