from __future__ import unicode_literals

from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
from django.utils.translation import ungettext

from acls.models import AccessControlList
from permissions import Permission

__all__ = (
    'DeleteExtraDataMixin', 'ExtraContextMixin',
    'ObjectListPermissionFilterMixin', 'ObjectPermissionCheckMixin',
    'RedirectionMixin', 'ViewPermissionCheckMixin'
)


class DeleteExtraDataMixin(object):
    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        success_url = self.get_success_url()
        if hasattr(self, 'get_delete_extra_data'):
            self.object.delete(**self.get_delete_extra_data())
        else:
            self.object.delete()

        return HttpResponseRedirect(success_url)


class ExtraContextMixin(object):
    extra_context = {}

    def get_extra_context(self):
        return self.extra_context

    def get_context_data(self, **kwargs):
        context = super(ExtraContextMixin, self).get_context_data(**kwargs)
        context.update(self.get_extra_context())
        return context


class MultipleInstanceActionMixin(object):
    model = None
    success_message = 'Operation performed on %(count)d object'
    success_message_plural = 'Operation performed on %(count)d objects'

    def get_pk_list(self):
        return self.request.GET.get(
            'id_list', self.request.POST.get('id_list', '')
        ).split(',')

    def get_queryset(self):
        return self.model.objects.filter(pk__in=self.get_pk_list())

    def get_success_message(self, count):
        return ungettext(
            self.success_message,
            self.success_message_plural,
            count
        ) % {
            'count': count,
        }

    def post(self, request, *args, **kwargs):
        count = 0
        for instance in self.get_queryset():
            try:
                self.object_action(instance=instance)
            except PermissionDenied:
                pass
            else:
                count += 1

        messages.success(
            self.request,
            self.get_success_message(count=count)
        )

        return HttpResponseRedirect(self.get_success_url())


class ObjectListPermissionFilterMixin(object):
    object_permission = None

    def get_queryset(self):
        queryset = super(ObjectListPermissionFilterMixin, self).get_queryset()

        if self.object_permission:
            try:
                # Check to see if the user has the permissions globally
                Permission.check_permissions(
                    self.request.user, (self.object_permission,)
                )
            except PermissionDenied:
                # No global permission, filter ther queryset per object +
                # permission
                return AccessControlList.objects.filter_by_access(
                    self.object_permission, self.request.user, queryset
                )
            else:
                # Has the permission globally, return all results
                return queryset
        else:
            return queryset


class ObjectPermissionCheckMixin(object):
    object_permission = None

    def get_permission_object(self):
        return self.get_object()

    def dispatch(self, request, *args, **kwargs):
        if self.object_permission:
            try:
                Permission.check_permissions(
                    request.user, (self.object_permission,)
                )
            except PermissionDenied:
                AccessControlList.objects.check_access(
                    self.object_permission, request.user,
                    self.get_permission_object()
                )

        return super(
            ObjectPermissionCheckMixin, self
        ).dispatch(request, *args, **kwargs)


class RedirectionMixin(object):
    post_action_redirect = None
    action_cancel_redirect = None

    def get_post_action_redirect(self):
        return self.post_action_redirect

    def get_action_cancel_redirect(self):
        return self.action_cancel_redirect

    def dispatch(self, request, *args, **kwargs):
        post_action_redirect = self.get_post_action_redirect()
        action_cancel_redirect = self.get_action_cancel_redirect()

        self.next_url = self.request.POST.get(
            'next', self.request.GET.get(
                'next', post_action_redirect if post_action_redirect else self.request.META.get(
                    'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
                )
            )
        )
        self.previous_url = self.request.POST.get(
            'previous', self.request.GET.get(
                'previous', action_cancel_redirect if action_cancel_redirect else self.request.META.get(
                    'HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL)
                )
            )
        )

        return super(
            RedirectionMixin, self
        ).dispatch(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super(RedirectionMixin, self).get_context_data(**kwargs)
        context.update(
            {
                'next': self.next_url,
                'previous': self.previous_url
            }
        )

        return context

    def get_success_url(self):
        return self.next_url or self.previous_url


class ViewPermissionCheckMixin(object):
    view_permission = None

    def dispatch(self, request, *args, **kwargs):
        if self.view_permission:
            Permission.check_permissions(
                requester=self.request.user,
                permissions=(self.view_permission,)
            )

        return super(
            ViewPermissionCheckMixin, self
        ).dispatch(request, *args, **kwargs)
