from datetime import datetime
import json
import logging
import os
import subprocess
from unicodedata import normalize
import uuid

from django.conf import settings
from django.contrib.auth import authenticate, login, get_user_model, SESSION_KEY, \
    load_backend, BACKEND_SESSION_KEY
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.core.urlresolvers import reverse
from django.db.models.aggregates import Max
from django.http.response import HttpResponseForbidden, HttpResponse, \
    HttpResponseBadRequest
from django.shortcuts import get_object_or_404, render_to_response, redirect
from django.template import RequestContext
from django.utils.importlib import import_module
from django.utils.translation import ugettext as _
from django.views.decorators.csrf import csrf_exempt
from haystack.query import RelatedSearchQuerySet
import requests
from sorl.thumbnail import default, get_thumbnail
from sorl.thumbnail.images import ImageFile

from egonomy.auth import parse_egonomy_token
from egonomy.models import ImageMetadata, Image, Fragment, ImageInfo, Collection, \
    CollectionItem
from egonomy.search_indexes import QueryParser
from egonomy.search_indexes.paginator import SearchPaginator
from egonomy.search_indexes.query import ModelRelatedSearchQuerySet
from egonomy.utils.queries import cache_generics


logger = logging.getLogger(__name__)
User = get_user_model()

def home(request):
    
    # We force list() because if not, img_id_list is a valuelistqueryset and not a list of values.
    # We separate image requests and make requests with select_related to optimize database hits.
    nb_display = 4
    img_id_list = list(Image.objects.values_list('id', flat=True).annotate(date_modif=Max('fragment__date_saved')).exclude(date_modif=None).order_by('-date_modif')[:nb_display])
    img_list = Image.objects.filter(id__in=img_id_list).select_related('info', 'metadata')
    frg_list = Fragment.objects.all().order_by('-date_saved').select_related('image', 'image__info', 'image__metadata','author')[:nb_display]
    
    return render_to_response("egonomy_home.html",
                              {'img_list':img_list, 'fragment_list':frg_list, 'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))


def annotate_picture(request, image_id):

    img = get_object_or_404(Image.objects.select_related('info', 'metadata'), id=image_id)
    
    # We force list() to get only one database hit instead of 3 (first request, count, [0])
    frg_list = list(Fragment.objects.filter(image=img).order_by('-date_saved').select_related('image', 'image__info', 'image__metadata','author'))
    last_frg = None
    if len(frg_list)>0:
        last_frg = frg_list[0]
    
    # If we display the picture after a search, we propose the previous and next picture
    search = request.GET.get("search") or None
    index_search = request.GET.get("index_search") or None
    if index_search:
        index_search = int(index_search)
    nb_results = request.GET.get("nb_results") or None
    if nb_results:
        nb_results = int(nb_results)
    
    # Get collections
    related_collections = Collection.objects.filter(public=True, pk__in=CollectionItem.objects.filter(content_type=ContentType.objects.get_for_model(img), object_id=img.id).values_list('collection', flat=True)).select_related('author')
    
    return render_to_response("egonomy_annotate_picture.html",
                              {'img': img, 'fragment_list': frg_list, 'last_frg':last_frg,
                               'search': search, 'index_search': index_search, 'nb_results': nb_results,
                               'related_collections':related_collections,
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))


def view_fragment(request, fragment_pk):
    
    frg = get_object_or_404(Fragment.objects.select_related('image', 'image__info', 'image__metadata','author'), pk=fragment_pk)
    frg_list = Fragment.objects.filter(image=frg.image).select_related('image', 'image__info', 'image__metadata','author')
    
    fragment_only = {'true': True, 'false': False, "0": False, "1": True}.get((request.GET.get("fragment_only") or "1").lower())
    
    # If we display the after after a search, we propose the previous and next fragment
    search = request.GET.get("search") or None
    index_search = request.GET.get("index_search") or None
    if index_search:
        index_search = int(index_search)
    nb_results = request.GET.get("nb_results") or None
    if nb_results:
        nb_results = int(nb_results)
    
    # Get collections
    related_collections = Collection.objects.filter(public=True, pk__in=CollectionItem.objects.filter(content_type=ContentType.objects.get_for_model(frg), object_id=str(frg.pk)).values_list('collection', flat=True)).select_related('author')
    
    return render_to_response("egonomy_view_fragment.html",
                              {'fragment': frg, 'fragment_list': frg_list, 'fragment_only':fragment_only,
                               'search': search, 'index_search': index_search, 'nb_results': nb_results,
                               'related_collections':related_collections,
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))

@login_required
def create_fragment(request, image_id, fragment_pk=None):
    
    img = get_object_or_404(Image.objects.select_related('info', 'metadata'), id=image_id)
    frg_list = Fragment.objects.filter(image=img).order_by('-date_saved').select_related('image', 'image__info', 'image__metadata','author')
    frg_to_modify = False
    frg_data = None
    if fragment_pk:
        frg_data = get_object_or_404(Fragment.objects.select_related('author'), pk=fragment_pk)
        # We check if the current user is the fragment's author
        if frg_data.author != request.user:
            return HttpResponseForbidden(_("You are not allowed to modify this fragment."))
        frg_to_modify = True
    else:
        frg_duplicate_pk = request.GET.get("duplicate") or None
        if frg_duplicate_pk:
            frg_data = get_object_or_404(Fragment.objects.select_related('author'), pk=frg_duplicate_pk)
    
    return render_to_response("egonomy_create_fragment.html",
                              {'img': img, 'frg_data': frg_data,  'frg_to_modify': frg_to_modify, 'fragment_list': frg_list},
                              context_instance=RequestContext(request))

@login_required
def save_fragment(request):
    
    frg_title = request.POST["fragment_title"]
    frg_desc = request.POST["fragment_description"]
    frg_kw = request.POST["user_keywords"]
    frg_path = request.POST["fragment_path"]
    frg_image_id = request.POST["image_id"]
    if "fragment_pk" in request.POST:
        frg_pk = request.POST["fragment_pk"]
        frg = get_object_or_404(Fragment.objects.select_related('author'), pk=frg_pk)
        # We check if the current user is the fragment's author
        if frg.author != request.user:
            return HttpResponseForbidden(_("You are not allowed to modify this fragment."))
    else :
        img = get_object_or_404(Image, id=frg_image_id)
        frg = Fragment()
        frg.image = img
        frg.author = request.user
    
    frg.coordinates = frg_path
    frg.title = frg_title
    frg.description = frg_desc
    frg.tags = frg_kw
    frg.save()
    
    return redirect("view_fragment", fragment_pk=frg.pk)


def all_pictures(request):
    
    # Get the cur_page_nb number parameter if possible
    cur_page_nb = request.GET.get("page") or 1
    cur_page_nb = int(cur_page_nb)

    search = None
    nb_results = 1
    if "search" in request.GET:
        search = request.GET["search"]
        field = "all"
        if "field" in request.GET:
            field = request.GET["field"]

    img_list = Image.objects.select_related('info', 'metadata')
    nb = request.GET.get("limit") or getattr(settings,"IMAGES_PER_PAGE", 32)
    if search:
        if not field or field == 'all':
            field = 'text'
        qp = QueryParser(field)
        res = ModelRelatedSearchQuerySet(model=Image).filter(qp.parse(search)).models(ImageMetadata).load_all_queryset(Image, img_list).load_all()
        paginator = SearchPaginator(res, nb)
        nb_results = paginator.count
    else:
        img_list = img_list.order_by('pk').all()
        paginator = Paginator(img_list, nb)
    
    try:
        results = paginator.page(cur_page_nb)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
    
    url_pagination = reverse("all_pictures") + "?limit=" + str(nb)
    offset_search = None
    if search:
        url_pagination = url_pagination + "&search=" + search
        offset_search = int(nb) * (cur_page_nb-1)

    return render_to_response("egonomy_all_pictures.html",
                              {'results':results, 'nb_pages':paginator.num_pages, 'cur_page_nb':cur_page_nb, "search":search, "nb_results":nb_results, 
                               "url_pagination":url_pagination, "offset_search":offset_search, "all_pictures":True,
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))


def picture_by_search(request):
    
    # We get the picture in the context of a search
    index_search = request.GET.get("index_search") or None
    if not index_search:
        redirect("home")
    else:
        index_search = int(index_search)

    search = None
    if "search" in request.GET:
        search = request.GET["search"]
        field = "all"
        if "field" in request.GET:
            field = request.GET["field"]
    
    if search:
        if not field or field == 'all':
            field = 'text'
        qp = QueryParser(field)
        # We don't need to do .load_all_queryset(Image, img_list).load_all()
        # because all we need the image's id/pk
        res = ModelRelatedSearchQuerySet(model=Image).filter(qp.parse(search)).models(ImageMetadata)
        img = res[index_search]
        nb_results = len(res)
        return redirect(reverse("annotate_picture", args=[img.pk]) + "?search=" + search + "&index_search=" + str(index_search) + "&nb_results=" + str(nb_results))
    else:
        redirect("home")



def all_fragments(request):
        
    # Get the cur_page_nb number parameter if possible
    cur_page_nb = request.GET.get("page") or 1
    cur_page_nb = int(cur_page_nb)

    search = None
    nb_results = 1
    if "search" in request.GET:
        search = request.GET["search"]
        field = "all"
        if "field" in request.GET:
            field = request.GET["field"]

    frg_list = Fragment.objects.select_related('image', 'image__info', 'image__metadata','author')
    nb = request.GET.get("limit") or getattr(settings,"IMAGES_PER_PAGE", 32)
    if search:
        if not field or field == 'all':
            field = 'text'
        qp = QueryParser(field)
        res = RelatedSearchQuerySet().filter(qp.parse(search)).models(Fragment).load_all_queryset(Fragment, frg_list).load_all().highlight()
        paginator = Paginator(res, nb)
        nb_results = paginator.count
    else:
        frg_list = frg_list.order_by('pk').all()
        paginator = Paginator(frg_list, nb)
        
    try:
        results = paginator.page(cur_page_nb)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
        
    url_pagination = reverse("all_fragments") + "?limit=" + str(nb)
    offset_search = None
    if search:
        url_pagination = url_pagination + "&search=" + search
        offset_search = int(nb) * (cur_page_nb-1)

    return render_to_response("egonomy_all_fragments.html",
                              {"search_fragment":True, 'results':results, 'nb_pages':paginator.num_pages, 'cur_page_nb':cur_page_nb, 
                               "search":search, "nb_results":nb_results, "url_pagination":url_pagination,
                               "offset_search":offset_search, "offset_search":offset_search,
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))



def fragment_by_search(request):
    
    # We get the picture in the context of a search
    index_search = request.GET.get("index_search") or None
    if not index_search:
        redirect("home")
    else:
        index_search = int(index_search)

    search = None
    if "search" in request.GET:
        search = request.GET["search"]
        field = "all"
        if "field" in request.GET:
            field = request.GET["field"]
    
    if search:
        if not field or field == 'all':
            field = 'text'
        qp = QueryParser(field)
        # We don't need to do .load_all_queryset(Fragment, frg_list).load_all().highlight()
        # because all we need the fragment's pk
        res = RelatedSearchQuerySet().filter(qp.parse(search)).models(Fragment)
        frg = res[index_search]
        nb_results = len(res)
        return redirect(reverse("view_fragment", args=[frg.pk]) + "?search=" + search + "&index_search=" + str(index_search) + "&nb_results=" + str(nb_results))
    else:
        redirect("home")



def user_fragments(request, username):
        
    # Get the cur_page_nb number parameter if possible
    cur_page_nb = request.GET.get("page") or 1
    cur_page_nb = int(cur_page_nb)
    # get the username
    user = get_object_or_404(User, username=username)
    
    frg_list = Fragment.objects.filter(author=user).order_by('-date_saved').select_related('image', 'image__info', 'image__metadata','author')
    nb = request.GET.get("limit") or getattr(settings,"IMAGES_PER_PAGE", 32)
    paginator = Paginator(frg_list, nb)
        
    try:
        results = paginator.page(cur_page_nb)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
        
    url_pagination = reverse("user_fragments", args=[username]) + "?limit=" + str(nb)

    return render_to_response("egonomy_all_fragments.html",
                              {"user_fragments":True, 'username':username, 'results':results, 'nb_pages':paginator.num_pages, "search":None, 'cur_page_nb':cur_page_nb, "url_pagination":url_pagination,
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))


def delete_fragment(request):
    
    if "fragment_pk" in request.GET:
        frg_pk = request.GET["fragment_pk"]
        frg = get_object_or_404(Fragment.objects.select_related('author'), pk=frg_pk)
        # We check if the current user is the fragment's author
        if frg.author != request.user:
            return HttpResponseForbidden(_("You are not allowed to delete this fragment."))
        # We check if the fragment is not part of a collection
        nb_items = CollectionItem.objects.filter(content_type=ContentType.objects.get_for_model(frg), object_id=str(frg.pk)).count()
        if nb_items > 0:
            return HttpResponseForbidden(_("You can not delete this fragment, it is used in one or several collections."))
        # Delete the fragment
        frg.delete()
    if "next" in request.GET:
        # Redirect to the next parameter
        return redirect(request.GET["next"])
    else:
        # Redirect to the next parameter
        return redirect(reverse("user_fragments", args=[request.user.username]))



def senseetive_api(request):
        
    # Get the cur_page_nb number parameter if possible
    image_id = request.GET.get("image") or None
    frg_path = request.GET.get("path") or "MZ"
    if not image_id or frg_path=="MZ":
        return HttpResponseForbidden("The request needs an image and a not null path parameters.")
     
    img = get_object_or_404(Image.objects.select_related('info', 'metadata'), id=image_id)
    frg = Fragment()
    frg.image = img
    frg.coordinates = frg_path
    # We build the svg xml
    filepath = os.path.join(settings.MEDIA_ROOT, str(img.info.image_file))
    image_file = default.kvstore.get_or_set(ImageFile(img.info.image_file))
    ratio = int(100 * frg.ratio * image_file.ratio)
    svg = '<svg preserveAspectRatio="none" width="' + str(ratio) + 'px" height="100px" viewBox="' + frg.viewbox +'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n\
    <defs>\n\
       <clipPath id="fragment-clip">\n\
           <path d="' + frg_path + '" />\n\
       </clipPath>\n\
    </defs>\n\
    <image xlink:href="' + filepath + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" opacity=".1"/>\n\
    <image xlink:href="' + filepath + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" clip-path="url(#fragment-clip)"/>\n\
</svg>'
    # We save the svg filepath
    uid = str(uuid.uuid1())
    svg_file_path = os.path.join(settings.BATIK_RASTERIZER_TEMP_FOLDER, uid + '.svg')
    svg_file = open(svg_file_path,'w')
    svg_file.write(svg)
    svg_file.close()
    # We execute the batik command
    args = ["java", "-jar", settings.BATIK_RASTERIZER_PATH, svg_file.name]
    p = subprocess.Popen(args, stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    _, err = p.communicate()
    if p.returncode!=0:
        return HttpResponse("Batik error : " + str(err))
    
    # The picture png is now created, we log into the senseetive api
    params = {
              "xaction":"sessions.create",
              "login":settings.SENSEETIVE_API_USER,
              "pwd":settings.SENSEETIVE_API_PASSWORD,
              "xtenant":settings.SENSEETIVE_API_TENANT,
              "role":"user"
    }
    req = requests.get(url=settings.SENSEETIVE_API_URL, params=params, verify=False)
    resp = req.json()
    if "xsessionid" in resp:
        session_id = resp["xsessionid"]
    else:
        return HttpResponseForbidden("Failed to connect to Senseetive API (1)")
    
    # We create the contents.read request and load the picture
    png_file_path = os.path.join(settings.BATIK_RASTERIZER_TEMP_FOLDER, uid + '.png')
    # (queryid 50d0574a03000043102a5177 for AS algorythm, 
    # 50d0574a0300000f102a5177 pigment
    # 50d0574a03000021102a5177 Gabor
    # 5204f79339d3f8e8ba6fc073 DominanteColoree)
    files = {
              'image0': (uid + '.png', open(png_file_path, 'rb').read()),
    }
    params = {
              "xaction":"contents.read",
              "xsessionid":session_id,
              "queryid":"5204f79339d3f8e8ba6fc073",
              "_order_by_":"score[:desc]",
              "_row_first_":"0",
              "_row_last_":"10",
              "requestfieldname":"image0"
    }
    # We make the request
    req = requests.post(url=settings.SENSEETIVE_API_URL, data=params, files=files, verify=False)#, headers=headers)
    resp = req.json()
    # Now that we have a response, we can remove the svg and png files
    try:
        os.remove(svg_file_path)
    except OSError:
        pass
    try:
        os.remove(png_file_path)
    except OSError:
        pass
    # We parse the response
    if "contentlist" not in resp:
        return HttpResponseForbidden("Failed to connect to Senseetive API (3) : " + str(resp))
    # We get the content list
    contents = resp["contentlist"]
    keywords = {}
    images_data = []
    for c in contents:
        # For each content's keyword, we associate or add its score.
        score = c["contentimagelist"][0]["score"]
        kwl = c["keywordlist"]
        for kw in kwl:
            kw = normalize('NFC',kw)
            if kw in keywords:
                keywords[kw] = keywords[kw] + score
            else:
                keywords[kw] = score
        # We add the image and its metadatas in the images list. We take the id from the filename "id.jpg".
        images_data.append({"id":c["contentimagelist"][0]["filename"][:-4], "url":"", "keywords":kwl, "title":c["title"]})
    # We generate the thumbnail and add its url for each picture
    images = ImageInfo.objects.filter(id__in=[i["id"] for i in images_data])
    for i in images_data:
        # We allow ourselves to loop in a loop because we know images_data has only 10 entries.
        for img in images:
            if img.id==i["id"]:
                # Get the thumbnail with fixed width
                i["url_width"] = get_thumbnail(img.image_file, '100', format='PNG', crop='center', quality=99).url
                # Get the thumbnail with fixed height
                i["url_height"] = get_thumbnail(img.image_file, 'x100', format='PNG', crop='center', quality=99).url
                break
    
    # We sort the keywords by descending score
    keywords = sorted(keywords, key=keywords.get, reverse=True)
    
    return HttpResponse(json.dumps({"keywords":keywords, "images":images_data}), content_type="application/json")



def all_collections(request):
        
    # Get the cur_page_nb number parameter if possible
    cur_page_nb = request.GET.get("page") or 1
    cur_page_nb = int(cur_page_nb)
    
    collections = Collection.objects.filter(public=True).order_by('-modification').select_related('author', 'items')
    nb = request.GET.get("limit") or getattr(settings,"IMAGES_PER_PAGE", 32)
    paginator = Paginator(collections, nb)
        
    try:
        results = paginator.page(cur_page_nb)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
        
    url_pagination = reverse("all_collections") + "?limit=" + str(nb)

    return render_to_response("egonomy_all_collections.html",
                              {"user_collections":False, 'results':results, 'nb_pages':paginator.num_pages, 'cur_page_nb':cur_page_nb,
                               "url_pagination":url_pagination, 'all_collections':True},
                              context_instance=RequestContext(request))



def user_collections(request, username):
        
    # Get the cur_page_nb number parameter if possible
    cur_page_nb = request.GET.get("page") or 1
    cur_page_nb = int(cur_page_nb)
    # get the username
    user = get_object_or_404(User, username=username)
    
    if user==request.user:
        user_collections = True
        collections = Collection.objects.filter(author=user).order_by('-modification').select_related('author', 'items')
    else:
        user_collections = False
        collections = Collection.objects.filter(author=user).filter(public=True).order_by('-modification').select_related('author', 'items')
        
    nb = request.GET.get("limit") or getattr(settings,"IMAGES_PER_PAGE", 32)
    paginator = Paginator(collections, nb)
        
    try:
        results = paginator.page(cur_page_nb)
    except (EmptyPage, InvalidPage):
        results = paginator.page(paginator.num_pages)
        
    url_pagination = reverse("user_collections", args=[username]) + "?limit=" + str(nb)
    
    return render_to_response("egonomy_all_collections.html",
                              {"user_collections":user_collections, 'username':username, 'results':results, 'nb_pages':paginator.num_pages, 'cur_page_nb':cur_page_nb, "url_pagination":url_pagination},
                              context_instance=RequestContext(request))



@login_required
def save_collection(request):
    
    # Get common datas
    col_title = request.POST["collection-title"]
    col_desc = request.POST["collection-description"]
    # Get datas available only when we update the collection
    col_pk = None
    if "collection-pk" in request.POST:
        col_pk =  request.POST["collection-pk"]
    col_publication_type = 1
    if "collection-publication-type" in request.POST:
        col_publication_type = int(request.POST["collection-publication-type"])
    col_public = True
    if "collection-public" in request.POST:
        col_public = request.POST["collection-public"]
    
    if col_pk:
        # Update existing collection
        col = get_object_or_404(Collection, pk=col_pk)
    else:
        # New collection
        col = Collection() 
        col.author = request.user
    
    # Save datas
    col.title = col_title
    col.description = col_desc
    col.publication_type = col_publication_type
    col.public = col_public
    col.save()
    
    return redirect("view_collection", collection_pk=col.pk)




def view_collection(request, collection_pk):
    
    display = request.GET.get("display") or "list"
    if display!="list" and display!="mosaic" and display!="slideshow" and display!="geographical":
        display = "list"
    
    col = get_object_or_404(Collection.objects.select_related('author'), pk=collection_pk)
    items = None
    places = {}
    if display!="slideshow":
        # Avoid useless database query. The query will be done by embed_slideshow view
        items = CollectionItem.objects.filter(collection=col).select_related('author', 'content_type', 'object_id', 'content_object').order_by("order")
        cache_generics(items)
        # If display is geographical, we prepare the datas for to link places to item
        for item in items:
            if item.content_type.model == "fragment":
                loc = item.content_object.image.metadata.localisation
            else:
                loc = item.content_object.metadata.localisation
            if loc != "" and loc != None:
                if loc not in places:
                    # We create the entry
                    places[loc] = {"location":{}, "items":[item.pk]}
                else:
                    places[loc]["items"].append(item.pk)
    
    return render_to_response("egonomy_view_collection.html",
                              {'col':col, 'items':items, 'display':display, 'places':json.dumps(places),
                               'current_user_collection_list':current_user_collection_list(request)},
                              context_instance=RequestContext(request))



@login_required
def delete_collection(request):
    
    # Get collection primary key
    collection_pk = request.GET["collection_pk"]
    if collection_pk:
        # Update existing collection
        col = get_object_or_404(Collection.objects.select_related('author'), pk=collection_pk)
        # We check if the current user is the collection's author
        if col.author != request.user:
            return HttpResponseForbidden(_("You are not allowed to delete this collection."))
        # Delete the collection
        col.delete()
    
    # Redirect to user's list of collections
    return redirect("user_collections", username=request.user)




def embed_slideshow(request, collection_pk):
    
    col = get_object_or_404(Collection.objects.select_related('author'), pk=collection_pk)
    items = CollectionItem.objects.filter(collection=col).select_related('author', 'content_type', 'object_id', 'content_object').order_by("order")
    cache_generics(items)
    
    slides = []
    for item in items:
        if item.content_type.model == "fragment":
            fragment = item.content_object
            if fragment:
                slides.append({"type":"fragment", 
                               "title": fragment.title,
                               "author": str(fragment.author),
                               "src": fragment.image.info.image_file.url,
                               "path": fragment.coordinates,
                               "description": item.description
                               })
        elif item.content_type.model == "image":
            image = item.content_object
            if image:
                slides.append({"type":"image", 
                               "title": image.metadata.titre or _('No title'),
                               "author": image.metadata.auteur or "",
                               "src": image.info.image_file.url,
                               "description": item.description
                               })
    
    return render_to_response("egonomy_embed_slideshow.html",
                              {'col':col, 'items':items, "slides":json.dumps(slides)},
                              context_instance=RequestContext(request))




def current_user_collection_list(request):
    
    if request.user.is_authenticated():
        return Collection.objects.filter(author=request.user).order_by("-modification")
    else:
        return None



@login_required
def add_item_to_collection(request):
    
    col_pk = request.POST["collection-pk"]
    item_desc = request.POST["item-description"]
    item_type = request.POST["item-type"]
    item_id = request.POST["item-id"]
    
    # Test collection
    try:
        col_pk = int(col_pk)
    except:
        return HttpResponse("Collection number invalid.", status_code=400)
    col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
    # We check if the current user is the collection's author
    if col.author != request.user:
        return HttpResponseForbidden(_("You are not allowed to modify this collection."))
    # We update the collection's modification date because by create an item we don't really touch the collection objet
    col.modification = datetime.now()
    col.save()
    
    if item_type=="image":
        # Test image
        item = get_object_or_404(Image, id=item_id)
    elif item_type=="fragment":
        # Test fragment
        try:
            item_id = int(item_id)
        except:
            return HttpResponse("Fragment number invalid.", status_code=400)
        item = get_object_or_404(Fragment, pk=item_id)
    else:
        return HttpResponse("item-type must be 'image' or 'fragment'.", status_code=400)
    
    col_item = CollectionItem()
    col_item.collection = col
    col_item.content_type = ContentType.objects.get_for_model(item)
    col_item.object_id = str(item_id)
    col_item.content_object = item
    col_item.description = item_desc
    # Get the collection's max order and set the new item's one
    max_order = CollectionItem.objects.filter(collection=col).aggregate(Max('order'))['order__max']
    if not max_order:
        max_order = 0
    col_item.order = max_order + 1
    col_item.save()
    
    #return redirect("view_collection", collection_pk=col.pk)
    # It is an ajax call, everything is saved and we return the collection's url
    return HttpResponse(reverse("view_collection", args=[col_pk]))



def remove_item_from_collection(request):
    
    col_pk = request.GET["collection_pk"] or None
    item_pk = request.GET["item_pk"] or None
    if "display" in request.GET:
        display = request.GET["display"] or "list"
    else:
        display = "list"
    
    # Test collection
    try:
        col_pk = int(col_pk)
    except:
        return HttpResponse("Collection number invalid.", status_code=400)
    col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
    # We check if the current user is the collection's author
    if col.author != request.user:
        return HttpResponseForbidden(_("You are not allowed to modify this collection."))
    # We update the collection's modification date because by creating an item we don't touch the collection object
    col.modification = datetime.now()
    col.save()
    
    # Test item's pk
    if not item_pk:
        return HttpResponse("item_pk must be set.", status_code=400)
    # Get item
    item = get_object_or_404(CollectionItem, pk=item_pk)
    # Everything has been checked, we can delete the item
    item.delete()
    
    #return redirect("view_collection", collection_pk=col.pk)
    return redirect(reverse("view_collection", args=[col.pk]) + "?display=" + display)
    # It is an ajax call, everything is saved and we return the collection's url
    #return HttpResponse(reverse("view_collection", args=[col_pk]))



@login_required
def modify_item_in_collection(request):
    
    item_pk = request.POST["item-pk"] or None
    col_pk = request.POST["collection_pk"] or None
    description = request.POST["item-description"] or None
    
    # Test collection
    try:
        col_pk = int(col_pk)
    except:
        return HttpResponse("Collection number invalid.", status_code=400)
    col = get_object_or_404(Collection.objects.select_related('author'), pk=col_pk)
    # We check if the current user is the collection's author
    if col.author != request.user:
        return HttpResponseForbidden(_("You are not allowed to modify this collection."))
    # We update the collection's modification date because by modifying an item we don't touch the collection object
    col.modification = datetime.now()
    col.save()
    
    # Test item's pk
    if not item_pk:
        return HttpResponse("item_pk must be set.", status_code=400)
    # Get item
    item = get_object_or_404(CollectionItem, pk=item_pk)
    if item.collection != col:
        return HttpResponse("Item and collection are not related.", status_code=400)
    # Everything has been checked, we can modify and save the item
    item.description = description
    item.save()
    
    # It is an ajax call, we juste return "ok"
    return HttpResponse("modifyok")

@login_required
def import_collection(request):
    
    imagelist = request.GET["imagelist"] or None
    # =98/06-503033.jpg,59/08-523465.jpg,56/09-502439.jpg,XX/08-527515.jpg,AB/10-530083.jpg
    img_ids = []
    if imagelist is not None and imagelist!="":
        imagelist = imagelist.split(",")
        for i in imagelist:
            try:
                img_ids.append(i[i.index("/")+1:i.index(".")])
            except:
                return HttpResponse("Wrong image id. It must be like 'XX/XXXXXXX.jpg'.", status=400)
    if len(img_ids)==0:
        return HttpResponse("imagelist must not be empty.")
    # First we check if the user has not imported a collection with exactly the same images.
    user_collections = Collection.objects.filter(author=request.user)
    img_content_type = ContentType.objects.get_for_model(Image)
    for uc in user_collections:
        items = CollectionItem.objects.filter(collection=uc).select_related('content_type', 'object_id').order_by("order")
        # We check length
        if len(items)==len(img_ids):
            # We check if all items are images
            all_items_are_img = True
            for i in items:
                if i.content_type != img_content_type:
                    all_items_are_img = False
                    break
            # If necessary, we check if all img's ids are the same
            if all_items_are_img:
                col_img_ids = items.values_list('object_id', flat=True)
                same_ids = True
                for i in img_ids:
                    if i not in col_img_ids:
                        same_ids = False
                        break
                if same_ids:
                    return redirect("view_collection", collection_pk=uc.pk)
            
    # New collection
    col = Collection() 
    col.author = request.user
    td = _("Imported collection") + " " + datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    col.title = td
    col.description = td
    col.publication_type = 1
    col.public = True
    col.save()
    order = 1
    for i in img_ids:
        item = get_object_or_404(Image, id=i)
        col_item = CollectionItem()
        col_item.collection = col
        col_item.content_type = img_content_type
        col_item.object_id = i
        col_item.content_object = item
        col_item.description = ""
        col_item.order = order
        order += 1
        col_item.save()
    
    return redirect("view_collection", collection_pk=col.pk)
    #return HttpResponse("hello image list = " + str(img_ids))



@csrf_exempt
def ajax_login(request):
    if request.method == 'POST':
        username = request.POST.get('username', '').strip()
        password = request.POST.get('password', '').strip()
        if username and password:
            # Test username/password combination
            user = authenticate(username=username, password=password)
            # Found a match
            if user is not None:
                # User is active
                if user.is_active:
                    # Officially log the user in
                    login(request, user)
                    data = {'success': True}
                else:
                    data = {'success': False, 'error': 'User is not active'}
            else:
                data = {'success': False, 'error': 'Wrong username and/or password'}

            return HttpResponse(json.dumps(data), mimetype='application/json')

    # Request method is not POST or one of username or password is missing
    return HttpResponseBadRequest()



def check_egonomy_token(request, token):
    
    logger.debug("TOKEN : " + token)
    if not token:
        return HttpResponseBadRequest("token must be provided")
    
    token_items = parse_egonomy_token(token)
    
    session_key = token_items.get('sessionid', None)
    salt = token_items.get('salt', None)
    
    error_msg = None
    
    if len(token_items) != 2:
        error_msg = "Bad token size"
    elif not session_key:
        error_msg = 'No session id in token'
    elif not salt or len(salt) != getattr(settings, 'EGONOMY_SALT_LENGTH', 12):
        error_msg = 'Bad token format'
        
    if error_msg:
        return HttpResponseBadRequest("Bad token format : %s" % error_msg)

    res_msg = {}

    #get session
    engine = import_module(settings.SESSION_ENGINE)
    session = engine.SessionStore(session_key)
    
    user_id = session.get(SESSION_KEY)
    auth_backend = load_backend(session.get(BACKEND_SESSION_KEY))

    if session.get_expiry_age() < 0:
        res_msg['success'] = False
        res_msg['message'] = "Token expired"
    elif not user_id or not auth_backend:
        res_msg['success'] = False
        res_msg['message'] = "no user"
    else:
        user = None
        try:
            user = auth_backend.get_user(user_id)
        except:
            pass

        if not user:
            res_msg['success'] = False
            res_msg['message'] = "user unknown"
        else:
            username = getattr(user,User.USERNAME_FIELD)
            res_msg['success'] = True
            res_msg['message'] = ""
            res_msg['username'] = username.replace(settings.EGONOMY_USER_PREFIX,"")
            res_msg['external'] = username.startswith(settings.EGONOMY_USER_PREFIX)
            
    return HttpResponse(json.dumps(res_msg), mimetype='application/json')





