def class_progress_report_graph_context(user_data, list_students):
    if not user_data:
        return {}

    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [(escape(s.email), (s.nickname[:14] + '...')
                            if len(s.nickname) > 17
                            else s.nickname)
                           for s in list_students]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    exercises_all = Exercise.get_all_use_cache()
    user_exercise_graphs = UserExerciseGraph.get(list_students)

    exercises_found = []

    for exercise in exercises_all:
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(exercise.name)
            if graph_dict and graph_dict["total_done"]:
                exercises_found.append(exercise)
                break

    exercise_names = [(e.name, e.display_name, escapejs(e.name))
                      for e in exercises_found]

    exercise_list = [{'name': e.name, 'display_name': e.display_name}
                     for e in exercises_found]

    exercise_data = {}

    for (student, _, _, user_exercise_graph) in izip(list_students,
                                                     student_email_pairs,
                                                     emails_escapejsed,
                                                     user_exercise_graphs):
        student_email = student.email

        for (exercise, (_, _, _)) in izip(exercises_found, exercise_names):

            exercise_name = exercise.name
            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            status = ""

            if graph_dict["proficient"]:

                if graph_dict["reviewing"]:
                    status = "Herzien"
                else:
                    status = "Gehaald"
                    if not graph_dict["explicitly_proficient"]:
                        status = ("Gehaald")

            elif graph_dict["struggling"]:
                status = "Moeite"
            elif graph_dict["total_done"] > 0:
                status = "Gestart"

            if student_email not in exercise_data:
                exercise_data[student_email] = {
                    'email': student.email,
                    'nickname': student.nickname,
                    'profile_root': student.profile_root,
                    'exercises': []
                }

            if len(status) > 0:
                exercise_data[student_email]['exercises'].append({
                    "status": status,
                    "progress": graph_dict["progress"],
                    "total_done": graph_dict["total_done"],
                    "last_done": (graph_dict["last_done"]
                                  if (graph_dict["last_done"] and
                                      graph_dict["last_done"].year > 1)
                                  else ''),
                    "last_done_ago": (timesince_ago(graph_dict["last_done"])
                                      if (graph_dict["last_done"] and
                                          graph_dict["last_done"].year > 1)
                                      else '')
                })
            else:
                exercise_data[student_email]['exercises'].append({
                    "name": exercise_name,
                    "status": status,
                })

    student_row_data = [data for (_, data) in exercise_data.iteritems()]

    return {
        'exercise_names': exercise_list,
        'exercise_data': student_row_data,
        'coach_email': user_data.email,
        'c_points': reduce(lambda a, b: a + b,
                           map(lambda s: s.points, list_students),
                           0)
    }
def class_progress_report_graph_context(user_data, list_students, days=31):
    if not user_data:
        return {}


    all_topic_names, videos_all, exercises_all = get_content_data()
    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [(escape(s.email), (s.nickname[:14] + '...') if len(s.nickname) > 17 else s.nickname) for s in list_students]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    user_exercise_graphs = UserExerciseGraph.get(list_students)

    exercise_list = []

    for name, exercise in exercises_all.iteritems():
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(name)
            if graph_dict and graph_dict["total_done"]:
                exercise_list.append(exercise)
                break

    exercise_list.sort(key=lambda e: e["display_name"])

    all_video_progress = get_video_progress_for_students(list_students, days=days)
    videos_found = reduce(set.union, all_video_progress.itervalues(), set())
    video_list = [videos_all[vid_id] for vid_id in videos_found if vid_id in videos_all]
    video_list.sort(key=lambda v: v["display_name"])

    progress_data = {}

    for (student, student_email_pair, escapejsed_student_email, user_exercise_graph) in izip(list_students, student_email_pairs, emails_escapejsed, user_exercise_graphs):

        student_email = student.email
        student_review_exercise_names = user_exercise_graph.review_exercise_names()
        progress_data[student_email] = student_data = {
            'email': student.email,
            'nickname': student.nickname,
            'profile_root': student.profile_root,
            'exercises': [],
            'videos': [],
        }

        for e in exercise_list:
            exercise_name, exercise_display, exercise_name_js =  e["name"], e["display_name"], escapejs(e["name"])

            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            status_name = ""

            if graph_dict["proficient"]:
                if exercise_name in student_review_exercise_names:
                    status_name = "review"
                else:
                    if not graph_dict["explicitly_proficient"]:
                        status_name = "proficient_implicit"
                    else:
                        status_name = "proficient"
            elif graph_dict["struggling"]:
                status_name = "struggling"
            elif graph_dict["total_done"] > 0:
                status_name = "started"

            if status_name:
                student_data['exercises'].append({
                    "status_name": status_name,
                    "progress": graph_dict["progress"],
                    "total_done": graph_dict["total_done"],
                    "last_done": graph_dict["last_done"] if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else '',
                    "last_done_ago": timesince_ago(graph_dict["last_done"]) if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else ''
                })
            else:
                student_data['exercises'].append({
                    "name": exercise_name,
                    "status_name": status_name,
                })

        video_progress = all_video_progress[student]
        for video in video_list:
            status_name = video_progress.get(video["key_id"], "")
            student_data['videos'].append({
                    "name": video["display_name"],
                    "status_name": status_name,
                })

    # prune topics
    topic_names = {
        topic_id: all_topic_names[topic_id]
        for item in chain(exercise_list, video_list)
        for topic_id in item['topics']
    }

    # clean-up video list
    for video in video_list:
        video.pop("key_id")

    student_row_data = [data for key, data in progress_data.iteritems()]

    return {
        'exercise_names': exercise_list,
        'video_names': video_list,
        'topic_names': topic_names,
        'progress_data': student_row_data,
        'coach_email': user_data.email,
        'c_points': reduce(lambda a, b: a + b, map(lambda s: s.points, list_students), 0)
    }
def class_progress_report_graph_context(user_data, list_students):
    if not user_data:
        return {}

    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [(escape(s.email), (s.nickname[:14] + '...') if len(s.nickname) > 17 else s.nickname) for s in list_students]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    exercises_all = Exercise.get_all_use_cache()
    user_exercise_graphs = UserExerciseGraph.get(list_students)

    exercises_found = []

    for exercise in exercises_all:
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(exercise.name)
            if graph_dict and graph_dict["total_done"]:
                exercises_found.append(exercise)
                break

    exercise_names = [(e.name, e.display_name, escapejs(e.name)) for e in exercises_found]
    exercise_list = [{'name': e.name, 'display_name': e.display_name} for e in exercises_found]

    videos_all = Video.get_all()
    all_video_progress = dict(zip(list_students, get_video_progress_for_students(list_students)))
    videos_found = reduce(set.union, all_video_progress.itervalues(), set())

    videos_found = [video for video in videos_all if video.key().id() in videos_found]
    video_list = [{'name': v.readable_id, 'display_name': v.title} for v in videos_found]

    progress_data = {}

    for (student, student_email_pair, escapejsed_student_email, user_exercise_graph) in izip(list_students, student_email_pairs, emails_escapejsed, user_exercise_graphs):

        student_email = student.email

        student_review_exercise_names = user_exercise_graph.review_exercise_names()

        progress_data[student_email] = student_data = {
            'email': student.email,
            'nickname': student.nickname,
            'profile_root': student.profile_root,
            'exercises': [],
            'videos': [],
        }

        for (exercise, (_, exercise_display, exercise_name_js)) in izip(exercises_found, exercise_names):

            exercise_name = exercise.name
            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            status = ""
            status_name = ""

            if graph_dict["proficient"]:
                if exercise_name in student_review_exercise_names:
                    status_name = "review"
                else:
                    if not graph_dict["explicitly_proficient"]:
                        status_name = "proficient_implicit"
                    else:
                        status_name = "proficient"
            elif graph_dict["struggling"]:
                status_name = "struggling"
            elif graph_dict["total_done"] > 0:
                status_name = "started"

            status = STATUSES[status_name]
            if status:
                student_data['exercises'].append({
                    "status": status,
                    "status_name": status_name,
                    "progress": graph_dict["progress"],
                    "total_done": graph_dict["total_done"],
                    "last_done": graph_dict["last_done"] if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else '',
                    "last_done_ago": timesince_ago(graph_dict["last_done"]) if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else ''
                })
            else:
                student_data['exercises'].append({
                    "name": exercise_name,
                    "status": status,
                })

        video_progress = all_video_progress[student]
        for video in videos_found:
            status_name = video_progress.get(video.key().id(), "")
            status = STATUSES[status_name]
            student_data['videos'].append({
                    "name": video.title,
                    "status": status,
                    "status_name": status_name,
                })


    student_row_data = [data for key, data in progress_data.iteritems()]

    return {
        'exercise_names': exercise_list,
        'video_names': video_list,
        'progress_data': student_row_data,
        'coach_email': user_data.email,
        'c_points': reduce(lambda a, b: a + b, map(lambda s: s.points, list_students), 0)
    }
def class_progress_report_graph_context(user_data, list_students):
    if not user_data:
        return {}

    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [(escape(s.email), (s.nickname[:14] + '...') if len(s.nickname) > 17 else s.nickname) for s in list_students]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    exercises_all = Exercise.get_all_use_cache()
    user_exercise_graphs = UserExerciseGraph.get(list_students)

    exercises_found = []

    for exercise in exercises_all:
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(exercise.name)
            if graph_dict and graph_dict["total_done"]:
                exercises_found.append(exercise)
                break

    exercise_names = [(e.name, e.display_name, escapejs(e.name)) for e in exercises_found]
    exercise_list = [{'name': e.name, 'display_name': e.display_name} for e in exercises_found]

    exercise_data = {}

    for (student, student_email_pair, escapejsed_student_email, user_exercise_graph) in izip(list_students, student_email_pairs, emails_escapejsed, user_exercise_graphs):

        student_email = student.email

        student_review_exercise_names = user_exercise_graph.review_exercise_names()

        for (exercise, (_, exercise_display, exercise_name_js)) in izip(exercises_found, exercise_names):

            exercise_name = exercise.name
            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            status = ""

            if graph_dict["proficient"]:

                if exercise_name in student_review_exercise_names:
                    status = "Review"
                else:
                    status = "Proficient"
                    if not graph_dict["explicitly_proficient"]:
                        status = "Proficient (due to proficiency in a more advanced module)"

            elif graph_dict["struggling"]:
                status = "Struggling"
            elif graph_dict["total_done"] > 0:
                status = "Started"

            if student_email not in exercise_data:
                exercise_data[student_email] = {
                    'email': student.email,
                    'nickname': student.nickname,
                    'exercises': []
                }

            if len(status) > 0:
                exercise_data[student_email]['exercises'].append({
                    "status": status,
                    "progress": graph_dict["progress"],
                    "total_done": graph_dict["total_done"],
                    "last_done": graph_dict["last_done"] if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else '',
                    "last_done_ago": timesince_ago(graph_dict["last_done"]) if graph_dict["last_done"] and graph_dict["last_done"].year > 1 else ''
                })
            else:
                exercise_data[student_email]['exercises'].append({
                    "name": exercise_name,
                    "status": status,
                })

    student_row_data = [data for key, data in exercise_data.iteritems()]

    return {
        'exercise_names': exercise_list,
        'exercise_data': student_row_data,
        'coach_email': user_data.email,
        'c_points': reduce(lambda a, b: a + b, map(lambda s: s.points, list_students), 0)
    }
def class_progress_report_graph_context(user_data, student_list):

    if not user_data:
        return {}

    list_students = None
    if student_list:
        list_students = student_list.get_students_data()
    else:
        list_students = user_data.get_students_data()

    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [(escape(s.email), truncate_to(s.nickname, 18)) for s in list_students]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    exercises_all = models.Exercise.get_all_use_cache()
    user_exercise_graphs = models.UserExerciseGraph.get(list_students)

    exercises_found = []

    for exercise in exercises_all:
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(exercise.name)
            if graph_dict and graph_dict["total_done"]:
                exercises_found.append(exercise)
                break

    exercise_names = [(e.name, e.display_name, escapejs(e.name)) for e in exercises_found]

    exercise_data = {}

    for (student, student_email_pair, escapejsed_student_email, user_exercise_graph) in izip(list_students, student_email_pairs, emails_escapejsed, user_exercise_graphs):

        student_email = student.email
        escaped_nickname = escape(student.nickname)
        escaped_student_email = student_email_pair[0]
        truncated_nickname = student_email_pair[1]

        student_review_exercise_names = user_exercise_graph.review_exercise_names()

        for (exercise, (_, exercise_display, exercise_name_js)) in izip(exercises_found, exercise_names):

            exercise_name = exercise.name
            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            if not exercise_data.has_key(exercise_name):
                exercise_data[exercise_name] = {}

            link = "/profile/graph/exerciseproblems?student_email=%s&exercise_name=%s" % \
                (escapejsed_student_email, exercise_name_js)

            status = ""
            hover = ""
            color = "transparent"

            if graph_dict["proficient"]:

                if exercise_name in student_review_exercise_names:
                    status = "Review"
                    color = "review light"
                else:
                    status = "Proficient"
                    color = "proficient"
                    if not graph_dict["explicitly_proficient"]:
                        status = "Proficient (due to proficiency in a more advanced module)"
                        
            elif graph_dict["struggling"]:
                status = "Struggling"
                color = "struggling"
            elif graph_dict["total_done"] > 0:
                status = "Started"
                color = "started"

            if len(status) > 0:
                hover = \
"""<b>%s</b><br/>
<b>%s</b><br/>
<em><nobr>Status: %s</nobr></em><br/>
<em>Progress: %s</em><br/>
<em>Problems attempted: %s</em>""" % (escaped_nickname,
                                      exercise_display,
                                      status,
                                      models.UserExercise.to_progress_display(graph_dict["progress"]),
                                      graph_dict["total_done"])

            exercise_data[exercise_name][escaped_student_email] = {
                "link": link,
                "hover": hover,
                "color": color
            }

    return {
        'student_emails': student_email_pairs,
        'exercise_names': exercise_names,
        'exercise_data': exercise_data,
        'coach_email': user_data.email,
        'user_data_students': list_students,
        'c_points': reduce(lambda a, b: a + b, map(lambda s: s.points, list_students), 0)
    }
def class_progress_report_graph_context(user_data, list_students):
    if not user_data:
        return {}

    list_students = sorted(list_students, key=lambda student: student.nickname)

    student_email_pairs = [
        (escape(s.email),
         (s.nickname[:14] + '...') if len(s.nickname) > 17 else s.nickname)
        for s in list_students
    ]
    emails_escapejsed = [escapejs(s.email) for s in list_students]

    exercises_all = Exercise.get_all_use_cache()
    user_exercise_graphs = UserExerciseGraph.get(list_students)

    exercises_found = []

    for exercise in exercises_all:
        for user_exercise_graph in user_exercise_graphs:
            graph_dict = user_exercise_graph.graph_dict(exercise.name)
            if graph_dict and graph_dict["total_done"]:
                exercises_found.append(exercise)
                break

    exercise_names = [(e.name, e.display_name, escapejs(e.name))
                      for e in exercises_found]
    exercise_list = [{
        'name': e.name,
        'display_name': e.display_name
    } for e in exercises_found]

    videos_all = Video.get_all()
    all_video_progress = dict(
        zip(list_students, get_video_progress_for_students(list_students)))
    videos_found = reduce(set.union, all_video_progress.itervalues(), set())

    videos_found = [
        video for video in videos_all if video.key().id() in videos_found
    ]
    video_list = [{
        'name': v.readable_id,
        'display_name': v.title
    } for v in videos_found]

    progress_data = {}

    for (student, student_email_pair, escapejsed_student_email,
         user_exercise_graph) in izip(list_students, student_email_pairs,
                                      emails_escapejsed, user_exercise_graphs):

        student_email = student.email

        student_review_exercise_names = user_exercise_graph.review_exercise_names(
        )

        progress_data[student_email] = student_data = {
            'email': student.email,
            'nickname': student.nickname,
            'profile_root': student.profile_root,
            'exercises': [],
            'videos': [],
        }

        for (exercise, (_, exercise_display,
                        exercise_name_js)) in izip(exercises_found,
                                                   exercise_names):

            exercise_name = exercise.name
            graph_dict = user_exercise_graph.graph_dict(exercise_name)

            status = ""
            status_name = ""

            if graph_dict["proficient"]:
                if exercise_name in student_review_exercise_names:
                    status_name = "review"
                else:
                    if not graph_dict["explicitly_proficient"]:
                        status_name = "proficient_implicit"
                    else:
                        status_name = "proficient"
            elif graph_dict["struggling"]:
                status_name = "struggling"
            elif graph_dict["total_done"] > 0:
                status_name = "started"

            status = STATUSES[status_name]
            if status:
                student_data['exercises'].append({
                    "status":
                    status,
                    "status_name":
                    status_name,
                    "progress":
                    graph_dict["progress"],
                    "total_done":
                    graph_dict["total_done"],
                    "last_done":
                    graph_dict["last_done"] if graph_dict["last_done"]
                    and graph_dict["last_done"].year > 1 else '',
                    "last_done_ago":
                    timesince_ago(graph_dict["last_done"])
                    if graph_dict["last_done"]
                    and graph_dict["last_done"].year > 1 else ''
                })
            else:
                student_data['exercises'].append({
                    "name": exercise_name,
                    "status": status,
                })

        video_progress = all_video_progress[student]
        for video in videos_found:
            status_name = video_progress.get(video.key().id(), "")
            status = STATUSES[status_name]
            student_data['videos'].append({
                "name": video.title,
                "status": status,
                "status_name": status_name,
            })

    student_row_data = [data for key, data in progress_data.iteritems()]

    return {
        'exercise_names':
        exercise_list,
        'video_names':
        video_list,
        'progress_data':
        student_row_data,
        'coach_email':
        user_data.email,
        'c_points':
        reduce(lambda a, b: a + b, map(lambda s: s.points, list_students), 0)
    }