<commit_before>import datetime
import os
import time

from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.core.urlresolvers import reverse
from django.views import generic

from .models import *

from django.utils import timezone
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib import messages
from django.contrib.auth import authenticate, login,logout
from django.contrib.auth.decorators import login_required
from django.core import mail
from prefpy.mechanism import *
from prefpy.allocation_mechanism import *
from prefpy.gmm_mixpl import *
from .email import EmailThread, setupEmail
from groups.models import *
from django.conf import settings
from multipolls.models import *

import json
import threading
import itertools
import django_rq

# view for homepage - index of questions & results
class IndexView(generic.ListView):
    template_name = 'polls/index2.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all().order_by('-pub_date')

class RegularPollsView(generic.ListView):
    template_name = 'polls/regular_polls.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all()
    def get_context_data(self, **kwargs):
        ctx = super(RegularPollsView, self).get_context_data(**kwargs)
        # sort the lists by date (most recent should be at the top)
        ctx['polls_created'] = Question.objects.filter(question_owner = self.request.user, m_poll = False).order_by('-pub_date')
        ctx['polls_participated'] = self.request.user.poll_participated.filter(m_poll = False).exclude(question_owner = self.request.user).order_by('-pub_date')
        return ctx

# the original query will return data from earliest to latest
# reverse the list so that the data is from latest to earliest
def reverseListOrder(query):
    listQuery = list(query)
    listQuery.reverse()
    return listQuery

class MultiPollsView(generic.ListView):
    template_name = 'polls/m_polls.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all()
    def get_context_data(self, **kwargs):
        ctx = super(MultiPollsView, self).get_context_data(**kwargs)
        # sort the list by date
        ctx['multipolls_created'] = reverseListOrder(MultiPoll.objects.filter(owner = self.request.user))
        ctx['multipolls_participated'] = reverseListOrder(self.request.user.multipoll_participated.exclude(owner = self.request.user))
        return ctx

# guest homepage view
class MainView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all().order_by('-pub_date')
    def get_context_data(self, **kwargs):
        ctx = super(MainView, self).get_context_data(**kwargs)
        # sort the list by date
        ctx['question']=Question.objects.first()
        ctx['voting_question'] = Question.objects.filter(question_text="Demo").first()
        ctx['preference'] = 1
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        ctx['view_preferences'] = getViewPreferences()
        
        return ctx

# demo for voting page in main page
# view for question detail
class DemoView(generic.DetailView):
    model = Question
    template_name = 'polls/demo.html'

    def get_order(self, ctx):
        otherUserResponses = self.object.response_set.reverse()
        defaultOrder = ctx['object'].item_set.all()
        #random.shuffle(defaultOrder)
        return defaultOrder
        #return getRecommendedOrder(otherUserResponses, self.request, defaultOrder)

    def get_context_data(self, **kwargs):
        ctx = super(DemoView, self).get_context_data(**kwargs)
        ctx['items'] = self.get_order(ctx)
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

        
# step 1: the intial question object will be created. 
def AddStep1View(request):
    context = RequestContext(request)
    if request.method == 'POST':
        questionString = request.POST['questionTitle']   
        questionDesc = request.POST['desc']
        questionType = request.POST['questiontype']
        imageURL = request.POST['imageURL']
        # create a new question using information from the form and inherit settings from the user's preferences
        question = Question(question_text=questionString, question_desc=questionDesc,
            pub_date=timezone.now(), question_owner=request.user,
            display_pref=request.user.userprofile.displayPref, emailInvite=request.user.userprofile.emailInvite,
            emailDelete=request.user.userprofile.emailDelete, emailStart=request.user.userprofile.emailStart,
            emailStop=request.user.userprofile.emailStop, creator_pref=1)
        if request.FILES.get('docfile') != None:
            question.image = request.FILES.get('docfile')
        elif imageURL != '':
            question.imageURL = imageURL 
        question.question_type = questionType
        question.save()
        setupEmail(question)
        return HttpResponseRedirect(reverse('polls:AddStep2', args=(question.id,)))
    return render_to_response('polls/add_step1.html', {}, context)

# step 2: the owner adds choices to a poll
class AddStep2View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step2.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep2View, self).get_context_data(**kwargs)
        ctx['items'] = self.object.item_set.all()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# step 3: the owner invites voters and groups to a poll
class AddStep3View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step3.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep3View, self).get_context_data(**kwargs)
        ctx['users'] = User.objects.all()
        ctx['groups'] = Group.objects.all()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# step 4: the owner selects the type of poll and other settings    
class AddStep4View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step4.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep4View, self).get_context_data(**kwargs)
        ctx['preference'] = self.request.user.userprofile.displayPref
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        ctx['view_preferences'] = getViewPreferences()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# Add a single choice to a poll.
# - A choice must contain text
# - No duplicate choices (text can't be the same) 
# - The user can add an image to the choice, but images are optional
def addChoice(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    item_text = request.POST['choice']
    imageURL = request.POST['imageURL']
    
    #check for empty strings
    if item_text == "":
        return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
    
    # check for duplicates
    allChoices = question.item_set.all()
    for choice in allChoices:
        if item_text == choice.item_text:
            return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
    
    # create the choice
    item = Item(question=question, item_text=item_text, timestamp=timezone.now())
    
    # if the user uploaded an image or set a URL, add it to the item
    if request.FILES.get('docfile') != None:
        item.image = request.FILES.get('docfile')
    elif imageURL != '':
        item.imageURL = imageURL 
    
    # save the choice
    item.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

def editChoice(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    for item in question.item_set.all():
        new_text = request.POST["item"+str(item.id)]
        item_desc = request.POST["itemdescription"+str(item.id)]
        imageURL = request.POST["imageURL"+str(item.id)]
        if item_desc != "":
            item.item_description = item_desc
        if request.FILES.get("docfile"+str(item.id)) != None:
            item.image = request.FILES.get("docfile"+str(item.id))
        elif imageURL != "":
            item.imageURL = imageURL
        item.item_text = new_text
        item.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

def editBasicInfo(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    new_title = request.POST["title"]
    new_desc = request.POST["desc"]
    question.question_text = new_title
    question.question_desc = new_desc    
    question.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# remove a choice from the poll. 
# deleting choices should only be done before the poll starts
def deleteChoice(request, choice_id):
    item = get_object_or_404(Item, pk=choice_id)
    item.delete()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# permanently erase a poll and all its information and settings
def deletePoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the current user is the owner
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))    
    
    question.delete()
    return HttpResponseRedirect(reverse('polls:index'))

# the voter can opt out of a poll at any time 
def quitPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    
    # notify the user if this option is checked
    if request.user.userprofile.emailDelete:
        email_class = EmailThread(request, question_id, 'remove')
        email_class.start()
        
    # remove from the voter list
    question.question_voters.remove(request.user)
    question.save()

    return HttpResponseRedirect(reverse('polls:regular_polls'))

# when a poll starts, users can cast votes at any time. 
# however, the owner won't be able to remove voters or choices
def startPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the owner started the poll
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))
    
    # set the poll to start
    question.status = 2
    question.save()
    
    # send notification email
    if question.emailStart:
        email_class = EmailThread(request, question_id, 'start')
        email_class.start()

    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))  

# when a poll stops, users can no longer cast votes
# the final results will be calculated and displayed
def stopPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the owner stopped the poll
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))    
    
    # set the status to stop
    question.status = 3
    # get winner or allocation, and save it
    if question.question_type == 1: #poll
        question.winner = getPollWinner(question)
    elif question.question_type == 2: #allocation
        getFinalAllocation(question)
    question.save()

    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# find the winner(s) using the polling algorithm selected earlier 
# Question question
# return String winnerStr
def getPollWinner(question):
    all_responses = question.response_set.filter(active=1).order_by('-timestamp')
    if len(all_responses) == 0:
        return ""

    (latest_responses, previous_responses) = categorizeResponses(all_responses)
    candMap = getCandidateMapFromList(list(question.item_set.all()))
    vote_results, mixtures = getVoteResults(latest_responses,candMap)
    indexVoteResults = question.poll_algorithm - 1
    current_result = vote_results[indexVoteResults]

    winnerStr = ""
    
    #item_set = getCandidateMap(latest_responses[0])
    for index, score in current_result.items():
        # index 5 uses Simplified Bucklin, where score is rank. A low score means it has a high rank (e.g. rank 1 > rank 2), so the best score is the minimum.
        # All other indices rank score from highest to lowest, so the best score would be the maximum.  
        if (score == min(current_result.values()) and indexVoteResults == 5) or (score == max(current_result.values()) and indexVoteResults != 5):
            #add a comma to separate the winners            
            if winnerStr != "":
                winnerStr += ", "
            #add the winner
            winnerStr += candMap[index].item_text
            
            
    result = FinalResult(question=question,timestamp=timezone.now(),result_string="",mov_string="",cand_num=question.item_set.all().count(),node_string="",edge_string="",shade_string="")
    resultstr = ""
    movstr = ""
    nodestr = ""
    edgestr = ""
    shadestr = ""
    mov = getMarginOfVictory(latest_responses,candMap)
    for x in range(0,len(vote_results)):
        for key,value in vote_results[x].items():
            resultstr += str(value)
            resultstr += ","
    for x in range(0,len(mov)):
        movstr += str(mov[x])
        movstr += ","
    resultstr = resultstr[:-1]
    movstr = movstr[:-1]
    (nodes, edges) = parseWmg(latest_responses,candMap)
    for node in nodes:
        for k,v in node.items():
            nodestr += k + "," + str(v) + ";"
        nodestr += "|"
    nodestr = nodestr[:-2]
    for edge in edges:
        for k,v in edge.items():
            edgestr += k + "," + str(v) + ";"
        edgestr += "|"
    edgestr = edgestr[:-2]
    shadevalues = getShadeValues(vote_results)
    for x in shadevalues:
        for y in x:
            shadestr += y + ";"
        shadestr += "|"
    shadestr = shadestr[:-2]
    result.result_string = resultstr
    result.mov_string = movstr
    result.node_string = nodestr
    result.edge_string = edgestr
    result.shade_string = shadestr
    result.save()
    return winnerStr
    
def interpretResult(finalresult):
    candnum = finalresult.cand_num
    resultstr = finalresult.result_string
    movstr = finalresult.mov_string
    shadestr = finalresult.shade_string
    nodestr = finalresult.node_string
    edgestr = finalresult.edge_string
    resultlist = resultstr.split(",")
    movlist = movstr.split(",")
    tempResults = []
    algonum = len(getListPollAlgorithms())
    if len(resultlist) > 0:
        for x in range(0,algonum):
            tempList = []
            for y in range(x*candnum, (x+1)*candnum):
                tempList.append(resultlist[y])
            tempResults.append(tempList)
    tempMargin = []
    for margin in movstr:
        tempMargin.append(margin)
    tempShades = []
    shadelist = shadestr.split(";|")
    for item in shadelist:
        tempShades.append(item.split(";"))
    tempNodes = []
    nodelist = nodestr.split(";|")
    for node in nodelist:
        data = {}
        l = node.split(";")
        for item in l:
            tup = item.split(",")
            data[tup[0]] = tup[1]
        tempNodes.append(data)
    tempEdges = []
    edgelist = edgestr.split(";|")
    for edge in edgelist:
        data = {}
        l = edge.split(";")
        for item in l:
            tup = item.split(",")
            data[tup[0]] = tup[1]
        tempEdges.append(data)
    return [tempResults, tempMargin, tempShades, tempNodes, tempEdges]

# check whether the user clicked 'reset' when ordering preferences
def isPrefReset(request):
    # reset link would have '?order=null' at the end
    orderStr = request.GET.get('order', '')
    if orderStr == "null":
        return True
    return False 

# given a list of responses, return the response's selection data
# List<Response> mostRecentResponse
# return List<List<(Item, int)>> array
def getCurrentSelection(mostRecentResponse):
    responseDict = {}
    if mostRecentResponse.dictionary_set.all().count() > 0:
        responseDict = mostRecentResponse.dictionary_set.all()[0]
    else:
        responseDict = buildResponseDict(mostRecentResponse,mostRecentResponse.question,getPrefOrder(mostRecentResponse.resp_str, mostRecentResponse.question))
    rd = responseDict
    array = []
    for itr in range(mostRecentResponse.question.item_set.all().count()):
        array.append([])
    for itr in rd:
        array[rd[itr] - 1].append(itr)
    return array

# view for question detail
class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

    def get_order(self, ctx):
        otherUserResponses = self.object.response_set.reverse()
        defaultOrder = list(ctx['object'].item_set.all())
        random.shuffle(defaultOrder)
        return defaultOrder
        #commented out to improve performance
        #return getRecommendedOrder(otherUserResponses, self.request, defaultOrder)

    def get_context_data(self, **kwargs):
        ctx = super(DetailView, self).get_context_data(**kwargs)
        ctx['lastcomment'] = ""
        
        #Case for anonymous user
        if self.request.user.get_username() == "":
            if isPrefReset(self.request):
                ctx['items'] = self.object.item_set.all()
                return ctx
            # check the anonymous voter
            if 'anonymousvoter' in self.request.session and 'anonymousid' in self.request.session:
                # sort the responses from latest to earliest
                currentAnonymousResponses = self.object.response_set.filter(anonymous_id = self.request.session['anonymousid']).reverse()
                if len(currentAnonymousResponses) > 0:
                    # get the voter's most recent selection
                    mostRecentAnonymousResponse = currentAnonymousResponses[0]
                    if mostRecentAnonymousResponse.comment:
                        ctx['lastcomment'] = mostRecentAnonymousResponse.comment
                    ctx['currentSelection'] = getCurrentSelection(currentAnonymousResponses[0])
            else:
                # load choices in the default order
                ctx['items'] = self.object.item_set.all()
            return ctx

        # Get the responses for the current logged-in user from latest to earliest
        currentUserResponses = self.object.response_set.filter(user=self.request.user).reverse()
        
        if len(currentUserResponses) > 0:
            if currentUserResponses[0].comment:
                ctx['lastcomment'] = currentUserResponses[0].comment

        # reset button
        if isPrefReset(self.request):
            ctx['items'] = self.get_order(ctx)
            return ctx
        
        # check if the user submitted a vote earlier and display that for modification
        if len(currentUserResponses) > 0: 
            ctx['currentSelection'] = getCurrentSelection(currentUserResponses[0])
            items = []
            for item in ctx['currentSelection']:
                for i in item:
                    items.append(i)
            ctx['items'] = items
            ctx['itr'] = itertools.count(1, 1)
        else:
            # no history so display the list of choices
            ctx['items'] = self.get_order(ctx)
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# view for settings detail
class PollInfoView(generic.DetailView):
    model = Question
    template_name = 'polls/pollinfo.html'
    def get_context_data(self, **kwargs):
        ctx = super(PollInfoView, self).get_context_data(**kwargs)
        emailInvite = Email.objects.filter(question=self.object, type=1)
        if len(emailInvite) == 1:
            setupEmail(self.object)
        if Email.objects.filter(question=self.object).count() > 0:
            ctx['emailInvite'] = Email.objects.filter(question=self.object, type=1)[0]
            ctx['emailDelete'] = Email.objects.filter(question=self.object, type=2)[0]
            ctx['emailStart'] = Email.objects.filter(question=self.object, type=3)[0]
            ctx['emailStop'] = Email.objects.filter(question=self.object, type=4)[0]
        ctx['users'] = User.objects.all()
        ctx['items'] = self.object.item_set.all()
        ctx['groups'] = Group.objects.all()
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        
        # display this user's history
        currentUserResponses = self.object.response_set.filter(user=self.request.user,active=1).order_by('-timestamp')
        ctx['user_latest_responses'] = getSelectionList([currentUserResponses[0]]) if (len(currentUserResponses) > 0) else None
        ctx['user_previous_responses'] = getSelectionList(currentUserResponses[1:])
        
        # get history of all users
        all_responses = self.object.response_set.filter(active=1).order_by('-timestamp')
        (latest_responses, previous_responses) = categorizeResponses(all_responses)
        ctx['latest_responses'] = getSelectionList(latest_responses)
        ctx['previous_responses'] = getSelectionList(previous_responses)    
        
        # get deleted votes
        deleted_responses = self.object.response_set.reverse().filter(active=0).order_by('-timestamp')
        (latest_deleted_responses, previous_deleted_responses) = categorizeResponses(deleted_responses)
        ctx['latest_deleted_responses'] = getSelectionList(latest_deleted_responses)
        ctx[''] = getSelectionList(previous_deleted_responses)
        
        if self.object.question_voters.all().count() > 0:
            progressPercentage = len(latest_responses) / self.object.question_voters.all().count() * 100
            ctx['progressPercentage'] = progressPercentage
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# view for results detail
class AllocateResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/allocate_results.html'

# view for submission confirmation
class ConfirmationView(generic.DetailView):
    model = Question
    template_name = 'polls/confirmation.html'

# view that displays vote results using various algorithms
class VoteResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/vote_rule.html'
    def get_context_data(self, **kwargs):
        ctx = super(VoteResultsView, self).get_context_data(**kwargs)
        
        candMap = getCandidateMapFromList(list(self.object.item_set.all()))
        ctx['cand_map'] = candMap# if (len(latest_responses) > 0) else None
        ctx['poll_algorithms'] = getListPollAlgorithms()
        if hasattr(self.object, 'finalresult'):
            final_result = self.object.finalresult
            l = interpretResult(final_result)
            ctx['vote_results'] = l[0]
            ctx['margin_victory'] = l[1]
            ctx['shade_values'] = l[2]
            ctx['wmg_nodes'] = l[3]
            ctx['wmg_edges'] = l[4]
        else:
            all_responses = self.object.response_set.filter(active=1).order_by('-timestamp')
            (latest_responses, previous_responses) = categorizeResponses(all_responses)
            voteResults, mixtures = getVoteResults(latest_responses,candMap) 
            ctx['vote_results'] = voteResults
            ctx['shade_values'] = getShadeValues(voteResults)
            (nodes, edges) = parseWmg(latest_responses,candMap)
            ctx['wmg_nodes'] = nodes
            ctx['wmg_edges'] = edges
            
            ctx['margin_victory'] = getMarginOfVictory(latest_responses,candMap)
            #ctx['mixtures_pl'] = mixtures[0]
            
        previous_results = self.object.voteresult_set.all()
        ctx['previous_winners'] = []
        for pw in previous_results:
            obj = {}
            obj['title'] = str(pw.timestamp.time())
            candnum = pw.cand_num
            resultstr = pw.result_string
            movstr = pw.mov_string
            if resultstr == "" and movstr == "":
                continue
            resultlist = resultstr.split(",")
            movlist = movstr.split(",")
            tempResults = []
            algonum = len(getListPollAlgorithms())
            if len(resultlist) > 0:
                for x in range(0,algonum):
                    tempList = []
                    for y in range(x*candnum, (x+1)*candnum):
                        tempList.append(resultlist[y])<commit_msg>fixed showing results of old polls<commit_after>import datetime
import os
import time

from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.core.urlresolvers import reverse
from django.views import generic

from .models import *

from django.utils import timezone
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.contrib import messages
from django.contrib.auth import authenticate, login,logout
from django.contrib.auth.decorators import login_required
from django.core import mail
from prefpy.mechanism import *
from prefpy.allocation_mechanism import *
from prefpy.gmm_mixpl import *
from .email import EmailThread, setupEmail
from groups.models import *
from django.conf import settings
from multipolls.models import *

import json
import threading
import itertools
import django_rq

# view for homepage - index of questions & results
class IndexView(generic.ListView):
    template_name = 'polls/index2.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all().order_by('-pub_date')

class RegularPollsView(generic.ListView):
    template_name = 'polls/regular_polls.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all()
    def get_context_data(self, **kwargs):
        ctx = super(RegularPollsView, self).get_context_data(**kwargs)
        # sort the lists by date (most recent should be at the top)
        ctx['polls_created'] = Question.objects.filter(question_owner = self.request.user, m_poll = False).order_by('-pub_date')
        ctx['polls_participated'] = self.request.user.poll_participated.filter(m_poll = False).exclude(question_owner = self.request.user).order_by('-pub_date')
        return ctx

# the original query will return data from earliest to latest
# reverse the list so that the data is from latest to earliest
def reverseListOrder(query):
    listQuery = list(query)
    listQuery.reverse()
    return listQuery

class MultiPollsView(generic.ListView):
    template_name = 'polls/m_polls.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all()
    def get_context_data(self, **kwargs):
        ctx = super(MultiPollsView, self).get_context_data(**kwargs)
        # sort the list by date
        ctx['multipolls_created'] = reverseListOrder(MultiPoll.objects.filter(owner = self.request.user))
        ctx['multipolls_participated'] = reverseListOrder(self.request.user.multipoll_participated.exclude(owner = self.request.user))
        return ctx

# guest homepage view
class MainView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'question_list'
    def get_queryset(self):
        return Question.objects.all().order_by('-pub_date')
    def get_context_data(self, **kwargs):
        ctx = super(MainView, self).get_context_data(**kwargs)
        # sort the list by date
        ctx['question']=Question.objects.first()
        ctx['voting_question'] = Question.objects.filter(question_text="Demo").first()
        ctx['preference'] = 1
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        ctx['view_preferences'] = getViewPreferences()
        
        return ctx

# demo for voting page in main page
# view for question detail
class DemoView(generic.DetailView):
    model = Question
    template_name = 'polls/demo.html'

    def get_order(self, ctx):
        otherUserResponses = self.object.response_set.reverse()
        defaultOrder = ctx['object'].item_set.all()
        #random.shuffle(defaultOrder)
        return defaultOrder
        #return getRecommendedOrder(otherUserResponses, self.request, defaultOrder)

    def get_context_data(self, **kwargs):
        ctx = super(DemoView, self).get_context_data(**kwargs)
        ctx['items'] = self.get_order(ctx)
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

        
# step 1: the intial question object will be created. 
def AddStep1View(request):
    context = RequestContext(request)
    if request.method == 'POST':
        questionString = request.POST['questionTitle']   
        questionDesc = request.POST['desc']
        questionType = request.POST['questiontype']
        imageURL = request.POST['imageURL']
        # create a new question using information from the form and inherit settings from the user's preferences
        question = Question(question_text=questionString, question_desc=questionDesc,
            pub_date=timezone.now(), question_owner=request.user,
            display_pref=request.user.userprofile.displayPref, emailInvite=request.user.userprofile.emailInvite,
            emailDelete=request.user.userprofile.emailDelete, emailStart=request.user.userprofile.emailStart,
            emailStop=request.user.userprofile.emailStop, creator_pref=1)
        if request.FILES.get('docfile') != None:
            question.image = request.FILES.get('docfile')
        elif imageURL != '':
            question.imageURL = imageURL 
        question.question_type = questionType
        question.save()
        setupEmail(question)
        return HttpResponseRedirect(reverse('polls:AddStep2', args=(question.id,)))
    return render_to_response('polls/add_step1.html', {}, context)

# step 2: the owner adds choices to a poll
class AddStep2View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step2.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep2View, self).get_context_data(**kwargs)
        ctx['items'] = self.object.item_set.all()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# step 3: the owner invites voters and groups to a poll
class AddStep3View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step3.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep3View, self).get_context_data(**kwargs)
        ctx['users'] = User.objects.all()
        ctx['groups'] = Group.objects.all()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# step 4: the owner selects the type of poll and other settings    
class AddStep4View(generic.DetailView):
    model = Question
    template_name = 'polls/add_step4.html'
    def get_context_data(self, **kwargs):
        ctx = super(AddStep4View, self).get_context_data(**kwargs)
        ctx['preference'] = self.request.user.userprofile.displayPref
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        ctx['view_preferences'] = getViewPreferences()
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# Add a single choice to a poll.
# - A choice must contain text
# - No duplicate choices (text can't be the same) 
# - The user can add an image to the choice, but images are optional
def addChoice(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    item_text = request.POST['choice']
    imageURL = request.POST['imageURL']
    
    #check for empty strings
    if item_text == "":
        return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
    
    # check for duplicates
    allChoices = question.item_set.all()
    for choice in allChoices:
        if item_text == choice.item_text:
            return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
    
    # create the choice
    item = Item(question=question, item_text=item_text, timestamp=timezone.now())
    
    # if the user uploaded an image or set a URL, add it to the item
    if request.FILES.get('docfile') != None:
        item.image = request.FILES.get('docfile')
    elif imageURL != '':
        item.imageURL = imageURL 
    
    # save the choice
    item.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

def editChoice(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    for item in question.item_set.all():
        new_text = request.POST["item"+str(item.id)]
        item_desc = request.POST["itemdescription"+str(item.id)]
        imageURL = request.POST["imageURL"+str(item.id)]
        if item_desc != "":
            item.item_description = item_desc
        if request.FILES.get("docfile"+str(item.id)) != None:
            item.image = request.FILES.get("docfile"+str(item.id))
        elif imageURL != "":
            item.imageURL = imageURL
        item.item_text = new_text
        item.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

def editBasicInfo(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    new_title = request.POST["title"]
    new_desc = request.POST["desc"]
    question.question_text = new_title
    question.question_desc = new_desc    
    question.save()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# remove a choice from the poll. 
# deleting choices should only be done before the poll starts
def deleteChoice(request, choice_id):
    item = get_object_or_404(Item, pk=choice_id)
    item.delete()
    request.session['setting'] = 0
    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# permanently erase a poll and all its information and settings
def deletePoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the current user is the owner
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))    
    
    question.delete()
    return HttpResponseRedirect(reverse('polls:index'))

# the voter can opt out of a poll at any time 
def quitPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    
    # notify the user if this option is checked
    if request.user.userprofile.emailDelete:
        email_class = EmailThread(request, question_id, 'remove')
        email_class.start()
        
    # remove from the voter list
    question.question_voters.remove(request.user)
    question.save()

    return HttpResponseRedirect(reverse('polls:regular_polls'))

# when a poll starts, users can cast votes at any time. 
# however, the owner won't be able to remove voters or choices
def startPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the owner started the poll
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))
    
    # set the poll to start
    question.status = 2
    question.save()
    
    # send notification email
    if question.emailStart:
        email_class = EmailThread(request, question_id, 'start')
        email_class.start()

    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))  

# when a poll stops, users can no longer cast votes
# the final results will be calculated and displayed
def stopPoll(request, question_id):
    question = get_object_or_404(Question, pk=question_id)

    # check to make sure the owner stopped the poll
    if request.user != question.question_owner:
        return HttpResponseRedirect(reverse('polls:index'))    
    
    # set the status to stop
    question.status = 3
    # get winner or allocation, and save it
    if question.question_type == 1: #poll
        question.winner = getPollWinner(question)
    elif question.question_type == 2: #allocation
        getFinalAllocation(question)
    question.save()

    return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

# find the winner(s) using the polling algorithm selected earlier 
# Question question
# return String winnerStr
def getPollWinner(question):
    all_responses = question.response_set.filter(active=1).order_by('-timestamp')
    if len(all_responses) == 0:
        return ""

    (latest_responses, previous_responses) = categorizeResponses(all_responses)
    candMap = getCandidateMapFromList(list(question.item_set.all()))
    vote_results, mixtures = getVoteResults(latest_responses,candMap)
    indexVoteResults = question.poll_algorithm - 1
    current_result = vote_results[indexVoteResults]

    winnerStr = ""
    
    #item_set = getCandidateMap(latest_responses[0])
    for index, score in current_result.items():
        # index 5 uses Simplified Bucklin, where score is rank. A low score means it has a high rank (e.g. rank 1 > rank 2), so the best score is the minimum.
        # All other indices rank score from highest to lowest, so the best score would be the maximum.  
        if (score == min(current_result.values()) and indexVoteResults == 5) or (score == max(current_result.values()) and indexVoteResults != 5):
            #add a comma to separate the winners            
            if winnerStr != "":
                winnerStr += ", "
            #add the winner
            winnerStr += candMap[index].item_text
            
            
    result = FinalResult(question=question,timestamp=timezone.now(),result_string="",mov_string="",cand_num=question.item_set.all().count(),node_string="",edge_string="",shade_string="")
    resultstr = ""
    movstr = ""
    nodestr = ""
    edgestr = ""
    shadestr = ""
    mov = getMarginOfVictory(latest_responses,candMap)
    for x in range(0,len(vote_results)):
        for key,value in vote_results[x].items():
            resultstr += str(value)
            resultstr += ","
    for x in range(0,len(mov)):
        movstr += str(mov[x])
        movstr += ","
    resultstr = resultstr[:-1]
    movstr = movstr[:-1]
    (nodes, edges) = parseWmg(latest_responses,candMap)
    for node in nodes:
        for k,v in node.items():
            nodestr += k + "," + str(v) + ";"
        nodestr += "|"
    nodestr = nodestr[:-2]
    for edge in edges:
        for k,v in edge.items():
            edgestr += k + "," + str(v) + ";"
        edgestr += "|"
    edgestr = edgestr[:-2]
    shadevalues = getShadeValues(vote_results)
    for x in shadevalues:
        for y in x:
            shadestr += y + ";"
        shadestr += "|"
    shadestr = shadestr[:-2]
    result.result_string = resultstr
    result.mov_string = movstr
    result.node_string = nodestr
    result.edge_string = edgestr
    result.shade_string = shadestr
    result.save()
    return winnerStr
    
def interpretResult(finalresult):
    candnum = finalresult.cand_num
    resultstr = finalresult.result_string
    movstr = finalresult.mov_string
    shadestr = finalresult.shade_string
    nodestr = finalresult.node_string
    edgestr = finalresult.edge_string
    resultlist = resultstr.split(",")
    movlist = movstr.split(",")
    tempResults = []
    algonum = len(getListPollAlgorithms())
    if len(resultlist) > 0:
        for x in range(0,algonum):
            tempList = []
            for y in range(x*candnum, (x+1)*candnum):
                tempList.append(resultlist[y])
            tempResults.append(tempList)
    tempMargin = []
    for margin in movstr:
        tempMargin.append(margin)
    tempShades = []
    shadelist = shadestr.split(";|")
    for item in shadelist:
        tempShades.append(item.split(";"))
    tempNodes = []
    nodelist = nodestr.split(";|")
    for node in nodelist:
        data = {}
        l = node.split(";")
        for item in l:
            tup = item.split(",")
            data[tup[0]] = tup[1]
        tempNodes.append(data)
    tempEdges = []
    edgelist = edgestr.split(";|")
    for edge in edgelist:
        data = {}
        l = edge.split(";")
        for item in l:
            tup = item.split(",")
            data[tup[0]] = tup[1]
        tempEdges.append(data)
    return [tempResults, tempMargin, tempShades, tempNodes, tempEdges]

# check whether the user clicked 'reset' when ordering preferences
def isPrefReset(request):
    # reset link would have '?order=null' at the end
    orderStr = request.GET.get('order', '')
    if orderStr == "null":
        return True
    return False 

# given a list of responses, return the response's selection data
# List<Response> mostRecentResponse
# return List<List<(Item, int)>> array
def getCurrentSelection(mostRecentResponse):
    responseDict = {}
    if mostRecentResponse.dictionary_set.all().count() > 0:
        responseDict = mostRecentResponse.dictionary_set.all()[0]
    else:
        responseDict = buildResponseDict(mostRecentResponse,mostRecentResponse.question,getPrefOrder(mostRecentResponse.resp_str, mostRecentResponse.question))
    rd = responseDict
    array = []
    for itr in range(mostRecentResponse.question.item_set.all().count()):
        array.append([])
    for itr in rd:
        array[rd[itr] - 1].append(itr)
    return array

# view for question detail
class DetailView(generic.DetailView):
    model = Question
    template_name = 'polls/detail.html'

    def get_order(self, ctx):
        otherUserResponses = self.object.response_set.reverse()
        defaultOrder = list(ctx['object'].item_set.all())
        random.shuffle(defaultOrder)
        return defaultOrder
        #commented out to improve performance
        #return getRecommendedOrder(otherUserResponses, self.request, defaultOrder)

    def get_context_data(self, **kwargs):
        ctx = super(DetailView, self).get_context_data(**kwargs)
        ctx['lastcomment'] = ""
        
        #Case for anonymous user
        if self.request.user.get_username() == "":
            if isPrefReset(self.request):
                ctx['items'] = self.object.item_set.all()
                return ctx
            # check the anonymous voter
            if 'anonymousvoter' in self.request.session and 'anonymousid' in self.request.session:
                # sort the responses from latest to earliest
                currentAnonymousResponses = self.object.response_set.filter(anonymous_id = self.request.session['anonymousid']).reverse()
                if len(currentAnonymousResponses) > 0:
                    # get the voter's most recent selection
                    mostRecentAnonymousResponse = currentAnonymousResponses[0]
                    if mostRecentAnonymousResponse.comment:
                        ctx['lastcomment'] = mostRecentAnonymousResponse.comment
                    ctx['currentSelection'] = getCurrentSelection(currentAnonymousResponses[0])
            else:
                # load choices in the default order
                ctx['items'] = self.object.item_set.all()
            return ctx

        # Get the responses for the current logged-in user from latest to earliest
        currentUserResponses = self.object.response_set.filter(user=self.request.user).reverse()
        
        if len(currentUserResponses) > 0:
            if currentUserResponses[0].comment:
                ctx['lastcomment'] = currentUserResponses[0].comment

        # reset button
        if isPrefReset(self.request):
            ctx['items'] = self.get_order(ctx)
            return ctx
        
        # check if the user submitted a vote earlier and display that for modification
        if len(currentUserResponses) > 0: 
            ctx['currentSelection'] = getCurrentSelection(currentUserResponses[0])
            items = []
            for item in ctx['currentSelection']:
                for i in item:
                    items.append(i)
            ctx['items'] = items
            ctx['itr'] = itertools.count(1, 1)
        else:
            # no history so display the list of choices
            ctx['items'] = self.get_order(ctx)
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# view for settings detail
class PollInfoView(generic.DetailView):
    model = Question
    template_name = 'polls/pollinfo.html'
    def get_context_data(self, **kwargs):
        ctx = super(PollInfoView, self).get_context_data(**kwargs)
        emailInvite = Email.objects.filter(question=self.object, type=1)
        if len(emailInvite) == 1:
            setupEmail(self.object)
        if Email.objects.filter(question=self.object).count() > 0:
            ctx['emailInvite'] = Email.objects.filter(question=self.object, type=1)[0]
            ctx['emailDelete'] = Email.objects.filter(question=self.object, type=2)[0]
            ctx['emailStart'] = Email.objects.filter(question=self.object, type=3)[0]
            ctx['emailStop'] = Email.objects.filter(question=self.object, type=4)[0]
        ctx['users'] = User.objects.all()
        ctx['items'] = self.object.item_set.all()
        ctx['groups'] = Group.objects.all()
        ctx['poll_algorithms'] = getListPollAlgorithms()
        ctx['alloc_methods'] = getAllocMethods()
        
        # display this user's history
        currentUserResponses = self.object.response_set.filter(user=self.request.user,active=1).order_by('-timestamp')
        ctx['user_latest_responses'] = getSelectionList([currentUserResponses[0]]) if (len(currentUserResponses) > 0) else None
        ctx['user_previous_responses'] = getSelectionList(currentUserResponses[1:])
        
        # get history of all users
        all_responses = self.object.response_set.filter(active=1).order_by('-timestamp')
        (latest_responses, previous_responses) = categorizeResponses(all_responses)
        ctx['latest_responses'] = getSelectionList(latest_responses)
        ctx['previous_responses'] = getSelectionList(previous_responses)    
        
        # get deleted votes
        deleted_responses = self.object.response_set.reverse().filter(active=0).order_by('-timestamp')
        (latest_deleted_responses, previous_deleted_responses) = categorizeResponses(deleted_responses)
        ctx['latest_deleted_responses'] = getSelectionList(latest_deleted_responses)
        ctx[''] = getSelectionList(previous_deleted_responses)
        
        if self.object.question_voters.all().count() > 0:
            progressPercentage = len(latest_responses) / self.object.question_voters.all().count() * 100
            ctx['progressPercentage'] = progressPercentage
        return ctx
    def get_queryset(self):
        """
        Excludes any questions that aren't published yet.
        """
        return Question.objects.filter(pub_date__lte=timezone.now())

# view for results detail
class AllocateResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/allocate_results.html'

# view for submission confirmation
class ConfirmationView(generic.DetailView):
    model = Question
    template_name = 'polls/confirmation.html'

# view that displays vote results using various algorithms
class VoteResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/vote_rule.html'
    def get_context_data(self, **kwargs):
        ctx = super(VoteResultsView, self).get_context_data(**kwargs)
        
        candMap = getCandidateMapFromList(list(self.object.item_set.all()))
        ctx['cand_map'] = candMap# if (len(latest_responses) > 0) else None
        ctx['poll_algorithms'] = getListPollAlgorithms()
        if hasattr(self.object, 'finalresult'):
            final_result = self.object.finalresult
            l = interpretResult(final_result)
            ctx['vote_results'] = l[0]
            ctx['margin_victory'] = l[1]
            ctx['shade_values'] = l[2]
            ctx['wmg_nodes'] = l[3]
            ctx['wmg_edges'] = l[4]
        else:
            all_responses = self.object.response_set.filter(active=1).order_by('-timestamp')
            (latest_responses, previous_responses) = categorizeResponses(all_responses)
            voteResults, mixtures = getVoteResults(latest_responses,candMap) 
            resultlist = []
            for r in voteResults:
                resultlist.append(r.values())
            ctx['vote_results'] = resultlist
            ctx['shade_values'] = getShadeValues(voteResults)
            (nodes, edges) = parseWmg(latest_responses,candMap)
            ctx['wmg_nodes'] = nodes
            ctx['wmg_edges'] = edges
            
            ctx['margin_victory'] = getMarginOfVictory(latest_responses,candMap)
            #ctx['mixtures_pl'] = mixtures[0]
            
        previous_results = self.object.voteresult_set.all()
        ctx['previous_winners'] = []
        for pw in previous_results:
            obj = {}
            obj['title'] = str(pw.timestamp.time())
            candnum = pw.cand_num
            resultstr = pw.result_string
            movstr = pw.mov_string
            if resultstr == "" and movstr == "":
                continue
            resultlist = resultstr.split(",")
            movlist = movstr.split(",")
            tempResults = []
            algonum = len(getListPollAlgorithms())
            if len(resultlist) > 0:
                for x in range(0,algonum):
                    tempList = []
                    for y in range(x*candnum, (x+1)*candnum):
                        tempList.append(resultlist[y])
{'fraction_non_alphanumeric': 0.10509678426475179, 'fraction_numerical': 0.004761161411177021, 'mean_word_length': 2.9789596273291927, 'pattern_counts': {'":': 14, '<': 9, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '632932', 'n_tokens_mistral': 15009, 'n_tokens_neox': 14722, 'n_words': 3360}