from django.contrib.auth.models import User
from django.forms.models import modelformset_factory
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponseRedirect
from django.template import Context, loader, RequestContext

from amnesia.ts.models import Ticket,Queue,Comment,TicketManager
from amnesia.ts.models import TicketForm
from django.contrib.auth.decorators import login_required
from email_notification import email_notify



def login_user(request):
    from django.contrib.auth import authenticate, login

    if not request.method == 'POST':
        if 'next' in request.GET:
            return render_to_response('ts/login.html', {
                                      'next' : request.GET['next']})
        else:
            return render_to_response('ts/login.html')

    if not 'username' in request.POST or not 'password' in request.POST:
        return render_to_response('ts/login.html')

    username = request.POST['username']
    password = request.POST['password']
    if not username or not password:
        return render_to_response('ts/login.html', {
                                  'message' : 'please fill in your complete login credentials'})

    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            if 'next' in request.POST:
                return HttpResponseRedirect(request.POST['next'])
            else:
                return HttpResponseRedirect('/ts/index/')
        else:
            return render_to_response('ts/login.html', {
                                      'message' : 'your user is deactivated'})
    else:
        return render_to_response('ts/login.html', {
                                  'message' : 'authentication failed'})

@login_required()
def detail(request, id):
    from django.db.models import Q
    from django.utils.datastructures import MultiValueDictKeyError
    p = get_object_or_404(Ticket, pk=id)
    comments = Comment.get_related_comments(id)

    if request.POST:
        if 'comment' in request.POST:
            if request.POST['comment'] == '':
                return render_to_response('ts/detail.html', {
                                          'ticket' : p,
                                          'comments' : comments,
                                          'message':'Your comment is empty'},
                                          RequestContext(request))

            comment        = Comment(text=request.POST['comment'])
            comment.owner  = request.user
            comment.ticket = p
            try:
                comment.repto  = Comment(id=request.POST['repto'])
            except MultiValueDictKeyError:
                pass
            comment.save()
            email_notify('comment', p, request, comment.text)
            if 'new_status' in request.POST:
                change_status(request, id, request.POST['new_status'])
                email_notify('status', p, request)

            return HttpResponseRedirect('/ts/detail/'+id)
    else:
        return render_to_response('ts/detail.html', {
                                  'ticket' : p,
                                  'editable' : p.resp == request.user or p.creator == request.user,
                                  'subscr' : p.subscr.all(),
                                  'comments' : comments},
                                  RequestContext(request))

@login_required()
def edit(request, id):
    from django.utils.datastructures import MultiValueDictKeyError

    p = get_object_or_404(Ticket, pk=id)
    comments = Comment.get_related_comments(id)

    if request.user != p.resp and request.user != p.creator:
        return render_to_response('ts/detail.html', {
                                  'ticket' : p,
                                  'editable' : False,
                                  'comments' : comments,
                                  'message' : 'You are not the owner and not responsible and therefore you can not edit this ticket.'},
                                  RequestContext(request))

    if not request.POST:
        t = TicketForm(None, instance=p)
        return render_to_response('ts/edit.html', {
                                  'ticket' : t,
                                  'users' : User.objects.all(),
                                  'queue' : Queue.objects.all(),
                                  'urgency' : Ticket.URG_CH,
                                  'status' : Ticket.STAT_CH,
                                  'comments' : comments},
                                  RequestContext(request))

    t = TicketForm(request.POST, instance=p)

    if t.is_valid():
        t.save()
        change_status(request,id,p.get_status())
        email_notify('edit', p, request)
        return HttpResponseRedirect('/ts/detail/'+id)
    else:
       return render_to_response('ts/edit.html', {
                                  'ticket' : t,
                                  'users' : User.objects.all(),
                                  'queue' : Queue.objects.all(),
                                  'urgency' : Ticket.URG_CH,
                                  'status' : Ticket.STAT_CH,
                                  'comments' : comments,
                                  'message' : t.errors},
                                  RequestContext(request))


from django.views.decorators.cache import cache_control
@cache_control(must_revalidate=True, max_age=0)
def logout_user(request):
    from django.contrib.auth import logout
    logout(request)
    return render_to_response('ts/login.html')


# just a wrapper around change_status with email notification
@login_required()
def set_status(request, id, stat):
    r = change_status(request, id, stat)
    p = get_object_or_404(Ticket, pk=id)
    email_notify('status', p, request)
    return r

@login_required()
def change_status(request, id, stat):
    from models import Ticket
    import datetime
    p = get_object_or_404(Ticket, pk=id)

    status = Ticket.get_foo_byname('status', stat)

    if not status:
        HttpResponseRedirect('/ts/index')

    p.status = status

    if status == 5:
        p.done = True
        p.d_date = datetime.datetime.today().strftime("%Y-%m-%d %H:%M")
    else:
        p.done = False
        p.d_date = None

    p.save()
    #print status
    #if status != 0 and status != 5:
    #    email_notify('status', p, request)
    return HttpResponseRedirect('/ts/index')

from django.views.decorators.cache import cache_control
@cache_control(must_revalidate=True, max_age=0)
@login_required()
def new_ticket(request):
    if request.method == 'POST':
        t = Ticket(creator=request.user)

        form = TicketForm(request.POST, instance=t)

        if form.is_valid():
            form.save()
            t.save()

            if 'resp' in request.POST and request.POST['resp'] != '':
                u = get_object_or_404(User, pk=request.POST['resp'])
                t.resp = u
                t.subscr.add(u)
                t.status = 1
                t.save()

            change_status(request,t.id,t.get_status())
            email_notify('new', t, request)
            return HttpResponseRedirect('/ts/index')
        else:
            return render_to_response('ts/new.html', {
                                      'form' : form,
                                      'message' : form.errors},
                                      RequestContext(request))
    else:

        form = TicketForm()
        return render_to_response('ts/new.html', {
                                  'form' : form},
                                  RequestContext(request))

@login_required()
def index(request):
    from django.db.models import Q

    sort    = 'urg'
    sort_vars = ['id', 'urg', 'e_date', 'resp', 'status']
    order = 'desc'
    order_vars = {'asc': 'desc', 'desc': 'asc'}

    # the following is an ugly hack
    if 'sort_by' in request.GET:
        if not 'order' in request.GET:
            pass
        else:
            if request.GET['order'] in order_vars.keys():
                order = request.GET['order']
            else:
                order = 'desc'

        if request.GET['sort_by'] in sort_vars:
            sort = request.GET['sort_by']

    if order == 'desc':
        ticket_list = Ticket.objects.filter(Q(done=False)).order_by('-'+sort)
    else:
        ticket_list = Ticket.objects.filter(Q(done=False)).order_by('-'+sort).reverse()

    order = order_vars[order]

    return render_to_response('ts/index.html', {
                              'ticket_list' : ticket_list,
                              'order' : order},
                              RequestContext(request))

@login_required()
def change_userdata(request):
    if not request.method == "POST":
        return render_to_response('ts/profile.html', {
                                  'user' : request.user.username},
                                  RequestContext(request))

    if not request.POST['pass1'] == request.POST['pass2']:
        return render_to_response('ts/profile.html', {
                                  'message' : 'the two passwords did not match'},
                                  RequestContext(request))

    m = User.objects.get(username=request.user.username)
    if not m.check_password(request.POST['password']):
        return render_to_response('ts/profile.html', {
                                  'message' : 'the given password does not match your current password'},
                                  RequestContext(request))

    m.set_password(request.POST['pass1'])
    m.save()
    return render_to_response('ts/profile.html', {
                              'message' : 'saved'},
                              RequestContext(request))


@login_required()
def subscribe(request, id):
    p = get_object_or_404(Ticket, pk=id)
    if not request.user in p.subscr.all():
        p.subscr.add(request.user)
    else:
        p.subscr.remove(request.user)

    p.save()
    return HttpResponseRedirect('/ts/detail/'+id)

@login_required()
def search(request):
    if not 'search_term' in request.POST:
        return render_to_response('ts/index.html', {
                                  'message' : 'Your query did not contain a search phrase'},
                                  RequestContext(request))

    search_term = request.POST['search_term']
    if search_term == '':
        return render_to_response('ts/index.html', {
                                  'message' : 'Your query did not contain a search phrase'},
                                  RequestContext(request))

    search_results = Ticket.objects.search(search_term)

    if search_results:
        return render_to_response('ts/index.html', {
                                  'ticket_list' : search_results},
                                  RequestContext(request))
    else:
        return render_to_response('ts/index.html', {
                                  'message' : 'Your query did not match any tickets'},
                                  RequestContext(request))

@login_required()
def take_ticket(request, id):
    p = get_object_or_404(Ticket, pk=id)

    if p.resp == request.user:
        p.resp = None
        p.status = 0
        p.save()
        email_notify('untake', p, request)
        return render_to_response('ts/detail.html', {
                                  'ticket' : p,
                                  'message' : 'You are no longer teh owner of this ticket'},
                                  RequestContext(request))

    #in case someone wants to prevent taking other peoples tickets...
    if p.resp:
        return render_to_response('ts/detail.html', {
                                  'ticket' : p,
                                  'message' : p.resp.username + ' already has taken this ticket'},
                                  RequestContext(request))

    p.resp = request.user
    if not request.user in p.subscr.all():
        p.subscr.add(request.user)

    if 0 == p.status:
        p.status = 1

    p.save()
    email_notify('take', p, request)
    return HttpResponseRedirect('/ts/detail/'+id)


def add_filter(attr, list):
    from django.db.models import Q
    q_objects = Q()

    for i in list:
        if attr == 's_desc' or attr == 'l_desc':
            terms = [term.strip() for term in i.split()]
            for term in terms:
                if term.find('!') == 0:
                    a = {attr + '__icontains' : term.lstrip('!')}
                    q_objects = q_objects & ~Q(**a)
                else:
                    a = {attr + '__icontains' : term}
                    q_objects = q_objects | Q(**a)
        else:
            neg = i.find('!')
            if neg == 0:
                i = i.lstrip('!')
            tmp = Ticket.get_foo_byname(attr, i)
            if tmp or tmp == int(0):
                a = { attr : Ticket.get_foo_byname(attr, i)}
                if neg == 0:
                    q_objects = q_objects & ~Q(**a)
                else:
                    q_objects = q_objects | Q(**a)

    return q_objects


@login_required()
def filter(request):
    from django.db.models import Q

    if not request.method == 'GET':
        return HttpResponseRedirect('/ts/index/')

    if len(request.GET) == 0:
        return render_to_response('ts/filter.html', {
                                   'users' : User.objects.all(),
                                   'queue' : Queue.objects.all(),
                                   'status' : Ticket.STAT_CH,
                                   'urgency' : Ticket.URG_CH},
                                   RequestContext(request))

    valid_filters = ['status', 'urg', 's_desc', 'l_desc', 'queue', 'resp', 'creator']
    supplied_vfilters = [i[0] for i in request.GET.items() if i[0] in valid_filters]
    q = Q()

    for i in supplied_vfilters:
        foo = request.GET.getlist(i)
        if foo[0] != '':
            tmp = add_filter(str(i), foo)
            q = q & add_filter(str(i), foo) if tmp else q


    return render_to_response('ts/index.html', {
                               'users' : User.objects.all(),
                               'queue' : Queue.objects.all(),
                               'status' : Ticket.STAT_CH,
                               'ticket_list' : None if not q else Ticket.objects.filter(q),
                               'urgency' : Ticket.URG_CH},
                               RequestContext(request))
