import base64
from itertools import groupby
import lxml.etree
from operator import itemgetter

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import Group
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse  # , resolve
from django.db import transaction
from django.http import (HttpResponseForbidden, HttpResponseNotFound,
    HttpResponseRedirect)
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _

import ldt.auth as ldt_auth
from ldt.indexation import get_results_with_context, highlight_documents
from ldt.ldt_utils import contentindexer
from ldt.ldt_utils.forms import SearchForm
from ldt.ldt_utils.models import Content, Project, Segment
from ldt.ldt_utils.projectserializer import ProjectJsonSerializer
from ldt.ldt_utils.utils import boolean_convert
from ldt.ldt_utils.views.content import get_contents_page
from ldt.ldt_utils.views.project import (get_projects_page,
    get_published_projects_page)
from ldt.security.utils import add_change_attr, get_userlist
from ldt.utils.url import static, absurl
from ldt.utils.web_url_management import get_web_url


@login_required
def home(request):
    
    num_page = 0
    # Prepare contents pagination
    content_nb, nb_ct_pages, content_list = get_contents_page(num_page, request.user)
    # get list of projects owned by the current user
    project_nb, nb_pj_pages, project_list = get_projects_page(num_page, request.user)

    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
    
    # render list
    return render_to_response("ldt/ldt_utils/workspace.html",
                              {'contents': content_list, 'nb_ct_pages': nb_ct_pages, 'content_nb': content_nb, 'current_content_page':float(num_page),
                               'projects': project_list, 'nb_pj_pages': nb_pj_pages, 'project_nb': project_nb, 'current_project_page':float(num_page),
                               'is_gecko': is_gecko
                               },
                              context_instance=RequestContext(request))

    

@login_required
def groups(request): 

    # get list of all published projects
    group_list = request.user.groups.exclude(name=settings.PUBLIC_GROUP_NAME)
    
    group_list = sorted(group_list.all(), key=lambda group: group.name.lower())    
    group_list = add_change_attr(request.user, group_list)

    can_add_group = request.user.has_perm('auth.add_group')
    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
    # render list
    return render_to_response("ldt/ldt_utils/groups.html",
                              {'groups': group_list,
                               'is_gecko': is_gecko,
                               'can_add_group': can_add_group},
                              context_instance=RequestContext(request))


@login_required
def published_project(request): 

    # get list of all published projects
    #project_list = Project.safe_objects.filter(state=2).exclude(title__startswith='front') #@UndefinedVariable
    num_page = 0
    project_nb, nb_pj_pages, project_list = get_published_projects_page(num_page)
    # Search form
    form = SearchForm()

    is_gecko = ((request.META['HTTP_USER_AGENT'].lower().find("firefox")) > -1);
    
    # render list
    return render_to_response("ldt/ldt_utils/published_projects.html",
                              {'projects': project_list, 'nb_pj_pages': nb_pj_pages, 'project_nb': project_nb, 'current_project_page':float(num_page), 
                               'form': form, 'is_gecko': is_gecko},
                              context_instance=RequestContext(request))


def share_filter(request, filter, use_groups=False):  # @ReservedAssignment
    use_groups = boolean_convert(use_groups)
    if not filter or len(filter) == 0:
        raise AttributeError("filter should be a string")
    
    filter = filter[1:]    # @ReservedAssignment
    resp = get_userlist(request.user, filter=filter)
            
    if use_groups:
        groups = Group.objects.filter(name__icontains=filter).exclude(name=settings.PUBLIC_GROUP_NAME)[0:20]

        for g in groups:
            resp.append({'name': g.name, 'id': g.id, 'type': 'group'})
    
    resp = sorted(resp, key=lambda elem: elem['name'].lower())
    
    return render_to_response("ldt/ldt_utils/partial/sharewith.html", {'elem_list' : resp}, context_instance=RequestContext(request))



def search_form(request): 
    form = SearchForm()
    return render_to_response('ldt/ldt_utils/search_form.html', {'form': form} , context_instance=RequestContext(request))

@login_required
def search_index(request):
    language_code = request.LANGUAGE_CODE[:2]
    nb = 0
    nb_segment=0
    results = []
    search = ''
    field = 'all'
    colorurl = static("ldt/swf/ldt/pkg/color.xml")
    i18nurl = static("ldt/swf/ldt/pkg/i18n")
    baseurl = static("ldt/swf/ldt/")
    sform = SearchForm(request.GET)
    if sform.is_valid():
        search = sform.cleaned_data["search"]
        queryStr = base64.urlsafe_b64encode(search.encode('utf8'))
        field = sform.cleaned_data["field"]
        page = sform.cleaned_data["page"] or 1
        ldt_pres = sform.cleaned_data["ldt_pres"]
        if ldt_pres:
            url = absurl(request, "ldt.ldt_utils.views.lignesdetemps.search_init", kwargs={'field':field, 'query':queryStr})
            return render_to_response('ldt/ldt_utils/init_ldt_full.html', {'colorurl': colorurl, 'i18nurl': i18nurl , 'language': language_code, 'baseurl': baseurl, 'url': url}, context_instance=RequestContext(request))
        else:                                        
            results, nb, nb_segment = get_search_results(request, search, field, page)            
            
    return render_to_response('ldt/ldt_utils/search_results.html', {'results': results, 'nb_results' : nb, 'nb_segment' : nb_segment, 'search' : search, 'field': field, 'colorurl': colorurl, 'i18nurl': i18nurl , 'language': language_code, 'baseurl': baseurl}, context_instance=RequestContext(request))
        
 
def get_search_results(request, search, field, page, content_list=None):
    # We parse the author if necessary. For author search to work in every case, we have to transform the query author:cheese shop into author:"CHEESE SHOP"
    if u'author:' in search.lower() :
        sub = search[7:]
        sub = sub.upper()
        if sub[0] != u'"':
            sub = u'"' + sub
        if sub[-1] != u'"':
            sub = sub + u'"'
        search = u'author:' + sub
    results = get_results_with_context(Segment, field, search, content_list)
    all_segments = Segment.objects.filter(element_id__in=[e['element_id'] for e in results])
    all_projects = Project.objects.filter(ldt_id__in=[e['project_id'] for e in results], state=2)
    all_contents = Content.objects.filter(iri_id__in=[e['iri_id'] for e in results]).select_related('stat_annotation')
    viewable_projects_id = [p.ldt_id for p in all_projects]
    nb_segment=0       
    complete_results = []           
    results.sort(key=lambda k: k['iri_id'])
           
    for iri_id, item in groupby(results, itemgetter('iri_id')):
        content=None
        content_filter = filter(lambda e: e.iri_id == iri_id, all_contents)
        if len(content_filter)>0:
            content = content_filter[0]
            if content.description is None:
                content.description = ''
        if content is None:
            continue
        all_related_segments = list(item)
                
        valid_segments = []
        for s in all_related_segments:
            array_of_segs = [seg for seg in all_segments if (seg.element_id == s['element_id'] and seg.project_id == s['project_id'] and seg.iri_id == s['iri_id'] and seg.cutting_id == s['cutting_id'] and seg.ensemble_id == s['ensemble_id']) ]
            if len(array_of_segs)>0:
                segment = array_of_segs[0]
                    
                segment.score = s['score']
                segment.indexation_id = s['indexation_id']
                segment.context = s['context']
                segment.context_tags = s['tags']
                segment.highlighted = s['highlighted']
                                        
                if not s['project_id']:
                    segment.project_id = '_'
                    valid_segments.append(segment)
                    nb_segment+=1
                elif s['project_id'] in viewable_projects_id:
                    valid_segments.append(segment)
                    nb_segment+=1
            
        # If all segments found belong to unpublished projects or projects
        # the current user is not allowed to see
        if not valid_segments:
            continue
            
        score = sum([seg.score for seg in valid_segments])
        complete_results.append({
                                 'list': valid_segments,
                                 'score': score,
                                 'content': content,                                         
                                 })                
      
    complete_results.sort(key=lambda k: k['score'])
    
    paginator = Paginator (complete_results, settings.LDT_RESULTS_PER_PAGE)
    
    try:
        results = paginator.page(page)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
            
    results.object_list = highlight_documents(results.object_list, search, field)
    
    return results, len(complete_results), nb_segment
   

def loading(request): 
    return render_to_response('ldt/ldt_utils/loading.html', context_instance=RequestContext(request))
   

@transaction.atomic
def delete_segment(request, project_id, content_id, ensemble_id, cutting_id, segment_id):
    if project_id and project_id != "_" :
        project = Project.safe_objects.get(ldt_id=project_id) #@UndefinedVariable
        if project:
            ldtdoc = lxml.etree.fromstring(project.ldt_encoded)
            xstr = "/iri/annotations/content[@id='%s']/ensemble[@id='%s']/decoupage[@id='%s']/elements/element[@id='%s']" % (content_id, ensemble_id, cutting_id, segment_id)
            element = None
            try:
                element = ldtdoc.xpath(xstr)
            except:
                return HttpResponseNotFound(_("Annotation not found in the xml"))
            if element and len(element)>0:
                # element[0] is the annotation to remove
                el = element[0]
                el.getparent().remove(el)
                project.ldt = lxml.etree.tostring(ldtdoc)
                project.save(must_reindex=False)
                contentindexer.delete_segment(project, project_id, content_id, ensemble_id, cutting_id, segment_id)                
                
                return HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
            else:
                return HttpResponseNotFound(_("Annotation not found"))
        else:
            return HttpResponseNotFound(_("Project not found"))
    else:
        return HttpResponseNotFound(_("Project not found"))

