from datetime import datetime
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
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
from django.shortcuts import get_object_or_404, render_to_response, redirect
from django.template import RequestContext
from django.utils.translation import ugettext as _
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
from haystack.query import RelatedSearchQuerySet
from sorl.thumbnail import default, get_thumbnail
from sorl.thumbnail.images import ImageFile
from unicodedata import normalize
import json
import os
import requests
import subprocess
import uuid

import logging
logger = logging.getLogger(__name__)


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
    file_path = 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="' + file_path + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" opacity=".1"/>\n\
    <image xlink:href="' + file_path + '" x="0" y="0" preserveAspectRatio="none" width="1" height="1" clip-path="url(#fragment-clip)"/>\n\
</svg>'
    # We save the svg file
    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=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=400)
        item = get_object_or_404(Fragment, pk=item_id)
    else:
        return HttpResponse("item-type must be 'image' or 'fragment'.", status=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=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=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=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=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=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))



