import os
from view_utils import submitImage, extractPreviewInfo

from django.http import HttpResponse, Http404, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.db.models import Q
from django.db import connection
from django.contrib.admin.views.decorators import staff_member_required
from django.conf import settings
from django.template import RequestContext

from models import Image, Size, Tag, ImageException, TMP_URL

#used by rest APIs
MODELS_BY_NAME = {
    'image': Image,
    'size': Size,
    'tag': Tag
}

def handle_uploads(request, keys):
    """Helper function to extract files from a request ??"""
    saved = []
    
    upload_dir = date.today().strftime('uploaded')
    upload_full_path = os.path.join(settings.MEDIA_ROOT, upload_dir)

    if not os.path.exists(upload_full_path):
        os.makedirs(upload_full_path)

    for key in keys:
        if key in request.FILES:
            upload = request.FILES[key]
            while os.path.exists(os.path.join(upload_full_path, upload.name)):
                upload.name = '_' + upload.name
            dest = open(os.path.join(upload_full_path, upload.name), 'wb')
            for chunk in upload.chunks():
                dest.write(chunk)
            dest.close()
            saved.append((key, os.path.join(upload_dir, upload.name)))
    # returns [(key1, path1), (key2, path2), ...]
    return saved

@staff_member_required
def addImage(request):
    """Display upload form and handle initial submission.
    
    This will be called if someone clicks a link on the gallery
    to add an image.
    GET displays a simple form to allow a URL or an Upload.
    The form POSTS back to this same URL, which does initial
    checks.  It may then either display an error message to the
    user, or redirect them to the preview form.
    
    """
    if request.method == 'POST':
        #the input form is so simple that we don't use Django's
        #forms framework.
        
        image_url = request.POST.get('image_url', None)
        image_file = request.FILES.get('image_upload', None)
        try:
            img = submitImage(image_file, image_url)
        except ImageException, e:
            e = repr(e).replace('\\n', '<br/>').replace(' ', '&nbsp;')
            return render_to_response('imadj/upload_image.html', {'sizes': Size.objects.all(), 'error': e})
        if isinstance(img, Image):
            return render_to_response('imadj/preview_new_image.html', {'already_present': True, 'image': img})
        return HttpResponseRedirect("/imagegallery/preview/%s" % img['id'])
    else:
        sizes = Size.objects.all()
        return render_to_response('imadj/upload_image.html', RequestContext(request, {'sizes': sizes}))

    
@staff_member_required
def previewNewImages(request, image_ref):
    """Let them tag, crop, pick sizes etc and then eventually accept.
    
    The image_ref is the temp file which should have been uploaded on
    the last hit.
    """
    try:
        info = extractPreviewInfo(image_ref)
        info['settings'] = settings
    except IOError:
        raise Http404
    except ImageException, e:
        return render_to_response('imadj/upload_image.html', {'sizes': Size.objects.all(), 'error': unicode(e)})

    if request.method == 'POST':
        #they tried to save it.  Do some checks.
        if not info['size']:
            return render_to_response('imadj/preview_new_image.html', info)

        tags = request.POST.get('tags', '')
        img = Image.new(path=info['imgfilename'], size=info['size'])
        img.description = request.POST.get('description', '')
        img.caption = request.POST.get('caption', '')
        tags = request.POST.get('tags', '')
        if tags:
            img.set_tag_text(tags)
        info = {}
        if img.format == 'PDF':
            info.update(box=request.POST.get('box', 'media'), page=0)
        img.info = repr(info)
        
        check_custom = True
        custom_id = 1
        while (check_custom):
            attr = 'custom%d' % custom_id
            if attr in request.POST:
                setattr(img, attr, request.POST.get(attr, ''))
                custom_id += 1
            else:
                check_custom = False
        
        img.save()
        #go home.  It should appear first.
        return HttpResponseRedirect("/imagegallery/")
        
    return render_to_response('imadj/preview_new_image.html', RequestContext(request, info))

@staff_member_required
def imageGallery(request):
    """Display the gallery, optionally with criteria.
    
    This is the main page which will be seen on /imadj/
    """
    cursor = connection.cursor()
    
    images = Image.objects.all()
    
    cursor.execute("SELECT tag_id, count(*) FROM imadj_image_tags t GROUP BY tag_id")
    tags = cursor.fetchall()
    
    cursor.execute("SELECT imadj_tag.id FROM imadj_tag LEFT OUTER JOIN imadj_image_tags \
                   ON imadj_tag.id=tag_id WHERE tag_id IS NULL")
    unused_tags = cursor.fetchall()
    unused_tags = [x[0] for x in unused_tags] # Just get the tag names, not tuples
    
    sizes = Size.objects.all()
    
    size_id = request.GET.get('size', None)
    if size_id:
        size = Size.objects.get(id=size_id)
        images = images.filter(size=size)
    else:
        size = None
    
    tag = request.GET.get('tag', None)
    if tag == 'untagged':
        images = images.filter(tags=None)
    elif tag:
        images = images.filter(tags__id=tag)
    
    search = request.GET.get('search', '')
    if search:
        for word in search.split():
            images = images.filter(
                Q(description__icontains=word) |  #OR
                Q(tags=word) |
                Q(size__id=word)
                ).distinct()
    
    
    
    #allow 'tags' to be a list of tags; all must be present.
    tag_ids = request.GET.get('tags', None)
    if tag_ids:
        if ',' in tag_ids:
            tag_ids = [t.strip() for t in tag_ids.split(',')]
        else:
            tag_ids = tag_ids.split()
        #filter repeatedly
        for tag_id in tag_ids:
            images = images.filter(tags=tag_id)

    size_id = request.GET.get('size', None)

    images_per_page = 20
    page = int(request.GET.get('page', 1))
    from_image = images_per_page * (page - 1)
    to_image = from_image + images_per_page
    
    totalNumImages = images.count()
    currentNumImages = images.order_by('-date_modified')[from_image:to_image].count()
    
    #the slice at the end is actually generating a limit
    #query, not cutting off 20 in Python land.
    images = images.order_by('-date_modified')[from_image:to_image]
    
    max_pages_float = float(totalNumImages) / images_per_page
    max_pages = int(max_pages_float)
    if max_pages_float > max_pages:
        max_pages = max_pages + 1
    
    to_image = from_image + images.count()
    
    #imadj_custom_values = []
    #for attr in settings.IMADJ_CUSTOM_ATTIBUTES:
    #    imadj_custom_values.append(settings.IMADJ_CUSTOM_ATTIBUTES
    
    
    namespace = dict(images=images,
                     tags=tags,
                     unused_tags=unused_tags,
                     selected_tag=tag,  #current selection if any
                     sizes=sizes,
                     selected_size=size,  #current selection if any
                     search=search,
                     totalNumImages=totalNumImages,
                     currentNumImages=currentNumImages,
                     page=page,
                     max_pages=max_pages,
                     pages=range(1,max_pages+1),
                     from_image=from_image+1,
                     to_image=to_image,
                     settings=settings,
                     )
    return render_to_response('imadj/main_page.html', RequestContext(request, namespace))


def show_image_details(request, image_ref):
    "Display (read-only) details about an image"
    
    namespace = dict(
            image = Image.objects.get(id=image_ref),
            TMP_URL = TMP_URL,
    )
    return render_to_response('imadj/image_detail_fragment.html', RequestContext(request, namespace))


@staff_member_required
def autocomplete_tags(request):
    """May be called by autocomplete.  Returns list of one item per line.
    
    It's often easier to put the tags in the template directly and save
    traffic as the user hits each key.
    """
    
    q = request.GET.get('q', None)

    tags = Tag.objects.all()

    if q:
        tags = tags.filter(id__contains=q)

    tags = tags.order_by('id',)
    output = '\n'.join([tag.id for tag in tags])
    return HttpResponse(output, mimetype="text/plain")


def test_transition(request, ref):
    "Render simple page to test the given transition"

    tag_id = ''
    size_id = ''
    #is ref a tag?
    found = Tag.objects.filter(id=ref).count()
    if found:
        tag_id = ref
    else:
        found = Size.objects.filter(id=ref).count()
        if found:
            size_id = ref

    limit = int(request.GET.get('limit', '0'))
    timeout = int(request.GET.get('timeout', '3000'))
    speed = int(request.GET.get('speed', '1000'))
    fx = request.GET.get('fx', 'fade')
    
    namespace = dict(tag_id=tag_id, size_id=size_id, limit=limit, 
            timeout=timeout, speed=speed, fx=fx       
            )
    namespace['media_url'] = settings.MEDIA_URL
    
    return render_to_response('imadj/test_transition.html', RequestContext(request, namespace))

