from django.utils.safestring import mark_safe
from django.utils.html import escape
from django.core import urlresolvers


class ReadonlyLinksMixin(object):
    @staticmethod
    def _make_link_widget(field_name, admin_view):
        def link_widget(instance):
            field = getattr(instance, field_name)
            if field is None:
                return "None"
            link = urlresolvers.reverse(admin_view, args=(field.id,))
            return mark_safe('<a href="%s">%s</a>' % (link, escape(unicode(field))))
        return link_widget

    def get_readonly_fields(self, request, obj=None):
        # get_readonly_fields gets called multiple times and they MUST return EXACTLY the same
        # fields because if not Django will break later on when doing some sneaky "let's subtract these fields
        # to those fields to see if there's a difference and if I'm missing something"
        # Exactly the same fields means, for the callables, that they must be defined only once.
        # We thus use some caching/memoization.
        try:
            return self._link_readonly_fields
        except AttributeError:
            pass

        initial_readonly_fields = super(ReadonlyLinksMixin, self).get_readonly_fields(request, obj)
        if not initial_readonly_fields:
            initial_readonly_fields = []
        link_readonly_fields = []

        if hasattr(self, 'readonly_fields_links'):
            for field_name in self.readonly_fields_links:
                try:
                    field = getattr(obj, field_name)
                    app_label = field._meta.app_label
                    model_name = field._meta.model_name
                except AttributeError:
                    # probably a native type and not a django model,
                    # let's set it as a normal readonly_field
                    link_readonly_fields.append(field_name)
                    continue

                admin_view = 'admin:%s_%s_change' % (app_label, model_name)
                link_widget = self._make_link_widget(field_name, admin_view)
                link_widget.short_description = obj._meta.get_field(field_name).verbose_name
                link_readonly_fields.append(link_widget)

                if self.exclude is None:
                    self.exclude = [field_name]
                elif field_name not in self.exclude:
                    self.exclude = list(self.exclude) + [field_name]

        link_readonly_fields.extend(initial_readonly_fields)
        self._link_readonly_fields = link_readonly_fields
        return link_readonly_fields