import django.forms
from django.shortcuts import render, redirect, get_object_or_404
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.http import FileResponse, HttpResponse, Http404, HttpResponseRedirect
from django.contrib import messages
from django.utils.safestring import mark_safe

from django.contrib.auth.decorators import login_required, user_passes_test
from django.views.static import serve

from .models import Deg_Plan_Doc, Student, Degree, Qual, Pre_Exam_Doc, Pre_Exam_Info,\
    T_D_Prop_Doc, Fin_Exam_Info, Fin_Exam_Doc, T_D_Doc, T_D_Info, Session_Note,\
    Other_Doc, Qual_Exam_Doc, Annual_Review_Doc, DocumentFile, Advising_Note
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

from .forms import create_doc_form, stu_search_form, stu_bio_form, deg_form, qual_form,\
    pre_exam_info_form, final_exam_info_form, thesis_dissertation_info_form,\
    session_note_form, degree_note_form, DocumentForm, advising_note_form

from .crypt import Cryptographer
from .functions import deg_doc, get_info_form, get_stu_objs, get_deg_objs, post_degrees, post_quals, post_session_note,\
    delete, get_stu_search_dict, permission_check

from openpyxl import Workbook
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from django.views.static import serve
import pandas as pd
import csv
import os
import pdb


def conditional_decorator(dec, condition):
    def decorator(func):
        if not condition:
            return func
        return dec(func)
    return decorator


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def home(request):
    return render(request, 'home.html')


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def upload(request):
    if request.method == 'POST' and request.FILES['myfile']:
        myfile = request.FILES['myfile']
        fs = FileSystemStorage()
        filename = fs.save(myfile.name, myfile)
        uploaded_file_url = fs.url(filename)
        return render(request, 'upload.html', {
            'uploaded_file_url': uploaded_file_url
        })
    return render(request, 'upload.html')


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def form_upload(request):
    if request.method == 'POST':
        form = create_doc_form(Deg_Plan_Doc)(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('home')
    else:
        form = create_doc_form(Deg_Plan_Doc)
    print 'dddd'
    return render(request, 'form_upload.html', {
        'form': form
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def doc_upload(request, id):
    student = Student.objects.get(id=id)
    if request.method == 'POST':
        form = create_doc_form(Deg_Plan_Doc)(request.POST, request.FILES)
        if form.is_valid():
            doc = form.save(commit=False)
            doc.stu = student
            doc.save()
            return redirect('doc_upload', id=id)
    else:
        student = Student.objects.get(id=id)
        form = create_doc_form(Deg_Plan_Doc)
    return render(request, 'form_upload.html', {
        'form': form,
        'student': student,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def doc_remove(request, id):
    doc = Deg_Plan_Doc.objects.get(id=id)
    stu_id = doc.stu.id
    if request.method == "POST":

        doc.delete()

    return redirect('doc_upload', id=stu_id)


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def tamu_upload(request, id):
    student = Student.objects.get(id=id)
    g_login = GoogleAuth()
    g_login.LoadCredentialsFile("mycreds.txt")
    if g_login.credentials is None:
        g_login.CommandLineAuth()
    elif g_login.access_token_expired:
        g_login.Refresh()
    else:
        g_login.Authorize()
    g_login.SaveCredentialsFile("mycreds.txt")
    drive = GoogleDrive(g_login)
    if request.method == 'POST':
        form = create_doc_form(Deg_Plan_Doc)(request.POST, request.FILES)
        if form.is_valid():
            doc = form.save(commit=False)
            doc.stu = student
            doc.save()
            # print("./media/"+ str(doc.doc))
            with open("./media/" + str(doc.doc), "rb") as file:
                file_drive = drive.CreateFile({'title': os.path.basename(file.name)})
                file_drive.SetContentFile(file.name)
                file_drive.Upload()

            doc.file_id = file_drive['id'].encode('utf8')
            os.remove(doc.doc.path)
            doc.save()
            print(doc.doc.path)
            return redirect('show_stu', id=id)

    else:
        student = Student.objects.get(id=id)
        form = create_doc_form(Deg_Plan_Doc)
    return render(request, 'form_upload.html', {
        'form': form,
        'student': student,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def tamu_download(request, id):
    g_login = GoogleAuth()
    g_login.LoadCredentialsFile("mycreds.txt")
    if g_login.credentials is None:
        g_login.CommandLineAuth()
    elif g_login.access_token_expired:
        g_login.Refresh()
    else:
        g_login.Authorize()
    g_login.SaveCredentialsFile("mycreds.txt")
    drive = GoogleDrive(g_login)
    doc = Deg_Plan_Doc.objects.get(id=id)
    stu_id = doc.stu.id
    file1 = drive.CreateFile({'id': str(doc.file_id)})
    file1.GetContentFile(str(doc.doc).split("/")[1])
    filepath = str(doc.doc).split("/")[1]
    return serve(request, os.path.basename(filepath), os.path.dirname(filepath))


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def degree_plan(request, deg_id, option='', id=0):
    if request.method == 'POST':
        if not permission_check(request, Deg_Plan_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Degree Plan", Deg_Plan_Doc, "/degree_plan/", deg_id, option, id)[1]
    else:
        method, data = deg_doc(request, "Degree Plan", Deg_Plan_Doc,
                               "/degree_plan/", deg_id, option, id)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'degree_plan.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def preliminary_exam(request, deg_id, option='', id=0):
    info_form = get_info_form(request, deg_id, Pre_Exam_Info, pre_exam_info_form)
    if request.method == 'POST':
        if not permission_check(request, Pre_Exam_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Preliminary Exam", Pre_Exam_Doc, "/preliminary_exam/",
                       deg_id, option, id, Pre_Exam_Info, info_form)[1]
    else:
        method, data = deg_doc(request, "Preliminary Exam", Pre_Exam_Doc, "/preliminary_exam/",
                               deg_id, option, id, Pre_Exam_Info)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'preliminary_exam.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
                'info_form': info_form,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def qualifying_exam(request, deg_id, option='', id=0):
    if deg_id != '0' and Degree.objects.get(id=deg_id).deg_type != 'phd':
        messages.error(request, "Only PhD degree has qualifying exam!")
        return redirect('home')
    extra_fields = [
        ('year', django.forms.NumberInput(
            attrs={'class': 'w3-input w3-cell', 'style': 'width:45%'})),
        ('sem', django.forms.Select(attrs={'class': 'w3-select w3-cell', 'style': 'width:52%'})),
        ('result', django.forms.Select(attrs={'class': 'w3-select', 'style': 'width:auto;'}))
    ]
    if request.method == 'POST':
        if not permission_check(request, Qual_Exam_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Qualifying Exam", Qual_Exam_Doc, "/qualifying_exam/",
                       deg_id, option, id, extra_fields=extra_fields)[1]
    else:
        method, data = deg_doc(request, "Qualifying Exam", Qual_Exam_Doc, "/qualifying_exam/",
                               deg_id, option, id, extra_fields=extra_fields)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'qualifying_exam.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def annual_review(request, deg_id, option='', id=0):
    if deg_id != '0' and Degree.objects.get(id=deg_id).deg_type != 'phd':
        messages.error(request, "Only PhD degree has annual review!")
        return redirect('home')
    extra_fields = [
        ('year', django.forms.NumberInput(
            attrs={'class': 'w3-input w3-cell', 'style': 'width:auto;'})),
        ('status', django.forms.Select(attrs={'class': 'w3-select', 'style': 'width:auto;'}))
    ]
    if request.method == 'POST':
        if not permission_check(request, Annual_Review_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Annual Review", Annual_Review_Doc, "/annual_review/",
                       deg_id, option, id, extra_fields=extra_fields)[1]
    else:
        method, data = deg_doc(request, "Annual Review", Annual_Review_Doc, "/annual_review/",
                               deg_id, option, id, extra_fields=extra_fields)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'annual_review.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def thesis_dissertation_proposal(request, deg_id, option='', id=0):
    if request.method == 'POST':
        if not permission_check(request, T_D_Prop_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Thesis/Dissertation Proposal", T_D_Prop_Doc, "/thesis_dissertation_proposal/",
                       deg_id, option, id)[1]
    else:
        method, data = deg_doc(request, "Thesis/Dissertation Proposal", T_D_Prop_Doc, "/thesis_dissertation_proposal/",
                               deg_id, option, id)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'thesis_dissertation_proposal.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def final_exam(request, deg_id, option='', id=0):
    info_form = get_info_form(request, deg_id, Fin_Exam_Info, final_exam_info_form)
    if request.method == 'POST':
        if not permission_check(request, Fin_Exam_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Final Exam", Fin_Exam_Doc, "/final_exam/",
                       deg_id, option, id, Fin_Exam_Info, info_form)[1]
    else:
        method, data = deg_doc(request, "Final Exam", Fin_Exam_Doc, "/final_exam/",
                               deg_id, option, id, Fin_Exam_Info)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'final_exam.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
                'info_form': info_form,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def thesis_dissertation(request, deg_id, option='', id=0):
    info_form = get_info_form(request, deg_id, T_D_Info, thesis_dissertation_info_form)
    if request.method == 'POST':
        if not permission_check(request, T_D_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Thesis/Dissertation", T_D_Doc, "/thesis_dissertation/",
                       deg_id, option, id, T_D_Info, info_form)[1]
    else:
        method, data = deg_doc(request, "Thesis/Dissertation", T_D_Doc, "/thesis_dissertation/",
                               deg_id, option, id, T_D_Info)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'thesis_dissertation.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
                'info_form': info_form,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def other_doc(request, deg_id, option='', id=0):
    if request.method == 'POST':
        if not permission_check(request, Other_Doc, option):
            return HttpResponse("Permission Denied")
        return deg_doc(request, "Other Document", Other_Doc, "/other_doc/", deg_id, option, id)[1]
    else:
        method, data = deg_doc(request, "Other Document", Other_Doc,
                               "/other_doc/", deg_id, option, id)
        if method != 'show':
            return data
        else:
            deg, forms = data
            return render(request, 'other_doc.html', {
                'deg': deg,
                'forms': forms,
                'option': option,
            })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def session_note(request, stu_id, option='', id=0):
    if option == 'del':
        if not permission_check(request, Session_Note, option):
            return HttpResponse("Permission Denied")
        return delete(request, Session_Note, id, "Session Note", "advised at",
                      "date", "/student/" + stu_id + "/session_note/")
    if request.method == 'POST':
        if not permission_check(request, Session_Note, option):
            return HttpResponse("Permission Denied")
        return post_session_note(request, stu_id, option, id)
    else:
        notes, student, new_form = get_stu_objs(
            Session_Note, session_note_form, stu_id, option, False)
        return render(request, 'session_note.html', {
            'stu': student,
            'notes': notes,
            'new_form': new_form,
            'option': option,
        })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def serve_protected_document(request, file_path):
    try:
        if file_path[0:6] != 'media/' or '../' in file_path:
            raise PermissionError
        file_path = os.path.join(settings.BASE_DIR, file_path)
        with open(file_path, 'rb') as fh:
            content = Cryptographer.decrypted(fh.read())
            response = HttpResponse(content, content_type="application/pdf")
            response['Content-Disposition'] = 'inline; filename=' + os.path.basename(file_path)
            return response
    except:
        raise Http404


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def students(request, **kwargs):  # uin, first_name, last_name, gender, status, cur_degree):
    if request.method == 'POST':
        form = stu_search_form(request.POST)
        form.is_valid()
        redirect_url = '/students/'
        search_form_params = {}
        for name, val in form.cleaned_data.items():
            if val and val != '':
                search_form_params[name] = val
                redirect_url += "{0}={1}/".format(name, val)
        return redirect(redirect_url, **search_form_params)
    else:
        students = Student.objects.all()
        seach_dict, search_form_params = get_stu_search_dict(kwargs, True)
        if kwargs:
            students = students.filter(**seach_dict)
        students = students.order_by('uin')
        if not students:
            if search_form_params:
                return render(request, 'NotFind.html')
        form = stu_search_form(search_form_params)
        paginator = Paginator(students, 20)  # Show 20 students per page. Use 1 for test.
        page = request.GET.get('page')
        # students_page = paginator.get_page(page)
        try:
            students_page = paginator.page(page)
        except PageNotAnInteger:
            students_page = paginator.page(1)
        except EmptyPage:
            students_page = paginator.page(paginator.num_pages)

        page = 1 if not page else int(page)
        neigh_pages = [n for n in range(max(page - 2, 1), min(page + 3, paginator.num_pages + 1))]
        if len(neigh_pages) == 0 or neigh_pages[0] > 1:
            neigh_pages.insert(0, -1)
            neigh_pages.insert(0, 1)
        if neigh_pages[-1] < paginator.num_pages:
            neigh_pages.append(-1)
            neigh_pages.append(paginator.num_pages)
    return render(request, 'students.html', {
        'form': form,
        'students': students_page,
        'neigh_pages': neigh_pages,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def create_stu(request, back_url=None):
    if request.method == 'POST':
        if not permission_check(request, Student, 'add'):
            return HttpResponse("Permission Denied")
        form = stu_bio_form(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Student is added.')
        else:
            messages.error(request, mark_safe("{0}".format(form.errors)))
        return redirect('create_stu')
    else:
        form = stu_bio_form()
        title = 'Add a Student'
        return render(request, 'stu_bio_info.html', {
            'form': form,
            'title': title,
        })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def parse_stu(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            # newdoc = DocumentFile(docfile = request.FILES['docfile'])
            # newdoc.save()
            csv_file = request.FILES['docfile']
            if not csv_file.name.endswith('.csv'):
                messages.error(request, 'THIS IS NOT A CSV FILE')
                return redirect("parse_stu")
            decoded_file = csv_file.read().decode('utf-8').splitlines()
            data = csv.DictReader(decoded_file)
            # check if any columns in the csv file is what we want
            headers = data.fieldnames
            parsed_lis = [' UIN', ' Email', ' Name', '  Start Semester',
                          ' Current Degree', ' Gender', '  Advisor']
            intersection = [i for i in headers if i in parsed_lis]
            if not intersection:
                messages.error(request, 'NO COLUMN MATCH IN THIS CSV FILE')
                return redirect("parse_stu")
            for row in data:
                # prnit(row)
                student = Student()
                student.uin = row[' UIN']
                student.email = row[' Email']
                name_detail = row[' Name'].split()
                student.first_name = name_detail[0]
                student.last_name = name_detail[-1]
                student.middle_name = name_datail[1] if len(name_detail) > 2 else ''
                start_detail = row['  Start Semester'].split()
                print(start_detail)
                student.start_sem = start_detail[0]
                student.start_year = start_detail[1]
                # cur_degree is onetoone field, need to create Degree instance
                # student.cur_degree = row[' Current Degree'] ??
                student.gender = row[' Gender']
                student.advisor = row['  Advisor']
                student.save()
                messages.success(request, 'File is parsed!.')
        else:
            return render(request, 'form_error.html', {'form': form})
        return redirect("parse_stu")
    else:
        title = 'Parse a Student CSV File'
        context = {
            'title': title
        }
        return render(request, 'parse_stu.html', context)


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def edit_stu(request, id, back_url=None):
    if request.method == 'POST':
        if not permission_check(request, Student, 'ch'):
            return HttpResponse("Permission Denied")
        form = stu_bio_form(request.POST, instance=Student.objects.get(id=id))
        if form.has_changed():
            if form.is_valid():
                form.save()
                messages.success(request, 'Student is updated.')
            else:
                messages.error(request, mark_safe("{0}".format(form.errors)))
        else:
            messages.info(request, 'Noting is changed.')
        return redirect('edit_stu', id=id)
    else:
        form = stu_bio_form(instance=Student.objects.get(id=id))
        title = 'Edit Student Bio Info'
        return render(request, 'stu_bio_info.html', {
            'form': form,
            'title': title,
        })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def show_stu(request, id):
    try:
        student = Student.objects.get(pk=id)
    except Student.DoesNotExist:
        raise Http404("Student does not exist.")
    context = {
        'stu': student
    }
    return render(request, 'show_stu.html', context)


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def advising_note(request, id):
    if request.method == 'POST':
        form = advising_note_form(request.POST)
        if form.is_valid():
            note = form.cleaned_data['note']
            stu = Student.objects.get(pk=id)
            firstName = stu.first_name
            lastName = stu.last_name
            advisingNote = Advising_Note(first_name=firstName, last_name=lastName, note=note)
            advisingNote.save()
            return redirect('advising_note', id=id)
    else:
        form = advising_note_form()
        advisingNotes = Advising_Note.objects.all()
    return render(request, 'advising_note.html', {
        'form': form,
        'advising_notes': advisingNotes,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def degree_info_more(request, id):
    try:
        degree = Degree.objects.get(id=id)
    except Degree.DoesNotExist:
        raise Http404("Degree does not exist.")
    student = Student.objects.get(pk=degree.stu.id)
    context = {
        'deg': degree,
        'stu': student,
    }
    return render(request, 'degree_info_more.html', context)


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def basic_info(request, id):
    student = Student.objects.get(id=id)
    return render(request, 'basic_info.html',  {
        'student': student,

    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def degree_info(request, id):
    student = Student.objects.get(id=id)
    return render(request, 'degree_info.html',  {
        'student': student,
        'id': id,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def degree_note(request, id):
    degree = Degree.objects.get(id=id)  # problem
    if request.method == 'POST':
        # request.POST: hit the post request
        form = degree_note_form(request.POST, instance=Degree.objects.get(id=id))
        if form.is_valid():
            form.save()
            return redirect('degree_info', id=degree.stu.id)
    else:
        form = degree_note_form(instance=Degree.objects.get(id=id))
    return render(request, 'degree_note.html',  {
        'degree': degree,
        'form': form,
    })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def delete_stu(request, id):
    if not permission_check(request, Student, 'del'):
        return HttpResponse("Permission Denied")
    return delete(request, Student, id, "Student", 'UIN', 'uin', '/students/')


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def degrees(request, stu_id, option='', id=0):
    if option == 'del':
        if not permission_check(request, Degree, option):
            return HttpResponse("Permission Denied")
        return delete(request, Degree, id, "Degree", "",
                      "deg_type", "/student/" + stu_id + "/degrees/")
    if request.method == 'POST':
        if not permission_check(request, Degree, option):
            return HttpResponse("Permission Denied")
        return post_degrees(request, stu_id, option, id)
    else:
        forms, student = get_stu_objs(Degree, deg_form, stu_id, option)
        cur_deg_id = student.cur_degree.id if student and student.cur_degree else -1
        return render(request, 'degrees.html', {
            'stu': student,
            'cur_deg_id': cur_deg_id,
            'forms': forms,
            'option': option,
        })


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def quals(request, deg_id, option='', id=0):
    if option == 'del':
        if not permission_check(request, Qual, option):
            return HttpResponse("Permission Denied")
        return delete(request, Qual, id, "Qual", "",
                      "result", "/degree/" + deg_id + "/quals/")
    if request.method == 'POST':
        if not permission_check(request, Qual, option):
            return HttpResponse("Permission Denied")
        return post_quals(request, deg_id, option, id)
    else:
        forms, degree = get_deg_objs(Qual, qual_form, deg_id, option)
        return render(request, 'quals.html', {
            'stu': degree.stu,
            'deg': degree,
            'forms': forms,
            'option': option,
        })


@user_passes_test(lambda u: u.is_superuser)
def download_stu_info(request, **kwargs):
    models = [Student, Degree, Pre_Exam_Info, T_D_Info]
    if request.method == 'POST':
        fields = {}
        wb = Workbook()
        ws = wb.active
        ws.title = "Information of Students"
        i, j = 1, 1
        for model in models:
            name = model._meta.model_name
            sub_fields = request.POST.getlist(name)
            sub_fields_display = []
            for field in model._meta.fields:
                prefix = ""
                if name != 'student' and name != 'degree':
                    prefix = model._meta.verbose_name + " "
                if field.attname in sub_fields:
                    sub_fields_display.append(prefix + field.verbose_name)
            for field in sub_fields_display:
                ws.cell(row=i, column=j, value=field)
                j += 1
            fields[model._meta.model_name] = sub_fields
        i += 1
        students = Student.objects.all()
        seach_dict = get_stu_search_dict(kwargs)
        if kwargs:
            students = students.filter(**seach_dict)
        students = students.order_by('uin')
        for stu in students:
            j = 1
            for model in models:
                name = model._meta.model_name
                if name == 'student':
                    obj = stu
                elif name == 'degree':
                    obj = stu.cur_degree
                else:
                    obj = getattr(stu.cur_degree, name) if hasattr(stu.cur_degree, name) else None
                if obj:
                    for field in fields[name]:
                        if hasattr(obj, "get_{0}_display".format(field)):
                            text = getattr(obj, "get_{0}_display".format(field))()
                            ws.cell(row=i, column=j, value=text)
                        else:
                            ws.cell(row=i, column=j, value=obj.__dict__[field])
                        j += 1
                else:
                    j += len(fields[name])
            i += 1
        file_name = "data.xlsx"
        file_path = os.path.join(settings.MEDIA_ROOT, file_name)
        try:
            if not os.path.isdir(settings.MEDIA_ROOT):
                os.mkdir(settings.MEDIA_ROOT)
            wb.save(file_path)
        except:
            messages.error(request, "Some error has occured, please retry it later.")
            return redirect('download_stu_info')
        finally:
            return redirect('get_tmp_file',
                            file_path=file_name,
                            content_type="application/vnd.ms-excel")
    else:
        fields = []
        for model in models:
            sub_fields = []
            for field in model._meta.fields:
                if not 'id' in field.attname:
                    sub_fields.append((field.attname, field.verbose_name))
            fields.append([model._meta.model_name, model._meta.verbose_name, sub_fields])
        return render(request, 'download_stu_info.html', {
            'fields': fields,
        })


class Tmp_File(object):
    def __init__(self, filename):
        self.filename = filename
        self.fd = None

    def open(self, mode):
        if self.fd == None:
            self.fd = open(self.filename, mode)
        return self.fd

    def __del__(self):
        if self.fd != None:
            self.fd.close()
            os.remove(self.filename)


@conditional_decorator(login_required(login_url='/login/'), not settings.DEBUG)
def get_tmp_file(request, file_path, content_type):
    try:
        if file_path[0:10] == 'documents/' or '../' in file_path:
            raise PermissionError
        file_path = os.path.join(settings.MEDIA_ROOT, file_path)
        fh = Tmp_File(file_path)
        content = fh.open('rb')
        response = HttpResponse(content, content_type=content_type)
        response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)
        return response
    except:
        raise Http404
