from django.core.extensions import get_object_or_404
from django.core.extensions import render_to_response
from django.core import template
from django.core import template_loader
from django.utils.httpwrappers import HttpResponse
from django.utils.httpwrappers import HttpResponseRedirect
from django.models.survey import surveys, questions, categories
from django.models.survey import submissions, answers
from django.core.extensions import DjangoContext as Context
from django.core.template.defaultfilters import slugify
from django.views.decorators.auth import user_passes_test
from django.views.decorators.cache import cache_page
import datetime
#from django.views.decorators.vary import vary_on_cookie
#from django.views.decorators.cache import cache_page
from itertools import *
import re

before_days = (datetime.date(2005, 02, 23), datetime.date(2006, 02, 22))
tutorial_days = (datetime.date(2006, 02, 22), datetime.date(2006, 02, 23))
convention_days = (datetime.date(2006, 02, 23), datetime.date(2006, 02, 27))
sprint_days = (datetime.date(2006, 02, 27), datetime.date(2006, 03, 02))
after_days = (datetime.date(2006, 03, 02), datetime.date(2007, 03, 02))

def fixed_cache_page(timeout=None):
    def _fixed_cache_page_wrapper(func):
        return cache_page(func, cache_timeout=timeout)
    return _fixed_cache_page_wrapper

def user_has_perm(user, perm):
    # Why isn't there a helper for doing this?
    return not user.is_anonymous() and user.is_active and (
                user.is_superuser or user.is_staff or user.has_perm(perm))

## rather useful for contexts and IDE tags integration
def mkdict(**kwds): return kwds

@user_passes_test(lambda u: user_has_perm(u, 'survey.can_view_results'),
                  login_url='/apps/login/')
@fixed_cache_page(60*60*12*24) ## cache for 24 hours
def result_index(request):
    submission_count = submissions.get_count()
    first_sub = 0
    last_sub = 0
    def format_submissions_for(days):
        count = submissions.get_count(datetime__range=days)
        if not count: return 0
        return "%d (%.1f%%)" % (count, float(count * 100)/submission_count)
    def format_survey_stats(count, parent_count=0, mac_count=0):
        if parent_count:
            return "%d (%.1f%%/%.1f%%)" % (count,
                        float(count * 100)/parent_count,
                        float(count * 100)/submission_count)
        if mac_count:
            return "%d (%.1f%%) from %d machines" % (count,
                        float(count * 100)/submission_count, mac_count)
        return "%d (%.1f%%)" % (count, float(count * 100)/submission_count)

    if submission_count:
        first_sub = submissions.get_list(order_by=['datetime'],
                                         limit=1)[0].datetime.ctime()
        last_sub  = submissions.get_list(order_by=['-datetime'],
                                         limit=1)[0].datetime.ctime()
    num_ans = answers.get_count()
    num_sess = len(submissions.get_values(fields=['session'], distinct=True,
                                          order_by=[]))
    survey_list = surveys.get_list()
    note="<i>(note: paper and kiosk submissions skew result)</i>"
    stat_list = [
        mkdict(name="Submissions", value=submission_count),
        mkdict(name="before convention", indent=True,
               value=format_submissions_for(before_days)),
        mkdict(name="durring tutorials", indent=True,
               value=format_submissions_for(tutorial_days)),
        mkdict(name="durring convention", indent=True,
               value=format_submissions_for(convention_days)),
        mkdict(name="durring sprints", indent=True,
               value=format_submissions_for(sprint_days)),
        mkdict(name="after convention", indent=True,
               value=format_submissions_for(after_days)),
        mkdict(name="first on", indent=True, value=first_sub),
        mkdict(name="last on", indent=True, value=last_sub),
        mkdict(name="Uniq machines", value=num_sess),
        mkdict(name="avg. submissions", indent=True,
               value="%.1f %s" % (float(submission_count)/num_sess, note)),
        mkdict(name="Answers", value=num_ans),
        mkdict(name="avg. per submission", indent=True,
               value="%.1f" % (float(num_ans)/submission_count)),
        mkdict(name="avg. per machine", indent=True,
               value="%.1f %s" %(float(num_ans)/num_sess, note)),
    ]
    survey_meta_list = []
    num_sub_surveys = 0
    num_overview = 0
    num_proper = 0
    for survey in survey_list:
        sub_count = survey.get_submission_count()
        mac_count = len(submissions.get_values(order_by=[],
                            where=['"survey_id"=%d' % survey.id],
                            fields=['session'], distinct=True))
        if not sub_count: continue
        survey_meta_list.append(mkdict(title=survey.title,
                                       url=survey.name,
                                       stats=format_survey_stats(sub_count,
                                                mac_count=mac_count)))
        subset = []
        if survey.view:
            ## RED_FLAG: bogus assumption we are dealing with two page
            cat = survey.get_category_list(limit=1)
            if not cat: continue
            cat = cat[0]
            quest = cat.get_question_list(limit=1)
            if not quest: continue
            quest = quest[0]
            qid = quest.id
            ans_set = answers.get_values(where=['"question_id"=%d' % qid],
                                         order_by=[],
                                         fields=['answer'], distinct=True)
            if not ans_set: continue
            for ad in ans_set:
                answer = ad['answer']
                num_w_answer = quest.get_answer_count(answer__exact=answer)
                subset.append(mkdict(sub=True,
                    title=answer,
                    url="-".join([survey.name, str(qid), answer]),
                    stats=format_survey_stats(num_w_answer, sub_count)))
            subset.sort(key=lambda x: x['stats'], reverse=True)
            survey_meta_list.extend(subset)
        if subset:
            num_overview += 1
            num_sub_surveys += len(subset)
        else:
            num_proper += 1
    stat_list.insert(0, mkdict(name="specialization", indent=True,
                               value=num_sub_surveys))
    stat_list.insert(0, mkdict(name="overview (merged)", indent=True,
                               value=num_overview))
    stat_list.insert(0, mkdict(name="regular", indent=True,
                               value=num_proper))
    stat_list.insert(0, mkdict(name="Survey Results",
                               value=len(survey_meta_list)))
    c = Context(request, {
        'title' :      "2006 Survey Results",
        'num_subs':    submission_count,
        'stat_list':   stat_list,
        'survey_list': survey_meta_list,
        })
    t = template_loader.get_template('results/index')
    return HttpResponse(t.render(c))


@user_passes_test(lambda u: user_has_perm(u, 'survey.can_view_results'),
                  login_url='/apps/login/')
@fixed_cache_page(60*60*12*24) ## cache for 24 hours
def survey_result(request, survey):
    question, answer = "", ""
    # man this breaks REST, should be done with the url pattern stuff...
    if "-" in survey:
        survey, question, answer = survey.split('-', 2)
    sobj = surveys.get_object(name__exact=survey)
    cats = sobj.get_category_list(order_by=['rank', 'name'])

    ans_list = []
    submission_count = 0
    limit = {}
    title = sobj.title
    if question:
        # get the sessions to limit by.
        ### *SIGH* MORE django bugs....
        sub_ans_list = answers.get_list(
            where=['"question_id"=' + question,
                   '"answer"=\'' + answer.replace("'", "\\'") + "'"])
        submission_ids = [ ans.submission_id for ans in sub_ans_list ]
        #limit['submission__in'] = submission_ids
        limit['where']=['id IN (' + ", ".join(map(str,submission_ids)) + ")"]
        ### gah these bugs are killing me
        ans_list = sobj.get_answer_list( #submission_id__in = submission_ids,
                        where=['"question_id"!=' + question,
                               '"submission_id" IN (' + ", ".join(
                                            map(str,submission_ids)) + ")"],
                        select_related=True)
        submission_count = len(submission_ids)
        title += " - " + answer
    else:
        submission_count = sobj.get_submission_count()
        ans_list = sobj.get_answer_list(select_related=True)
    def gen_cmp_key(ans):
        quest = ans.get_question()
        return (quest.get_category().rank, quest.rank, ans.question_id)
    ans_list.sort(key=gen_cmp_key)
    def format_submissions_for(days):
        count = sobj.get_submission_count(datetime__range=days, **limit)
        if not count: return 0
        return "%d (%.1f%%)" % (count, float(count * 100)/submission_count)
    first_sub = 0
    last_sub = 0
    num_mac = 0
    if submission_count:
        num_mac   = len(submissions.get_values(order_by=[],
                            where=(['"survey_id"=%d' % sobj.id] +
                                    limit.get('where', [])),
                            fields=['session'], distinct=True))
        first_sub = sobj.get_submission_list(order_by=['datetime'],
                                             limit=1,
                                             **limit)[0].datetime.ctime()
        last_sub  = sobj.get_submission_list(order_by=['-datetime'],
                                             limit=1,
                                             **limit)[0].datetime.ctime()
    stat_list = [
        mkdict(name="Submissions", value=submission_count),
        mkdict(name="before convention", indent=True,
               value=format_submissions_for(before_days)),
        mkdict(name="durring tutorials", indent=True,
               value=format_submissions_for(tutorial_days)),
        mkdict(name="durring convention", indent=True,
               value=format_submissions_for(convention_days)),
        mkdict(name="durring sprints", indent=True,
               value=format_submissions_for(sprint_days)),
        mkdict(name="after convention", indent=True,
               value=format_submissions_for(after_days)),
        mkdict(name="first on", indent=True, value=first_sub),
        mkdict(name="last on", indent=True, value=last_sub),
        mkdict(name="Uniq Machines", value=num_mac),
        mkdict(name="submissions per", indent=True,
               value="%.1f" % (float(submission_count)/num_mac)),
        mkdict(name="Questions", value=sobj.get_question_count()),
        mkdict(name="Answers", value=len(ans_list)),
        mkdict(name="per submission", indent=True,
               value="%.1f" % (float(len(ans_list))/submission_count)),
    ]
    c = Context(request, {
        'title' :     title,
        'num_subs':   submission_count,
        'stat_list':  stat_list,
        'survey':     sobj,
        'categories': cats,
        'answers' :   ans_list,
        })
    t = template_loader.get_template('results/result')
    return HttpResponse(t.render(c))

