from django.core.exceptions import ImproperlyConfigured
from rest_framework import relations
from rest_framework import serializers
from rest_framework.compat import NoReverseMatch
from rest_framework.reverse import reverse


# This displays the URL to the child of a Device. Could use some work, but functional for now.
class HyperlinkedDeviceField(serializers.HyperlinkedRelatedField):
    def __init__(self, **kwargs):
        self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
        self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field)
        self.format = kwargs.pop('format', None)
        self.model_view_maps = kwargs.pop('model_view_maps')

        # We include this simply for dependency injection in tests.
        # We can't add it as a class attributes or it would expect an
        # implicit `self` argument to be passed.
        self.reverse = reverse
        super(serializers.HyperlinkedRelatedField, self).__init__(**kwargs)

    def to_representation(self, value):
        view_name = self.model_view_maps[type(value.instance)]
        assert 'request' in self.context, (
            "`%s` requires the request in the serializer"
            " context. Add `context={'request': request}` when instantiating "
            "the serializer." % self.__class__.__name__
        )

        request = self.context['request']
        format = self.context.get('format', None)

        # By default use whatever format is given for the current context
        # unless the target is a different type to the source.
        #
        # Eg. Consider a HyperlinkedIdentityField pointing from a json
        # representation to an html property of that representation...
        #
        # '/snippets/1/' should link to '/snippets/1/highlight/'
        # ...but...
        # '/snippets/1/.json' should link to '/snippets/1/highlight/.html'
        if format and self.format and self.format != format:
            format = self.format

        # Return the hyperlink, or error if incorrectly configured.
        try:
            url = self.get_url(value.instance, view_name, request, format)
        except NoReverseMatch:
            msg = (
                'Could not resolve URL for hyperlinked relationship using '
                'view name "%s". You may have failed to include the related '
                'model in your API, or incorrectly configured the '
                '`lookup_field` attribute on this field.'
            )
            if value in ('', None):
                value_string = {'': 'the empty string', None: 'None'}[value]
                msg += (
                    " WARNING: The value of the field on the model instance "
                    "was %s, which may be why it didn't match any "
                    "entries in your URL conf." % value_string
                )
            raise ImproperlyConfigured(msg % view_name)

        if url is None:
            return None

        return relations.Hyperlink(url, value)

    def to_interal_value(self, data):
        pass

from django.core.exceptions import ImproperlyConfigured
from rest_framework import relations
from rest_framework import serializers
from rest_framework.compat import NoReverseMatch
from rest_framework.reverse import reverse


# This displays the URL to the child of a Device. Could use some work, but functional for now.
class HyperlinkedDeviceField(serializers.HyperlinkedRelatedField):
    def __init__(self, **kwargs):
        self.lookup_field = kwargs.pop('lookup_field', self.lookup_field)
        self.lookup_url_kwarg = kwargs.pop('lookup_url_kwarg', self.lookup_field)
        self.format = kwargs.pop('format', None)
        self.model_view_maps = kwargs.pop('model_view_maps')

        # We include this simply for dependency injection in tests.
        # We can't add it as a class attributes or it would expect an
        # implicit `self` argument to be passed.
        self.reverse = reverse
        super(serializers.HyperlinkedRelatedField, self).__init__(**kwargs)

    def to_representation(self, value):
        view_name = self.model_view_maps[type(value.instance)]
        assert 'request' in self.context, (
            "`%s` requires the request in the serializer"
            " context. Add `context={'request': request}` when instantiating "
            "the serializer." % self.__class__.__name__
        )

        request = self.context['request']
        format = self.context.get('format', None)

        # By default use whatever format is given for the current context
        # unless the target is a different type to the source.
        #
        # Eg. Consider a HyperlinkedIdentityField pointing from a json
        # representation to an html property of that representation...
        #
        # '/snippets/1/' should link to '/snippets/1/highlight/'
        # ...but...
        # '/snippets/1/.json' should link to '/snippets/1/highlight/.html'
        if format and self.format and self.format != format:
            format = self.format

        # Return the hyperlink, or error if incorrectly configured.
        try:
            url = self.get_url(value.instance, view_name, request, format)
        except NoReverseMatch:
            msg = (
                'Could not resolve URL for hyperlinked relationship using '
                'view name "%s". You may have failed to include the related '
                'model in your API, or incorrectly configured the '
                '`lookup_field` attribute on this field.'
            )
            if value in ('', None):
                value_string = {'': 'the empty string', None: 'None'}[value]
                msg += (
                    " WARNING: The value of the field on the model instance "
                    "was %s, which may be why it didn't match any "
                    "entries in your URL conf." % value_string
                )
            raise ImproperlyConfigured(msg % view_name)

        if url is None:
            return None

        return relations.Hyperlink(url, value)

    def to_interal_value(self, data):
        pass

# This displays the URL to the child of a Device. Could use some work, but functional for now. # We include this simply for dependency injection in tests. # We can't add it as a class attributes or it would expect an # implicit `self` argument to be passed. # By default use whatever format is given for the current context # unless the target is a different type to the source. # # Eg. Consider a HyperlinkedIdentityField pointing from a json # representation to an html property of that representation... # # '/snippets/1/' should link to '/snippets/1/highlight/' # ...but... # '/snippets/1/.json' should link to '/snippets/1/highlight/.html' # Return the hyperlink, or error if incorrectly configured.