"""
Drop in replacements for DRF's fields. Use as follows:

    from rest_framework_serializer_field_permissions import fields

    class PersonSerializer(FieldPermissionSerializerMixin, serializers.ModelSerializer):

        family_names = fields.CharField(permission_classes=(IsAuthenticated(), ))
        given_names = fields.CharField(permission_classes=(IsAuthenticated(), ))
        nick_name = fields.CharField(permission_classes=(AllowAny(), ))
"""
import copy
import inspect
from rest_framework import fields
from rest_framework.serializers import LIST_SERIALIZER_KWARGS, ListSerializer


class PermissionMixin(object):
    """
    Mixin for DRF's field objects, to make them permission capable.
    """
    def __init__(self, *args, **kwargs):
        permission_classes = kwargs.pop("permission_classes", ())

        super(PermissionMixin, self).__init__(*args, **kwargs)
        self.permission_classes = permission_classes

    def check_permission(self, request):
        """
        Check this field's permissions to determine whether or not it may be
        shown.
        """
        return all((permission.has_permission(request) for permission in self.permission_classes))


# TODO: docstring
# pylint: disable=missing-docstring
class SerializerPermissionMixin(PermissionMixin):

    # TODO: diagnost/address abstract-method issue
    # pylint: disable=abstract-method
    class PermissionListSerializer(ListSerializer):

        def __init__(self, *args, **kwargs):
            self.child = kwargs.pop('child', copy.deepcopy(self.child))

            self.permission_classes = self.child.permission_classes
            self.check_permission = self.child.check_permission

            self.allow_empty = kwargs.pop('allow_empty', True)

            assert self.child is not None, '`child` is a required argument.'
            assert not inspect.isclass(self.child), '`child` has not been instantiated.'

            # TODO: diagnose/address bad-super-call issue
            # pylint: disable=bad-super-call
            super(ListSerializer, self).__init__(*args, **kwargs)

            self.child.bind(field_name='', parent=self)

    @classmethod
    def many_init(cls, *args, **kwargs):

        child_serializer = cls(*args, **kwargs)
        list_kwargs = {'child': child_serializer}
        list_kwargs.update(dict([
            (key, value) for key, value in kwargs.items()
            if key in LIST_SERIALIZER_KWARGS
        ]))
        return SerializerPermissionMixin.PermissionListSerializer(*args, **list_kwargs)


# pylint: disable=missing-docstring
class BooleanField(PermissionMixin, fields.BooleanField):
    pass


# pylint: disable=missing-docstring
class NullBooleanField(PermissionMixin, fields.NullBooleanField):
    pass


# pylint: disable=missing-docstring
class CharField(PermissionMixin, fields.CharField):
    pass


# pylint: disable=missing-docstring
class EmailField(PermissionMixin, fields.EmailField):
    pass


# pylint: disable=missing-docstring
class RegexField(PermissionMixin, fields.RegexField):
    pass


# pylint: disable=missing-docstring
class SlugField(PermissionMixin, fields.SlugField):
    pass


# pylint: disable=missing-docstring
class URLField(PermissionMixin, fields.URLField):
    pass


# pylint: disable=missing-docstring
class IntegerField(PermissionMixin, fields.IntegerField):
    pass


# pylint: disable=missing-docstring
class FloatField(PermissionMixin, fields.FloatField):
    pass


# pylint: disable=missing-docstring
class DecimalField(PermissionMixin, fields.DecimalField):
    pass


# pylint: disable=missing-docstring
class DateField(PermissionMixin, fields.DateField):
    pass


# pylint: disable=missing-docstring
class DateTimeField(PermissionMixin, fields.DateTimeField):
    pass


# pylint: disable=missing-docstring
class TimeField(PermissionMixin, fields.TimeField):
    pass


# pylint: disable=missing-docstring
class ChoiceField(PermissionMixin, fields.ChoiceField):
    pass


# pylint: disable=missing-docstring
class MultipleChoiceField(PermissionMixin, fields.MultipleChoiceField):
    pass


# pylint: disable=missing-docstring
class FileField(PermissionMixin, fields.FileField):
    pass


# pylint: disable=missing-docstring
class ImageField(PermissionMixin, fields.ImageField):
    pass


# pylint: disable=missing-docstring
class ListField(PermissionMixin, fields.ListField):
    pass


# pylint: disable=missing-docstring
# pylint: disable=abstract-method
class ReadOnlyField(PermissionMixin, fields.ReadOnlyField):
    pass


# pylint: disable=missing-docstring
# pylint: disable=abstract-method
class HiddenField(PermissionMixin, fields.HiddenField):
    pass


# pylint: disable=missing-docstring
class ModelField(PermissionMixin, fields.ModelField):
    pass


# pylint: disable=missing-docstring
# pylint: disable=abstract-method
class SerializerMethodField(PermissionMixin, fields.SerializerMethodField):
    pass
