from abc import abstractmethod

SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')


class BasePermission:
    """
    A base class from which all permission classes should inherit.
    """

    @abstractmethod
    def has_permission(self, request, *args, **kwargs):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True


class AND(BasePermission):
    def __init__(self, *ops):
        self.ops = ops

    def has_permission(self, request, *args, **kwargs):
        tmp = True
        for op in self.ops:
            tmp = tmp and op().has_permission(request, *args, **kwargs)
        ret = tmp
        return ret


class OR(BasePermission):
    def __init__(self, *ops):
        self.ops = ops

    def has_permission(self, request, *args, **kwargs):
        tmp = False
        for op in self.ops:
            tmp = tmp or op().has_permission(request, *args, **kwargs)
        ret = tmp
        return ret


class NOT(BasePermission):
    def __init__(self, op):
        self.op = op

    def has_permission(self, request, *args, **kwargs):
        return not self.op().has_permission(request, *args, **kwargs)


class AllowAny(BasePermission):
    """
    Allow any access.
    This isn't strictly required, since you could use an empty
    permission_classes list, but it's useful because it makes the intention
    more explicit.
    """

    def has_permission(self, request, *args, **kwargs):
        return True


class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, *args, **kwargs):
        return bool(request.user and request.user.is_authenticated)


class IsAdminUser(BasePermission):
    """
    Allows access only to admin users.
    """

    def has_permission(self, request, *args, **kwargs):
        return bool(request.user and request.user.is_staff)


class IsAuthenticatedOrReadOnly(BasePermission):
    """
    The request is authenticated as a user, or is a read-only request.
    """

    def has_permission(self, request, *args, **kwargs):
        return bool(
            request.method in SAFE_METHODS or
            request.user and
            request.user.is_authenticated
        )
