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.vary import vary_on_cookie
#from django.views.decorators.cache import cache_page
import itertools

def question_groupby_keygen(qdict):
    question, exten = qdict['base'], qdict['extension']
    qtype = question.qtype
    style = hasattr(exten, 'style') and exten.style or None
    qtypet = 'survey/' + slugify(qtype)
    stylet = style is not None and 'survey/'+slugify(qtype+"-"+style) or None
    subset = None
    if qtype == 'SingleSelection' and style == 'RS':
        if exten.remote:
            subset = list((repr(choice) for choice in exten.get_choice_list()))
        else:
            subset = list((choice.label
                       for choice in exten.get_singlechoice_list(
                            order_by=['rank', 'id', 'label'])))
        if exten.na:
            subset.append('N/A')
    return (qtype, qtypet, style, stylet, subset)

def expand_group_iter(iter):
    return tuple((a, tuple(b)) for a, b in iter)

def index(request):
    s = surveys.get_list(where=["live IS TRUE"])
    c = Context(request, {
            'surveys': s,
            })
    t = template_loader.get_template('survey/index')
    return HttpResponse(t.render(c))

def thankyou(request, survey):
    sobj = surveys.get_object(name__exact=survey)
    thx = template_loader.get_template('survey/thankyou')
    cont = Context(request, { 'survey': sobj } )
    return HttpResponse(thx.render(cont))

def basic_survey(request, survey_obj, categories, errors={},
                 template='survey/survey', action='', method='post',
                 submit=None):
    submit = submit is None and survey_obj.label or submit
    cont = Context(request, {
        'errors': errors,
        'mobile': 'mobile' in request.GET,
        'action': action,
        'method': method,
        'submit': submit,
        'survey': survey_obj,
        'catset_iter': [
            { 'errors': errors,
              'category': cat,
              'qgroups': expand_group_iter(itertools.groupby( (
                { 'base': q, 'extension': q.get_extension() }
                    for q in cat.get_question_list(
                        order_by=['rank', 'question']) ),
                                           question_groupby_keygen)) }
            for cat in categories] } )

    tsurvey = template_loader.get_template(template)
    request.session.set_test_cookie()
    return HttpResponse(tsurvey.render(cont))

def submit_survey(request, survey_obj):
    submit = submissions.Submission(ipaddr=request.META['REMOTE_ADDR'],
                                    survey_id=survey_obj.id)
    if request.session.test_cookie_worked():
        request.session.delete_test_cookie()
        submit.session = request.session.session_key
        try:    sessions.get_object(pk=request.session.session_key)
        except: request.session['save'] = True ## force cookie and DB save
    else:
        try:    sessions.get_object(pk=request.session.session_key)
        except: pass
        else:   submit.session = request.session.session_key
    submit.save()
    for smdict in (request.POST, request.GET):
        for qid, answer_list in smdict.lists():
            rank = None
            if 'other' in qid:
                if 'data' not in qid: continue
                rank, qid = '-1', qid.split('.')[0]
            elif not qid.replace('.', '').isdigit(): continue
            elif '.' in qid: qid, rank = qid.split('.',1)
            for answer in answer_list:
                if answer: answers.createAnswer(submit, qid, answer, rank)
    return HttpResponseRedirect("thankyou")

def survey(request, survey):
    errors = {}
    sobj = surveys.get_object(name__exact=survey)
    cats = sobj.get_category_list(order_by=['rank', 'name'])
    if request.POST:
        ## Ok, so I should have a custom Manipulator which key's off of
        ## the question type (label for tags look like:
        ## 'id_<type>.<question_id>[.<rank>]' which can be used to do the
        ## manipulation and validataion if any and set any errors to be
        ## rendered below and have the form re-posted. Thats a bunch of work
        ## and Im not doing it now. Especially sence we are just taking the raw
        ## data and putting it into a text field to be parsed later.
        ## That is where a manipulator would be extreemly useful, to turn
        ## the test fields back into python objects of the proper type.
        ## Again, not enought time, and hand coding that in the question
        ## extension class is more expediant.
        res = submit_survey(request, sobj)
        if isinstance(res, dict):
            errors = res
        else:
            return res
    if sobj.view:
        view = sobj.get_custom_view()
        return view(request, sobj, cats, errors)
    return basic_survey(request, sobj, cats, errors)

def twopage(request, survey_obj, categories, errors={}):
    topcat = categories[0]
    categories = categories[1:]
    if 'submit' in request.GET and request.GET['submit'] == "Next >>":
        gd = dict(request.GET.lists())
        def find_all(qid):
            res = []
            for name in gd:
                if ('.' in name and name.replace('.','').isdigit() and
                    name.startswith(qid)):
                    res.extend(gd[name])
            return res
        cats = []
        for cat in categories:
            cont = cat.get_contingency()
            qid  = cont is not None and str(cont.question.id) or None
            if cont is None:
                cats.append(cat)
            elif qid in gd and cont.answer in gd[qid]:
                cats.append(cat)
            elif cont.answer in find_all(qid):
                cats.append(cat)
        return basic_survey(request, survey_obj, cats, errors)
    return basic_survey(request, survey_obj, [topcat], errors,
                        submit="Next >>", method="get")


#### What the @$#%^#$^ does that bit of code do?
#### Glad you asked... its does alot.
#### It bhilds a structure which looks like this
#### (if the generators and iterators are expanded that is)
#### We build a huge context (well not huge thanks to iters and geners)
#### { 'action': <form action>,
####   'survey': <survey model obj>,
####   'catset_iter':
####       #     Type,     template, Style, template, Sub-Listing
####       ( ( ('Boolean', 'boolean', 'C', 'boolean-c', None),
####           ( { 'base': <Question Model obj>,
####             { 'extension': <BooleanQuestion Model obj> },
####             .... some more booleans maybe ....              ), ),
####         ( ('String', 'string', None, None, None),
####           ( { 'base': <Question Model obj>,
####               'extension': <StringQuestion Model obj> },
####             .... some more strings maybe ....               ), ),
####         # this is type-style groupby sorting of questions sorted by rank
####         # so we see another bool just like the first group....
####         ( ('Boolean', 'boolean', 'C', 'boolean-c', None),
####           ( { 'base': <Question Model obj>,
####             { 'extension': <BooleanQuestion Model obj> },
####             .... you get the idea ....                      ), ),
####         # THIS is the reason for the groupby complexity!!!
####         ( ('SingleSelection', 'singleselection', 'RS',
####            'singleselection-rs', ('choice-label-1', .., 'choice-label-N')),
####           ( { 'base': <Question Model obj>, ## Question 1 of the table
####             { 'extension': <SingleSelectionQuestion Model Obj> },
####           ( { 'base': <Question Model obj>, ## Question 2 of the table
####             { 'extension': <SingleSelectionQuestion Model Obj> },
####           ( { 'base': <Question Model obj>, ## Question 3 of the table
####             { 'extension': <SingleSelectionQuestion Model Obj> },
####         #### We would have a different singleselection-rs here if the
####         #### labels change... yea!!
####
