# -*- coding: utf-8 -*-
import os
from datetime import datetime, date, time
from django.shortcuts import render
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.forms.models import inlineformset_factory
from django.core import mail
from django.core.mail import EmailMultiAlternatives

from dynastie.models import *
from dynastie.forms import *
from dynastie.search import *

from django.template.defaultfilters import register
from django.template import Variable, VariableDoesNotExist

@register.filter
def hash(object, attr):

    pseudo_context = { 'object' : object }
    try:
        value = Variable('object.%s' % attr).resolve(pseudo_context)
    except VariableDoesNotExist:
        value = None
    return value

def have_I_right(request, blog_id=None, post_id=None, must_be_superuser=False):
    b = None
    p = None

    if must_be_superuser and not request.user.is_superuser:
        raise Http404

    if not post_id is None:
        p = Post.objects.get(pk=post_id)
        
        if p is None:
            raise Http404

        blog_id = p.blog.id

    if not blog_id is None:
        if not request.user.is_superuser:
            b = Blog.objects.filter(pk=blog_id, writers=request.user.id)
            if len(b) == 0:
                raise Http404
            b = b[0]
        else:
            b = Blog.objects.get(pk=blog_id)
    
        if b is None:
            raise Http404

    return (b, p)

def createNavigationBar(blog_id, cur_page, nb_pages):
    if nb_pages == 0: return ''

    navigation_bar = ''
    if cur_page == 0:
        navigation_bar += '<< <'
    else:
        navigation_bar += '<a href="/blog/%d?page=0">&lt;&lt;</a> ' % blog_id
        navigation_bar += '<a href="/blog/%d?page=%d">&lt;</a> ' % (blog_id, cur_page-1)

    for i in range(nb_pages+1):
        if i == cur_page:
            navigation_bar += ' %d' % (i+1)
        else:
            navigation_bar += ' <a href="/blog/%d?page=%d">%d</a>' % (blog_id, i, i+1)

    if cur_page == nb_pages:
        navigation_bar += ' > >>'
    else:
        navigation_bar += '  <a href="/blog/%d?page=%d">&gt;</a>' % (blog_id, cur_page+1)
        navigation_bar += '  <a href="/blog/%d?page=%d">&gt;&gt;</a>' % (blog_id, nb_pages)

    return navigation_bar


def index(request):
    if request.user.is_authenticated():
            return HttpResponseRedirect('/blog')

    login_failed = False
    if 'login' in request.POST:
        user = authenticate(username=request.POST['login'], password=request.POST['password'])
        if user is None:
            login_failed = True
        else:
            login(request, user)
            if 'next' in request.GET:
                return HttpResponseRedirect(request.GET['next'])
            else:
                return HttpResponseRedirect('/blog')

    c = {'login_failed' : login_failed}

    return render(request, 'templates/login.html', c)

def disconnect(request):
    logout(request)
    c = {'login_failed' : False}
    return HttpResponseRedirect('/')

@login_required
def user(request):
    users = User.objects.all()

    c = {'users' : users}

    return render(request, 'templates/user.html', c)

@login_required
def add_user(request):
    if not request.user.is_superuser:
        return HttpResponseRedirect('/user')
 
    if request.method == 'POST':
        if 'add' in request.POST:
            form = UserForm(request.POST)
            if form.is_valid():
                form = form.save()
                user = User.objects.get(pk=form.id)
                user.set_password(request.POST['password'])
                user.save()
                return HttpResponseRedirect('/user')
        else:
            return HttpResponseRedirect('/user')
    else:
        form = UserForm()

    return render(request, 'add_user.html', {'form': form})

@login_required
def edit_user(request, user_id):
    user = User.objects.get(pk=user_id)

    if user is None:
        raise Http404

    edited = False

    if request.method == 'POST':
        if int(user_id) != int(request.user.id) and (not request.user.is_superuser):
            return HttpResponseRedirect('/user')
        if 'edit' in request.POST:
            form = UserForm(request.POST, instance=user, initial={'password':''})
            if form.is_valid():
                form.save()
                if request.POST['password'] != '':
                    user.set_password(request.POST['password'])
                user.save()
                edited = True
        else:
            if 'delete' in request.POST and request.user.is_superuser:
                User.objects.get(pk=user_id).delete()
                return HttpResponseRedirect('/user')
            if 'cancel' in request.POST:
                return HttpResponseRedirect('/user')
    else:
        form = UserForm(instance=user, initial={'password':''})
        
    c = {'user_to_edit' : user, 'form' : form, 'edited' : edited}

    return render(request, 'templates/edit_user.html', c)

@login_required
def category(request, blog_id):
    b,_ = have_I_right(request, blog_id)

    categories = Category.objects.filter(blog_id=blog_id)

    c = {'categories' : categories, 'blog' : b}

    return render(request, 'templates/category.html', c)

@login_required
def add_category(request, blog_id):
    b,_ = have_I_right(request, blog_id)
 
    if request.method == 'POST':
        if 'add' in request.POST:
            form = CategoryForm(request.POST)
            form.blog = b
            if form.is_valid():
                form = form.save()
                return HttpResponseRedirect('/category/' + str(b.id))
        else:
            return HttpResponseRedirect('/category/' + str(b.id))
    else:
        form = CategoryForm()

    return render(request, 'add_category.html', {'form': form})

@login_required
def edit_category(request, category_id):
    category = Category.objects.get(pk=category_id)

    if category is None:
        raise Http404

    b,_ = have_I_right(request, category.blog.id)
    
    if request.method == 'POST':
        if 'cancel' in request.POST:
            return HttpResponseRedirect('/category/' + str(b.id))
        if 'edit' in request.POST:
            name = category.name
            name = name.strip()
            form = CategoryForm(request.POST, instance=category)
            if form.is_valid():
                if request.POST['name'] != name:
                    category.remove()
                form.save()
            return HttpResponseRedirect('/category/' + str(b.id))
    else:
        form = CategoryForm(instance=category)

    c = {'category' : category, 'form' : form}

    return render(request, 'templates/edit_category.html', c)

@login_required
def delete_category(request, category_id):
    category = Category.objects.get(pk=category_id)

    if category is None:
        raise Http404

    b,_ = have_I_right(request, category.blog.id)

    category.delete()

    return HttpResponseRedirect('/category/' + str(b.id))

@login_required
def tag(request, blog_id):
    b,_ = have_I_right(request, blog_id)

    tags = Tag.objects.filter(blog_id=blog_id)

    c = {'tags' : tags, 'blog' : b}

    return render(request, 'templates/tag.html', c)

@login_required
def edit_tag(request, tag_id):
    tag = Tag.objects.get(pk=tag_id)

    if tag is None:
        raise Http404

    b,_ = have_I_right(request, tag.blog.id)
    
    if request.method == 'POST':
        if 'cancel' in request.POST:
            return HttpResponseRedirect('/tag/' + str(b.id))
        if 'edit' in request.POST:
            name = tag.name
            form = TagForm(request.POST, instance=tag)
            if form.is_valid():
                if request.POST['name'] != name:
                    tag.remove()
                form.save()
            return HttpResponseRedirect('/tag/' + str(b.id))
    else:
        form = TagForm(instance=tag)

    c = {'tag' : tag, 'form' : form}

    return render(request, 'templates/edit_tag.html', c)

@login_required
def delete_tag(request, tag_id):
    tag = Tag.objects.get(pk=tag_id)

    if tag is None:
        raise Http404

    b,_ = have_I_right(request, tag.blog.id)

    tag.delete()

    return HttpResponseRedirect('/tag/' + str(b.id))

@login_required
def blog(request):
    if request.user.is_superuser:
        b = Blog.objects.all()
    else:
        b = Blog.objects.filter(writers=request.user.id)

    c = {'blogs' : b}

    return render(request, 'templates/blog.html', c)

@login_required
def add_blog(request):
    if not request.user.is_superuser:
        return HttpResponseRedirect('/blog')
 
    if request.method == 'POST':
        if 'add' in request.POST:
            form = BlogForm(request.POST)
            if form.is_valid():
                form = form.save()
                form.create()
                return HttpResponseRedirect('/blog')
        else:
            return HttpResponseRedirect('/blog')
    else:
        form = BlogForm()

    return render(request, 'add_blog.html', {'form': form})

@login_required
def view_blog(request, blog_id):
    b,_ = have_I_right(request, blog_id)

    posts = Post.objects.filter(blog=b)
    count = posts.count()
    nb_pages = int(count/50)
    if 'page' in request.GET:
        cur_page = int(request.GET['page'])
    else:
        if 'cur_page' in request.session:
            cur_page = request.session['cur_page']
        else:
            cur_page = 0

    # Prevent error injection
    if cur_page < 0 : cur_page = 0
    if cur_page > nb_pages : cur_page = nb_pages-1

    request.session['cur_page'] = cur_page

    start = cur_page * 50
    end = start + 50

    posts = posts.order_by('-creation_date')[start:end]
    form = BlogForm(instance=b)
    
    comments = Comment.objects.all()
    dict_comments = {}
    for comment in comments:
        key = comment.post.id
        if not key in dict_comments:
            dict_comments[key] = 1
        else:
            dict_comments[key] = dict_comments[key] + 1

    navigation_bar = createNavigationBar(b.id, cur_page, nb_pages)

    c = {'blog' : b, 'posts' : posts, 'form' : form, 'comments' : dict_comments, 'navigation_bar' : navigation_bar}

    return render(request, 'templates/view_blog.html', c)

@login_required
def edit_blog(request, blog_id):
    if not request.user.is_superuser:
        return HttpResponseRedirect('/blog/' + str(blog_id))

    b = Blog.objects.get(pk=blog_id)

    if b is None:
        raise Http404

    edited = False

    if request.method == 'POST':
        if 'edit' in request.POST:
            form = BlogForm(request.POST, instance=b)
            if form.is_valid():
                form.save()
                edited = True
        else:
            if 'delete' in request.POST:
                b = Blog.objects.get(pk=blog_id)
                b.delete()
                return HttpResponseRedirect('/blog')
    else:
        form = BlogForm(instance=b)

    posts = Post.objects.filter(blog=b).order_by('-creation_date')

    c = {'blog' : b, 'posts' : posts, 'form' : form, 'edited' : edited}

    return render(request, 'templates/view_blog.html', c)

@login_required
def add_post(request, blog_id):
    (b,_) = have_I_right(request, blog_id)

    if request.method == 'POST':
        if 'add' in request.POST:
            post = Post(blog=Blog.objects.get(pk=blog_id), author=User.objects.get(pk=request.user.id), creation_date=datetime.now(), modification_date=datetime.now())
            content = request.POST['content']
            # del request.POST['content']
            form = PostForm(request.POST, instance=post)
            if form.is_valid():
                form = form.save()
                form.createPost(content, request.POST['text_tags'])
                s = Search()
                s.index_post(b, form.id)
                return HttpResponseRedirect('/blog/' + blog_id)
        else:
            return HttpResponseRedirect('/blog/' + blog_id)
    else:
        form = PostForm()

    return render(request, 'add_post.html', {'form': form, 'blog_id' : blog_id})

@login_required
def edit_post(request, post_id):
    (b, post) = have_I_right(request, None, post_id)

    title = post.title
    blog_id = b.id

    if request.method == 'POST':
        if 'edit' in request.POST:
            form = PostForm(request.POST, instance=post)
            if form.is_valid():
                if title != request.POST['title']:
                    post.remove()
                form.save()
                post.createPost(request.POST['content'], request.POST['text_tags'])
                s = Search()
                s.edit_post(b, post_id)
                return HttpResponseRedirect('/blog/' + str(blog_id))
        else:
            if 'cancel' in request.POST:
                return HttpResponseRedirect('/blog/' + str(blog_id))
    else:
        form = PostForm(instance=post, initial={'text_tags':', '.join((tag.name) for tag in post.tags.all())})

    filename = b.src_path + '/_post/' + str(post.pk)
    if os.path.exists(filename):
        f = open(filename, 'rb')
        content = f.read()
        f.close()
    else:
        content = 'Empty post'

    comments = Comment.objects.filter(post=post).order_by('date')
    comment_list = []
    for comment in comments:
        comment_list.append(comment)

    return render(request, 'edit_post.html', {
        'form': form, 'post_id' : post_id, 'content' : content,
        'blog_id' : blog_id, 'comments' : comment_list
    })

@login_required
def delete_post(request, post_id):
    (b, post) = have_I_right(request, None, post_id)

    s = Search()
    s.delete_post(b, post_id)

    post.delete()

    return HttpResponseRedirect('/blog/' + str(b.id))

def _generate(request, blog_id, report):
    b,_ = have_I_right(request, blog_id)

    posts = Post.objects.filter(blog=b).order_by('-creation_date')
    nb_pages = int(posts.count()/50)
    posts = posts[0:50]
    b = Blog.objects.get(pk=blog_id)
    form = BlogForm(instance=b)
    
    comments = Comment.objects.all()
    dict_comments = {}
    for comment in comments:
        key = comment.post.id
        if not key in dict_comments:
            dict_comments[key] = 1
        else:
            dict_comments[key] = dict_comments[key] + 1

    navigation_bar = createNavigationBar(b.id, 0, nb_pages)

    c = {'blog' : b, 'posts' : posts, 'form' : form, 'report': report, 'comments' : dict_comments, 'navigation_bar' : navigation_bar}
    
    return render(request, 'templates/generate.html', c)

@login_required
def generate(request, blog_id):
    b,_ = have_I_right(request, blog_id)

    report = b.generate()

    return _generate(request, blog_id, report)

@login_required
def generate_search(request, blog_id):
    b,_ = have_I_right(request, blog_id)

    hash_posts = {}
    hash_posts_content = {}
    s = Search(hash_posts, hash_posts_content)

    report = s.create_index(b)

    return _generate(request, blog_id, report)

@csrf_exempt
def search(request, blog_id):
    from dynastie.generators import search

    ref = request.META['HTTP_REFERER']

    b = Blog.objects.filter(pk=blog_id)

    if len(b) == 0:
        return HttpResponseRedirect(ref)

    b = b[0]

    if 'text' in request.POST:
        text = request.POST['text']
    else:
        return HttpResponseRedirect(ref)
        
    s = Search()
    post_list = s.search(b, text)

    if post_list is None: post_list = []

    hash_posts = {}
    hash_posts_content = {}
    s = search.Search(hash_posts, hash_posts_content)
    
    res = s.generate(b, b.src_path, b.output_path, post_list)

    c = {'result' : res}

    # Simple wrapper to HTML content
    return render(request, 'templates/search.html', c)

@login_required
def preview(request, blog_id):
    from dynastie.generators import post

    (b, p) = have_I_right(request, blog_id)

    values = {'title' : request.POST['title'], \
              'author' : request.user.first_name + ' ' + request.user.last_name, \
              'content' : request.POST['content']
              }

    engine = globals()['post']

    for name, obj in inspect.getmembers(engine):
        if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \
                and obj.__module__.endswith("post"):
            e = obj()
            content = e.preview(b.src_path, values)
            break

    output = b.output_path
    path = output + '/preview.html'
    if os.path.exists(path):
        os.unlink(path)

    f = open(path, 'wb')
    f.write(content)
    f.close()

    c = {'content' : content}

    return HttpResponseRedirect('http://' + b.name + '/preview.html')
    # return HttpResponseRedirect('http://' + 'localhost:8080' + '/preview.html')

def _tinymcelist(request, b, year, month):
    ret = 'var tinyMCEImageList = new Array('

    if month < 10:
        suffix = '/images/' + str(year) + '/0' + str(month)
    else:
        suffix = '/images/' + str(year) + '/' + str(month)

    path = b.src_path + '/' + suffix
    url = 'http://' + b.name + '/' + suffix + '/'

    if os.path.exists(path):
        files = ''
        for p in os.listdir(path):
            files += '["' + p + '", "' + url + p + '"],'
        # Remove last comma
        if len(files) != 0:
            ret += files[:-1]

    ret += ');'

    return ret

@login_required
def tinymcelist_add(request, blog_id):
    now = datetime.now()
    year = now.year
    month = now.month

    try:
        (b, p) = have_I_right(request, blog_id)
    except Http404:
        return HttpResponse('', content_type='application/x-javascript')

    ret = _tinymcelist(request, b, year, month)

    return HttpResponse(ret, content_type='application/x-javascript')

@login_required
def tinymcelist_edit(request, post_id):
    try:
        (b, post) = have_I_right(request, None, post_id)
    except Http404:
        return HttpResponse('', content_type='application/x-javascript')

    year = post.creation_date.year()
    month = post.creation_date.month()

    ret = _tinymcelist(request, b, year, month)

    return HttpResponse(ret, content_type='application/x-javascript')

@csrf_exempt
def add_comment(request, post_id, parent_id):
    from dynastie.generators import post

    ref = request.META['HTTP_REFERER']

    # Anti robot !!
    if request.POST['email'] != '':
        print 'fucking robot'
        return HttpResponseRedirect(ref)

    post = Post.objects.get(pk=post_id)
    if post is None:
        return HttpResponseRedirect(ref)

    blog = Blog.objects.get(pk=post.blog_id)

    if blog is None:
        return HttpResponseRedirect(ref)

    parent_id = int(parent_id)
    if parent_id != 0:
        parentComment = Comment.objects.get(pk=parent_id)
    else:
        parentComment = None

    if request.POST['author'] == '' or request.POST['the_comment'] == '':
        return HttpResponseRedirect(ref)

    # Behind nginx proxy
    if 'HTTP_X_FORWARDED_FOR' in request.META:
        ip = request.META['HTTP_X_FORWARDED_FOR']
    else:
        ip = request.META['REMOTE_ADDR']

    # Avoid script injection
    the_comment = request.POST['the_comment']
    the_comment = the_comment.replace('<', '&lt;')
    the_comment = the_comment.replace('>', '&gt;')

    if 'mel' in request.POST:
        mel = request.POST['mel'].strip()
    else:
        mel = ''

    comment = Comment(post=post, parent=parentComment, date=datetime.now(), author=request.POST['author'].strip(),\
                          email=mel, the_comment=the_comment, ip=ip)
    comment.save()

    engine = globals()['post']

    post_list = [post]
    for name, obj in inspect.getmembers(engine):
        if inspect.isclass(obj) and obj.__module__.startswith("dynastie.generators") \
                and obj.__module__.endswith("post"):
            e = obj()
            content = e._generate(blog, blog.src_path, blog.output_path, post_list)
            break

    # Send emails
    emails = {}
    comments = Comment.objects.filter(post=post).order_by('date')
    comment_index = str(len(comments))
    for comment in comments:
        email = comment.email
        if email != '' and email != request.POST['mel'] and not email in emails:
            emails[email] = comment.author


    if post.author.email not in emails:
        emails[post.author.email] = post.author.first_name

    if len(emails) > 0:
        connection = mail.get_connection(fail_silently=True)
        connection.open()
        
        messages = []
        subject = '[%s] Nouveau commentaire pour l\'article "%s"' % (blog.name, post.title)

        for email,author in emails.items():
            text_body = u'Bonjour %s,\n\nUn nouveau commentaire a été posté pour l\'article "%s".\n\n' % (author, post.title)
            text_body += u'Pour le consulter, rendez vous sur http://%s%s/#comment_%s\n\n----------------\n\n'  % (blog.name, post.getPath(), comment_index)
            text_body += the_comment
            text_body += '\n'

            html_body = u'<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /></head><body>'
            html_body += u'Bonjour %s,<br/><br/>Un nouveau commentaire a été posté pour l\'article "%s".<br/><br/>' % (author, post.title)
            html_body = html_body + u'Pour le consulter, rendez vous sur <a href="http://%s%s#comment_%s">http://%s%s#comment_%s</a><br/><br/>----------------<br/><pre>'  % (blog.name, post.getPath(), comment_index, blog.name, post.getPath(), comment_index)
            c = comment.the_comment
            html_body += the_comment + '</pre>'
            html_body += '</body></html>'

            msg = EmailMultiAlternatives(subject, text_body, 'no-reply@%s' % blog.name , [email])
            msg.attach_alternative(html_body, "text/html")
            messages.append(msg)

        connection.send_messages(messages)
        connection.close()
        
    response = HttpResponseRedirect(ref)
    response['Cache-Control'] = 'no-store, no-cache, must-revalidate'
    response['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT'

    response.set_cookie('author', request.POST['author'], domain=blog.name, secure=True, httponly=False);
    if mel != '':
        response.set_cookie('email', mel, domain=blog.name, secure=True, httponly=False);

    return response
    
    

@login_required
def edit_comment(request, comment_id):
    comment = Comment.objects.get(pk=comment_id)

    if comment is None:
        return Http404

    (b, post) = have_I_right(request, None, comment.post_id)
    post_id = comment.post_id

    if request.method == 'POST':
        if 'edit' in request.POST:
            form = CommentForm(request.POST, instance=comment)
            if form.is_valid():
                form = form.save()
                return HttpResponseRedirect('/post/edit/' + str(post_id))
        else:
            return HttpResponseRedirect('/post/edit/' + str(post_id))
    else:
        form = CommentForm(instance=comment)

    return render(request, 'edit_comment.html', {'form': form, 'comment':comment})

@login_required
def delete_comment(request, comment_id):
    comment = Comment.objects.get(pk=comment_id)
    if comment is None:
        return Http404

    (b, post) = have_I_right(request, None, comment.post_id)
    post_id = comment.post_id
    
    childs = Comment.objects.filter(parent=comment.id)

    try:
        parent = comment.parent
    except:
        parent = None

    for child in childs:
        child.parent = parent
        child.save()

    comment.delete()

    return HttpResponseRedirect('/post/edit/' + str(post_id))
