# Source code for quiz.views

    from django.shortcuts import render
    from django.http import HttpResponse
    from django.core.paginator import Paginator
    from django.http import HttpResponseRedirect
    from django.db.models import Max
    from django.shortcuts import redirect
    from .forms import UploadFileForm
    from . newQuiz import readCSV
    from . models import Questions
    from . models import quiz
    from .models import submission
    from .models import cribs
    from .models import result as results
    from .models import cribs as crib
    from .models import Permission
    from .models import log
    import collections
    from django.db import connection, transaction
    import numpy as np
    import math
    import pandas as pd
    import scipy.stats as stats
    import csv
    from prettytable import PrettyTable
    #for login
    from django.contrib.auth.models import User
    from django.contrib.auth.forms import UserCreationForm
    from django.contrib.auth import login
    from django.contrib.auth.decorators import login_required
    from django.db.models import Count
    import matplotlib.pyplot as plt, mpld3
    import json
    import random
    import string
    from datetime import datetime
    from django.views.decorators.clickjacking import xframe_options_exempt
    from django.core.files import File
    from django.utils import timezone
    from django.core.files.storage import default_storage

    startedquiz = dict()

    def index(request):
        """ This function is responsible for for rendering the quiz page to the student for the selected quiz by the student
        """
        quiz_id = int(request.GET['q'])
        quizInstance = quiz.objects.get(pk=quiz_id)
        obj = Questions.objects.filter(quizId=quizInstance).all().order_by('questionId')
        endtime = quizInstance.end_datetime
        endtime = json.dumps(endtime.isoformat())
        count = len(obj)
        return render(request,'index.html',{'questions':obj,'count':count, 'endtime': endtime, 'quizId': quiz_id})

    @login_required
    def result(request):
        """This function is called on submission of quiz to  calculate the marks og the student the marks are added to total score for
        every correct answer and for every wronf answer the negative marks set by instructor are deducted"""
        if request.user.is_authenticated and request.method =="POST":
            quizId=int(request.POST['quizId'])
            quizInstance = quiz.objects.get(pk=quizId)
            prev_subm = submission.objects.all().filter(quizId=quizInstance, studentId=request.user)
            score = 0
            if len(prev_subm)==0:
                for questionno in request.POST:
                    if questionno.startswith('question_'):
                        questionId = int(questionno[9:])
                        questionInstance = Questions.objects.get(pk=questionId)
                        q=Questions.objects.all().filter(quizId=quizInstance,questionId=questionId).values()
                        if(request.POST[questionno]==q[0]['answer']):
                            score+=q[0]['marks']
                        else:
                            score-=q[0]['negative']
                        t=submission(questionId=questionInstance, option=request.POST[questionno], studentId=request.user, quizId=quizInstance)
                        t.save()
                t=results(quizId=quizInstance,studentId=request.user,marks=int(score))
                t.save()
                return redirect('/view_submission/?q='+str(quizId))
            else:
                return HttpResponse("You have already submitted this quiz")

    def save_ans(request):
        """
        this function keeps saving the response of the quiz while the student is attempting in order to ensure if due to network failure
        student quiz stops then he can continue later from the point where he was interrupted
        """
        ans = request.GET['ans']
        quizId=request.GET['quizId']
        questionId=request.GET['questionId']
        studentId=1# initialize here student id
        t=submission(questionId=questionId,option=ans,quizId=quizId,studentId=studentId)
        t.save()
        return HttpResponse('')

    def save_cribs(request):
        """This function saves the cribs that the student has raised"""
        crib=request.GET.get('cribs')
        quizId=int(request.GET.get('quiz'))
        quizInstance = quiz.objects.get(pk=quizId)
        questionId=int(request.GET.get('question'))
        questionInstance = Questions.objects.get(pk=questionId)
        t=cribs(cribs=crib,studentId=request.user,questionId=questionInstance,quizId=quizInstance)
        t.save()
        return HttpResponse('Suuuuuccess')

    def upload(request):
        """This function Renders the upload page for instructor to upload quiz through csv"""
        return render(request,'upload.html')

    @login_required
    def student(request):
        """This function depending on the role of the logged in user load the professor dasboard or student dashboard"""
        role = Permission.objects.all().filter(userId=request.user).values('role')
        if role:
            role = role[0]['role']
            if role == "P":
                return render(request,'professor.html')
            else:
                return HttpResponse('Role not configured for this user')
        else:
            return render(request,'student.html')

    def ongoing_quiz(request):
        """Displays all ongoing quiz to the professor who has hosted the quiz"""
        quizzes = quiz.objects.all().order_by('-date', '-startTime')
        return render(request, 'ongoing_quiz.html', {'quizId': quizzes})

    def upload_file(request):
        """ This function reads the csv file and inserts the questions into the database """
        uploaded=False
        temp1='test'
        random_code = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 6))
        q= quiz(length=request.POST.get('length'),quizCode=random_code,quizInfo=request.POST.get('quiz_name'),date=request.POST.get('date'),
        quizInstructor=request.user,startTime =request.POST.get('startTime'),quizDone=False)
        q.save()
        form = UploadFileForm(request.POST, request.FILES)
        if request.method == 'POST' and form.is_valid():
            handle_uploaded_file(request.FILES['file'],q)
            uploaded=True
            return HttpResponse('success')

        else :
            return render(request,'upload.html',{temp1:'invalid File'})

    def instructor(request):
        """This function is used to display the instructor with graphs(bell curve and histogram) , cribs raised by the students of the quiz selected"""
        q_id = request.GET.get('quiz_id')
        quizId = 0
        allquizs = quiz.objects.all().filter(quizInstructor=request.user).order_by('-date', '-startTime')
        if q_id:
            quizId = int(q_id)
        else:
            #quizId = quiz.objects.all().filter(quizInstructor=request.user)[0]
            if True:
                quizId = allquizs[0].quizId
            else:
                print(quizId)

        quizInstance = quiz.objects.all().filter(quizId=quizId, quizInstructor=request.user)[0]
        students = results.objects.all().filter(quizId=quizId).values('studentId')
        marks = results.objects.all().filter(quizId=quizId).values('marks')
        cribs=crib.objects.all().filter(quizId=quizId).select_related()

        fig, ax = plt.subplots()
        allMarks=list()
        for mark in marks:
            allMarks.append(mark['marks'])
        allStudents=list()
        for student in students:
            allStudents.append(student['studentId'])
        std=np.std(allMarks)
        mean=np.mean(allMarks)
        data =allMarks
        c = collections.Counter(data)
        c = sorted(c.items())
        score_num = [i[0] for i in c]
        freq = [i[1] for i in c]
        plt.barh(score_num, freq)
        plt.title("Score V/S N.O of Students")
        plt.xlabel("N.O of Students")
        plt.ylabel("Scores")
        ax.set_xticks(range(1,len(allMarks)+1))
        #ax.set_xticklabels(months)
        html_graph = mpld3.fig_to_html(fig)
        fig1, ax1 = plt.subplots()
        mu = mean
        variance = np.std(allMarks)
        sigma = math.sqrt(variance)
        x = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
        ax1.plot(x, stats.norm.pdf(x, mu, sigma))
        ax1.set_title('Normal Distribution for Scores to Students')
        ax1.set_xlabel('Score')
        ax1.set_ylabel('PDF')
        html_graph1 = mpld3.fig_to_html(fig1)
        quizDone = False
        if quizInstance.end_datetime < datetime.now():
            quizDone = True
        return render(request, 'instructor.html',{"graph": html_graph, "graph1": html_graph, "graph2": html_graph1,'quiz':quizInstance,'cribs':cribs, 'all_quizes': allquizs, 'quizDone':quizDone})

    def quizTable(request):
        """This function helps in rendering all the quiz hosted by the instructor"""
        quizs = quiz.objects.filter(quizInstructor=request.user).all()
        return render(request,'quizTable.html',{'quiz':quizs})

    def handle_uploaded_file(f,q1):
        """This function reads the csv file uploaded by the instructor and makes insert into the database"""
        with open('name.csv', 'wb+') as destination:
            for chunk in f.chunks():
                destination.write(chunk)
        destination=open("name.csv","r")
        rows=readCSV(destination)
        for row in rows:

            q=Questions(question=row[0],option1=row[1],option2=row[2],option3=row[3],option4=row[4],answer=row[5],type=row[6],marks=int(row[7]),negative=float(row[8]),explainations=row[9],quizCode=q1.quizCode,quizId=q1)#hardcoded quizid
            q.save()

    def create_quiz(request):
        """This function renders the create quiz page for manually entering questions"""
        return render(request, 'quiz_create.html')

    #login functionality
    def sign_up(request):
        """This function renders the sign up page for the users"""
        context = {}
        form = UserCreationForm(request.POST or None)
        if request.method == "POST":
            if form.is_valid():
                user = form.save()
                login(request,user)
                return render(request,'student.html')
        context['form']=form
        return render(request,'registration/signup.html',context)

    @login_required
    def submissions(request):
        """ This function helps in rendering the submission page showing the student all the previous attempted quizzes"""
        #prev_subm = submission.objects.all().filter(studentId=request.user)
        prev_subm = results.objects.all().filter(studentId=request.user).select_related().all()
        return render(request,'submissions.html', { 'submissions' : prev_subm })

    @login_required
    def view_sub(request):
        """This function gives details to the student about the completed quiz consisting of  correct answers
        and choosen answers also the explainations for the questions provided by the professor"""
        if request.method == "GET":
            quizId = int(request.GET.get('q'))
            quizInstance = quiz.objects.get(pk=quizId)
            subs = submission.objects.filter(quizId=quizInstance, studentId=request.user).select_related().all()
            score = 0
            total = 0
            message = ''
            for sub in subs:
                if sub.option == sub.questionId.answer:
                    score = score + sub.questionId.marks
                else:
                    score = score - sub.questionId.negative
                total = total + sub.questionId.marks
            return render(request,'view_submissions.html', { 'submissions' : subs , 'score': round(score,2), 'total': total, 'quizId': quizId })

    def add_quiz(request):
        """This function makes insert into database for all the manually entered quiz questions"""
        vals=list()
        for req in request.POST.values():
            vals.append(req)
        i=1
        quizName= vals[i]
        i+=1
        date=vals[i]
        i+=1
        startTime=vals[i]
        i+=1
        length=vals[i]
        i+=1
        random_code = ''.join(random.choices(string.ascii_uppercase + string.digits, k = 6))
        q= quiz(length=length,quizCode=random_code,quizInfo=quizName,date=date,
        quizInstructor=request.user,startTime =startTime,quizDone=False)
        q.save()

        while(i<len(vals)):

            row=(vals[i],vals[i+1],vals[i+2],vals[i+3],vals[i+4],vals[i+5],vals[i+6],vals[i+7],vals[i+8])
            q1=Questions(question=row[0],option1=row[1],option2=row[2],option3=row[3],option4=row[4],
            answer=row[7],marks=int(row[5]),negative=float(row[6]),explainations=row[8],quizCode=q.quizCode,quizId=q)
            print(row)
            q1.save()
            i=i+9
        return render(request,'professor.html',{'quiz_upload':True})#(request,'success')

    def monitor(request):
        """
        Thid function renders the monitor page for the instructor to view ongoing quiz , and monitor the student activity
        """
        q_id = request.GET.get('quiz')
        allquizs = quiz.objects.all().filter(quizInstructor=request.user).order_by('-date', '-startTime')

        if q_id:
            quizId = int(q_id)
            quizInstance = quiz.objects.get(pk=quizId)
            startedquiz[quizId] = dict()
            return render(request, 'monitor.html', { 'quiz': quizInstance , 'all': allquizs })
        else:
            quizId = allquizs[0].quizId
            startedquiz[quizId] = dict()
            return render(request, 'monitor.html', { 'quiz': allquizs[0] , 'all': allquizs })

    @xframe_options_exempt
    def getbeat(request):
        """This function track the student activity for displaying the same on the instructor monitor page"""
        quizId = int(request.GET.get('quiz'))
        test = startedquiz.get(quizId)
        return render(request,'student_activity.html', {'activity': test })

    def view_logs(request):
        """THus function helps in viewing all the quizzes logs"""
        quizId = int(request.GET.get('quiz'))
        quizInstance = quiz.objects.get(pk=quizId)
        quiz_logs = log.objects.all().filter(quizId=quizInstance)
        return render(request,'log.html', {'logs': quiz_logs })

    def heartbeat(request):
        """This function keeps track of student whether he exited full screen and which question he is currently on"""
        quizId = int(request.GET.get('quiz'))
        quizInstance = quiz.objects.get(pk=quizId)
        if quizId in startedquiz:
            question = int(request.GET.get('question'))
            fs = request.GET.get('fullscreen')
            db = request.GET.get('log')
            time = timezone.now()
            jtime = json.dumps(time.isoformat())
            startedquiz[quizId][request.user] = (question, fs, jtime)
            if db == "true":
                if fs == "true":
                    fstext="Entered Fullscreen"
                else:
                    fstext="Left Fullscreen"
                l=log(quizId=quizInstance, studentId=request.user, fullscreen=fstext, questions=str(question))
                l.save()
                print("Log saved!")

        return HttpResponse('')