# coding=utf-8

import os
import logging
import urllib
import operator
from StringIO import StringIO

from django.template import RequestContext, loader
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
from django.utils.encoding import smart_unicode
from django.db.models import Q

from models import Publication
from forms import ImportForm, SimpleSearchForm, UploadForm
from helpers import import_utils, pdf_utils, publist_utils, bibtex_utils

def index(request, template_name='index.html'):
    pubs = _get_publications_by_query(request)
    pubs_by_year = publist_utils.group_pubs_by_year(pubs)
    for year, pubs4year in pubs_by_year.items():
        pubs_by_year[year] = publist_utils.sort_pubs_by_author(pubs4year)
    if 'searchBy' in request.GET:
        searchForm = SimpleSearchForm(initial={'searchBy' : request.GET['searchBy']})
    else:
        searchForm = SimpleSearchForm()
    
    omitYears = request.GET.get('omitYears', 'false').lower() == 'true'
    
    bibtex_query = [(key, [v.encode('utf-8') for v in request.GET.getlist(key)]) 
                    for key in request.GET.iterkeys()]
    
    t = loader.get_template(template_name)
    c = RequestContext(request, {
                 'bibtex_query' : urllib.urlencode(bibtex_query, doseq=True),
                 'authors' : _get_queried_attr(request, 'author'),
                 'years' : _get_queried_attr(request, 'year'),
                 'titles' : _get_queried_attr(request, 'title'),
                 'pubs_by_year' : sorted(pubs_by_year.items(), key=lambda (k, v): -k),
                 'search_form': searchForm,
                 'omitYears': omitYears})
    return HttpResponse(t.render(c))

def _get_queried_attr(request, attr):
    if request.GET.get('searchBy', None) == attr:
        return request.GET.getlist('argument')
    elif attr in request.GET:
        return request.GET.getlist(attr)
    else:
        return None

def _get_publications_by_query(request):
    authors = _get_queried_attr(request, 'author')
    titles = _get_queried_attr(request, 'title')
    years = _get_queried_attr(request, 'year')
    keys = _get_queried_attr(request, 'key')
    keywords = _get_queried_attr(request, 'keyword')
    
    qset = Publication.objects
    if years:
        qset = qset.filter(reduce(operator.or_, [Q(year=y) for y in years]))
    if titles:
        qset = qset.filter(reduce(operator.or_, [Q(title__icontains=t) for t in titles]))
    if authors:
        listOfQs = [
                    Q(authors__name__icontains=author) 
                    | (Q(editors__name__icontains=author) & Q(authors=None))
                    for author in authors]
        qset = qset.filter(reduce(operator.or_, listOfQs))
    if keys:
        qset = qset.filter(reduce(operator.or_, [Q(id=k) for k in keys]))
    if keywords:
        qset = qset.filter(reduce(operator.or_, [Q(keywords__name__icontains=kw) for kw in keywords]))
    return qset.distinct()

def advancedSearch(request):
    return render(request, 'advancedSearch.html')

@login_required
def import_pub(request):
    if request.method == 'POST': # If the form has been submitted...
        form = ImportForm(request.POST, request.FILES)
        if form.is_valid(): # All validation rules pass
#            f = request.FILES['bibtex']
#            bibtex_text = smart_unicode(f.read())
#            logging.warn(bibtex_text)
            import_utils.import_bibtex(smart_unicode(form.cleaned_data['bibtex']))
            return HttpResponseRedirect(reverse('index')) # Redirect after POST
    else:
        form = ImportForm() # An unbound form
    return render(request, 'import.html', {'form': form})

@login_required
def edit(request, pub_id):
#    pub_id = request.GET['pub_id']
    pub = Publication.objects.get(id=pub_id)
    params = {'upload_form': UploadForm(), 
              'pub': pub,
              }
    if request.method == 'POST' and 'pdf' in request.FILES:
        form = UploadForm(request.POST, request.FILES) # A form bound to the POST data
        pdf_utils.handle_uploaded_file(request.FILES['pdf'], pub_id)
        import_utils.update_bibtex_and_html_fields(pub_id)
        params['uploaded'] = True
    if pdf_utils.uploaded_file_exists(pub_id):
        params['pdf_url'] = pdf_utils.pubid2url(pub_id)
    return render(request, 'edit.html', params)

@login_required
def upload(request, pub_id):
    if request.method == 'POST' and 'pdf' in request.FILES: # If the form has been submitted...
        form = UploadForm(request.POST, request.FILES) # A form bound to the POST data
        pdf_utils.handle_uploaded_file(request.FILES['pdf'], pub_id)
        import_utils.update_bibtex_and_html_fields(pub_id)
        return HttpResponseRedirect(reverse('edit', args=[pub_id])) # Redirect after POST
    elif request.method == 'POST':
        return HttpResponseRedirect(reverse('edit', args=[pub_id]), uploadError='True')
    else:
        return render(request, 'error.html')

def download(request, pub_id):
    filepath = pdf_utils.pubid2filepath(pub_id)
    logging.warn(filepath)
    if not os.path.isfile(filepath):
        raise Http404
    else:
        response = HttpResponse(mimetype='application/pdf')
        response['Content-Disposition'] = 'attachment; filename=%s' % pdf_utils.pubid2filename(pub_id)
        response.write(open(filepath, 'rb').read())
        return response

def bibtex(request, pub_id):
    pub = Publication.objects.get(id=pub_id)
    response = HttpResponse(mimetype='text/plain')
    response['Content-Disposition'] = 'attachment'
    response.write(pub.get_bibtex())
    return response

def bibtex_aggregate(request):
    pubs = _get_publications_by_query(request)
    response = HttpResponse(mimetype='text/plain')
    response['Content-Disposition'] = 'attachment'
    response.write(bibtex_utils.get_bibtex_aggregate(pubs))
    return response

@login_required
def deletePublication(request, pub_id):
    pub = Publication.objects.get(id=pub_id)
    pub.delete()
    pdf_utils.delete_uploaded_file(pub_id)
    return HttpResponseRedirect(reverse('index'))

@login_required
def deletePdf(request, pub_id):
    pdf_utils.delete_uploaded_file(pub_id)
    import_utils.update_bibtex_and_html_fields(pub_id)
    
    return HttpResponseRedirect(reverse('edit', args=[pub_id]))

def about(request):
    return render(request, 'about.html')
