'Return a list of PlaylistProgress objects associated with the user.'

@classmethod
def user_progress(cls, user_id, language=None):

    if (not language):
        language = (Settings.get('default_language') or settings.LANGUAGE_CODE)
    user = FacilityUser.objects.get(id=user_id)
    (user_vid_logs, user_ex_logs) = cls.get_user_logs(user)
    exercise_ids = list(set([ex_log['exercise_id'] for ex_log in user_ex_logs]))
    video_ids = list(set([vid_log['video_id'] for vid_log in user_vid_logs]))
    user_playlists = get_content_parents(ids=(exercise_ids + video_ids), language=language)
    user_progress = list()
    for (i, p) in enumerate(user_playlists):
        (pl_video_ids, pl_exercise_ids) = cls.get_playlist_entry_ids(p)
        n_pl_videos = float(len(pl_video_ids))
        n_pl_exercises = float(len(pl_exercise_ids))
        pl_ex_logs = [ex_log for ex_log in user_ex_logs if (ex_log['exercise_id'] in pl_exercise_ids)]
        pl_vid_logs = [vid_log for vid_log in user_vid_logs if (vid_log['video_id'] in pl_video_ids)]
        n_vid_complete = len([vid for vid in pl_vid_logs if vid['complete']])
        n_vid_started = len([vid for vid in pl_vid_logs if ((vid['total_seconds_watched'] > 0) and (not vid['complete']))])
        vid_pct_complete = (int(((float(n_vid_complete) / n_pl_videos) * 100)) if n_pl_videos else 0)
        vid_pct_started = (int(((float(n_vid_started) / n_pl_videos) * 100)) if n_pl_videos else 0)
        if (vid_pct_complete == 100):
            vid_status = 'complete'
        elif (n_vid_started > 0):
            vid_status = 'inprogress'
        else:
            vid_status = 'notstarted'
        n_ex_mastered = len([ex for ex in pl_ex_logs if ex['complete']])
        n_ex_started = len([ex for ex in pl_ex_logs if (ex['attempts'] > 0)])
        n_ex_incomplete = len([ex for ex in pl_ex_logs if ((ex['attempts'] > 0) and (not ex['complete']))])
        n_ex_struggling = len([ex for ex in pl_ex_logs if ex['struggling']])
        ex_pct_mastered = int(((float(n_ex_mastered) / (n_pl_exercises or 1)) * 100))
        ex_pct_incomplete = int(((float(n_ex_incomplete) / (n_pl_exercises or 1)) * 100))
        ex_pct_struggling = int(((float(n_ex_struggling) / (n_pl_exercises or 1)) * 100))
        if (not n_ex_started):
            ex_status = 'notstarted'
        elif (ex_pct_struggling > 0):
            ex_status = 'struggling'
        elif (ex_pct_mastered < 99):
            ex_status = 'inprogress'
        else:
            ex_status = 'complete'
        progress = {'title': p.get('title'), 'id': p.get('id'), 'tag': p.get('tag'), 'vid_pct_complete': vid_pct_complete, 'vid_pct_started': vid_pct_started, 'vid_status': vid_status, 'ex_pct_mastered': ex_pct_mastered, 'ex_pct_incomplete': ex_pct_incomplete, 'ex_pct_struggling': ex_pct_struggling, 'ex_status': ex_status, 'n_pl_videos': n_pl_videos, 'n_pl_exercises': n_pl_exercises}
        try:
            progress['url'] = reverse('view_playlist', kwargs={'playlist_id': p.get('id')})
        except NoReverseMatch:
            progress['url'] = (reverse('learn') + p.get('path'))
        user_progress.append(cls(**progress))
    return user_progress
