from django.conf import settings
from django.contrib import messages
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import ImproperlyConfigured
from django import http
from django.utils.translation import ugettext as _
from django.utils.http import urlquote


class LoginRequiredMixin(object):
    """
    View mixin which verifies that the user has authenticated.

    NOTE:
        This should be the left-most mixin of a view.
    """
    login_url = settings.LOGIN_URL
    raise_exception = False
    redirect_field_name = REDIRECT_FIELD_NAME

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated():
            return super(LoginRequiredMixin, self).dispatch(request, *args,
                                                            **kwargs)
        elif self.raise_exception:  # if an exception was desired
            return http.HttpResponseForbidden()  # return a forbidden response.
        else:
            messages.error(request, _("You need to be logged in"))
            path = urlquote(request.get_full_path())
            return http.HttpResponseRedirect(
                "%s?%s=%s" % (self.login_url, self.redirect_field_name, path))


class PermissionRequiredMixin(object):
    """
    View mixin which verifies that the loggedin user has the specified
    permission.

    Class Settings
    `permission_required` - the permission to check for.
    `login_url` - the login url of site
    `redirect_field_name` - defaults to "next"
    `raise_exception` - defaults to False - raise 403 if set to True

    Example Usage

        class SomeView(PermissionRequiredMixin, ListView):
            ...
            # required
            permission_required = "app.permission"

            # optional
            login_url = "/signup/"
            redirect_field_name = "hollaback"
            raise_exception = True
            ...
    """
    login_url = settings.LOGIN_URL
    permission_required = None
    permission_failed_message = _("You don't have the permission to do this")
    raise_exception = False
    redirect_field_name = REDIRECT_FIELD_NAME

    def dispatch(self, request, *args, **kwargs):
        # Verify class settings
        if self.permission_required is None or len(
                self.permission_required.split(".")) != 2:
            raise ImproperlyConfigured(
                "'PermissionRequiredMixin' requires 'permission_required' attribute to be set.")
        has_permission = request.user.has_perm(self.permission_required)

        if has_permission:
            return super(PermissionRequiredMixin, self).dispatch(request, *args,
                                                                 **kwargs)
        elif self.raise_exception:
            return http.HttpResponseForbidden()
        else:
            messages.warning(request, self.permission_failed_message)
            path = urlquote(request.get_full_path())
            return http.HttpResponseRedirect(
                "%s?%s=%s" % (self.login_url, self.redirect_field_name, path))


class SuperuserRequiredMixin(object):
    """
    Mixin allows you to require a user with `is_superuser` set to True.
    """
    login_url = settings.LOGIN_URL  # LOGIN_URL from project settings
    raise_exception = False  # Default whether to raise an exception to none
    redirect_field_name = REDIRECT_FIELD_NAME  # Set by django.contrib.auth

    def dispatch(self, request, *args, **kwargs):
        if request.user.is_superuser:  # If the user is a standard user,
            return super(SuperuserRequiredMixin, self).dispatch(request, *args,
                                                                **kwargs)
        elif self.raise_exception:  # *and* if an exception was desired
            return http.HttpResponseForbidden()  # return a forbidden response.
        else:
            messages.error(request,
                           _("You don't have the permissions for this"))
            path = urlquote(request.get_full_path())
            return http.HttpResponseRedirect(
                "%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
