"""Base classes and mixins for new class-based generic views."""


class CheckRequestMethodViewMixin(object):
    """Generic view mixin to check the HTTP method before dispatching.

    In a normal class-based view, it's up to the
    :py:meth:`~django.views.generic.base.View.dispatch` method to ensure that
    an HTTP method is valid before dispatching to the handler. However, more
    complex views may need to perform other checks before dispatching, meaning
    that logic is being performed before the validity checks happen, which
    would be unnecessary and wasteful.

    This mixin, when put before any other mixins or parent classes, will
    perform the validity checks up-front and immediately bail with a
    :http:`405` if the HTTP method is not allowed.
    """

    def dispatch(self, request, *args, **kwargs):
        """Dispatch a HTTP request to the right handler.

        This will first check if the HTTP method is allowed. If it is not,
        then this will immediately return a :http:`405`.

        Args:
            *args (tuple):
                Positional arguments to pass to the handler.

            **kwargs (dict):
                Keyword arguments to pass to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response to send to the client.
        """
        norm_method = request.method.lower()

        if (norm_method not in self.http_method_names or
            not hasattr(self, norm_method)):
            # The HTTP method is not allowed. We can bail early.
            return self.http_method_not_allowed(request, *args, **kwargs)

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


class PrePostDispatchViewMixin(object):
    """Generic view mixin to call methods before/after dispatching the handler.

    This is useful for more complex generic views that take advantage of
    mixins that augment the :py:meth:`~django.views.generic.base.View.dispatch`
    method. It allows views to perform additional actions both before and
    after the HTTP handler is called.

    This mixin should be placed after any mixins that add decorators to
    :py:meth:`~django.views.generic.base.View.dispatch` and before any
    mixins/classes that inherit from :py:meth:`~django.views.generic.base.View`
    or provide an implementation of
    :py:meth:`~django.views.generic.base.View.dispatch`.

    Views should generally not have more than one version of this mixin
    applied.
    """

    def dispatch(self, *args, **kwargs):
        """Dispatch a HTTP request to the right handler.

        This will first call :py:meth:`pre_dispatch`, returning the response if
        provided by that method. It will then dispatch as normal, and then
        call :py:meth:`post_dispatch`.

        Args:
            *args (tuple):
                Positional arguments to pass to the handler.

            **kwargs (dict):
                Keyword arguments to pass to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response to send to the client.
        """
        response = self.pre_dispatch(*args, **kwargs)

        if response is not None:
            return response

        response = \
            super(PrePostDispatchViewMixin, self).dispatch(*args, **kwargs)

        return self.post_dispatch(response, *args, **kwargs)

    def pre_dispatch(self, *args, **kwargs):
        """Perform actions before dispatching to the HTTP method handler.

        This can generate state before calling the appropriate HTTP method
        handler. It can optionally return a HTTP response, which will be
        returned directly to the client.

        Subclasses don't need to call the parent method, but can.

        Args:
            *args (tuple):
                Positional arguments being passed to the handler.

            **kwargs (dict):
                Keyword arguments being passed to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response to immediately send to the client. This
            is optional. Subclasses can return ``None`` or no value at all to
            allow the standard HTTP handler to run.
        """
        return None

    def post_dispatch(self, response, *args, **kwargs):
        """Perform actions after dispatching to the HTTP method handler.

        The handler's response is provided, allowing subclasses to alter the
        response. It must then return a response (either the existing one or a
        new one) to send to the client.

        Subclasses don't need to call the parent method, but can.

        Args:
            response (django.http.HttpResponse):
                The HTTP response generated by the handler.

            *args (tuple):
                Positional arguments that were passed to the handler.

            **kwargs (dict):
                Keyword arguments that were passed to the handler.

        Returns:
            django.http.HttpResponse:
            The resulting HTTP response to send to the client.
        """
        return response
