/**
 * Generate HTML markup for an achievement's required steps
 *
 * This will generate an unorderd list (<ul>) if steps are non-sequential
 * and an ordered list (<ol>) if steps require sequentiality.
 *
 * @since  1.0.0
 * @param  array   $steps           An achievement's required steps
 * @param  integer $achievement_id  The given achievement's ID
 * @param  integer $user_id         The given user's ID
 * @return string                   The markup for our list
 */
function badgeos_get_required_achievements_for_achievement_list_markup($steps = array(), $achievement_id = 0, $user_id = 0)
{
    // If we don't have any steps, or our steps aren't an array, return nothing
    if (!$steps || !is_array($steps)) {
        return null;
    }
    // Grab the current post ID if no achievement_id was specified
    if (!$achievement_id) {
        global $post;
        $achievement_id = $post->ID;
    }
    $count = count($steps);
    // If we have no steps, return nothing
    if (!$count) {
        return null;
    }
    // Grab the current user's ID if none was specifed
    if (!$user_id) {
        $user_id = wp_get_current_user()->ID;
    }
    // Setup our variables
    $output = $step_output = '';
    $container = badgeos_is_achievement_sequential() ? 'ol' : 'ul';
    // Concatenate our output
    foreach ($steps as $step) {
        // check if user has earned this Achievement, and add an 'earned' class
        $earned_status = badgeos_get_user_achievements(array('user_id' => absint($user_id), 'achievement_id' => absint($step->ID), 'since' => absint(badgeos_achievement_last_user_activity($achievement_id, $user_id)))) ? 'user-has-earned' : 'user-has-not-earned';
        // get step title and if it doesn't have a title get the step trigger type post-meta
        $title = !empty($step->post_title) ? $step->post_title : get_post_meta($step->ID, '_badgeos_trigger_type', true);
        $step_output .= '<li class="' . apply_filters('badgeos_step_class', $earned_status, $step) . '">' . apply_filters('badgeos_step_title_display', $title, $step) . '</li>';
    }
    $post_type_object = get_post_type_object($step->post_type);
    $output .= '<h4>' . apply_filters('badgeos_steps_heading', sprintf(__('%1$d Required %2$s', 'badgeos'), $count, $post_type_object->labels->name), $steps) . '</h4>';
    $output .= '<' . $container . ' class="badgeos-required-achievements">';
    $output .= $step_output;
    $output .= '</' . $container . '><!-- .badgeos-required-achievements -->';
    // Return our output
    return $output;
}
/**
 * Check if user may access/earn achievement.
 *
 * @since  1.0.0
 * @param  integer $user_id        The given user's ID
 * @param  integer $achievement_id The given achievement's post ID
 * @param  string $this_trigger    The trigger
 * @param  integer $site_id        The triggered site id
 * @param  array $args        The triggered args
 * @return bool                    True if user has access, false otherwise
 */
function badgeos_user_has_access_to_achievement($user_id = 0, $achievement_id = 0, $this_trigger = '', $site_id = 0, $args = array())
{
    // Set to current site id
    if (!$site_id) {
        $site_id = get_current_blog_id();
    }
    // Assume we have access
    $return = true;
    // If the achievement is not published, we do not have access
    if ('publish' != get_post_status($achievement_id)) {
        $return = false;
    }
    // If we've exceeded the max earnings, we do not have acces
    if ($return && badgeos_achievement_user_exceeded_max_earnings($user_id, $achievement_id)) {
        $return = false;
    }
    // If we have access, and the achievement has a parent...
    if ($return && ($parent_achievement = badgeos_get_parent_of_achievement($achievement_id))) {
        // If we don't have access to the parent, we do not have access to this
        if (!badgeos_user_has_access_to_achievement($user_id, $parent_achievement->ID, $this_trigger, $site_id, $args)) {
            $return = false;
        }
        // If the parent requires sequential steps, confirm we've earned all previous steps
        if ($return && badgeos_is_achievement_sequential($parent_achievement->ID)) {
            foreach (badgeos_get_children_of_achievement($parent_achievement->ID) as $sibling) {
                // If this is the current step, we're good to go
                if ($sibling->ID == $achievement_id) {
                    break;
                }
                // If we haven't earned any previous step, we can't earn this one
                if (!badgeos_get_user_achievements(array('user_id' => absint($user_id), 'achievement_id' => absint($sibling->ID)))) {
                    $return = false;
                    break;
                }
            }
        }
    }
    // Available filter for custom overrides
    return apply_filters('user_has_access_to_achievement', $return, $user_id, $achievement_id, $this_trigger, $site_id, $args);
}