import json
from functools import update_wrapper

from django.contrib import admin
from django.conf.urls import patterns, url
from django.conf import settings
try:
    from django.contrib.contenttypes.generic import GenericForeignKey,  GenericTabularInline, GenericStackedInline
except ImportError:
    from django.contrib.contenttypes.admin import GenericStackedInline, GenericTabularInline
    from django.contrib.contenttypes.fields import GenericForeignKey

from django.contrib.contenttypes.models import ContentType
try:
    from django.utils.encoding import force_text 
except ImportError:
    from django.utils.encoding import force_unicode as force_text
from django.utils.text import capfirst
from django.contrib.admin.widgets import url_params_from_lookup_dict
from django.http import HttpResponse, HttpResponseNotAllowed, Http404
try:
    from django.contrib.admin.views.main import IS_POPUP_VAR
except ImportError:
    from django.contrib.admin.options import IS_POPUP_VAR
from  django.core.exceptions import ObjectDoesNotExist

JS_PATH = getattr(settings, 'GENERICADMIN_JS', 'genericadmin/js/') 

class BaseGenericModelAdmin(object):
    class Media:
        js = ()

    content_type_lookups = {}
    generic_fk_fields = []
    content_type_blacklist = []
    content_type_whitelist = []
    
    def __init__(self, model, admin_site):
        try:
            media = list(self.Media.js)
        except:
            media = []
        media.append(JS_PATH + 'genericadmin.js')
        self.Media.js = tuple(media)
        
        self.content_type_whitelist = [s.lower() for s in self.content_type_whitelist]
        self.content_type_blacklist = [s.lower() for s in self.content_type_blacklist]        
            
        super(BaseGenericModelAdmin, self).__init__(model, admin_site)

    def get_generic_field_list(self, request, prefix=''):
        if hasattr(self, 'ct_field') and hasattr(self, 'ct_fk_field'):
            exclude = [self.ct_field, self.ct_fk_field]
        else:
            exclude = []
        
        field_list = []
        if hasattr(self, 'generic_fk_fields') and self.generic_fk_fields:
            for fields in self.generic_fk_fields:
                if fields['ct_field'] not in exclude and \
                        fields['fk_field'] not in exclude:
                    fields['inline'] = prefix != ''
                    fields['prefix'] = prefix
                    field_list.append(fields)
        else:    
            for field in self.model._meta.virtual_fields:
                if isinstance(field, GenericForeignKey) and \
                        field.ct_field not in exclude and field.fk_field not in exclude:
                    field_list.append({
                        'ct_field': field.ct_field, 
                        'fk_field': field.fk_field,
                        'inline': prefix != '',
                        'prefix': prefix,
                    })
                    
        if hasattr(self, 'inlines') and len(self.inlines) > 0:
            for FormSet, inline in zip(self.get_formsets(request), self.get_inline_instances(request)):
                if hasattr(inline, 'get_generic_field_list'):
                    prefix = FormSet.get_default_prefix()
                    field_list = field_list + inline.get_generic_field_list(request, prefix)

        return field_list

    def get_urls(self):
        def wrap(view):
            def wrapper(*args, **kwargs):
                return self.admin_site.admin_view(view)(*args, **kwargs)
            return update_wrapper(wrapper, view)
        
        custom_urls = patterns('',
            url(r'^obj-data/$', wrap(self.generic_lookup), name='admin_genericadmin_obj_lookup'),
            url(r'^genericadmin-init/$', wrap(self.genericadmin_js_init), name='admin_genericadmin_init'),
        )
        return custom_urls + super(BaseGenericModelAdmin, self).get_urls()
            
    def genericadmin_js_init(self, request):
        if request.method == 'GET':
            obj_dict = {}
            for c in ContentType.objects.all():
                val = force_text('%s/%s' % (c.app_label, c.model))
                params = self.content_type_lookups.get('%s.%s' % (c.app_label, c.model), {})
                params = url_params_from_lookup_dict(params)
                if self.content_type_whitelist:
                    if val in self.content_type_whitelist:
                        obj_dict[c.id] = (val, params)
                elif val not in self.content_type_blacklist:
                    obj_dict[c.id] = (val, params)
        
            data = {
                'url_array': obj_dict,
                'fields': self.get_generic_field_list(request),
                'popup_var': IS_POPUP_VAR,
            }
            resp = json.dumps(data, ensure_ascii=False)
            return HttpResponse(resp, content_type='application/json')
        return HttpResponseNotAllowed(['GET'])
    
    def generic_lookup(self, request):
        if request.method != 'GET':
            return HttpResponseNotAllowed(['GET'])
        
        if 'content_type' in request.GET and 'object_id' in request.GET:
            content_type_id = request.GET['content_type']
            object_id = request.GET['object_id']
            
            obj_dict = {
                'content_type_id': content_type_id,
                'object_id': object_id,
            }

            content_type = ContentType.objects.get(pk=content_type_id)
            obj_dict["content_type_text"] = capfirst(force_text(content_type))

            try:
                obj = content_type.get_object_for_this_type(pk=object_id)
                obj_dict["object_text"] = capfirst(force_text(obj))
            except ObjectDoesNotExist:
                raise Http404
            
            resp = json.dumps(obj_dict, ensure_ascii=False)
        else:
            resp = ''
        return HttpResponse(resp, content_type='application/json')
        


class GenericAdminModelAdmin(BaseGenericModelAdmin, admin.ModelAdmin):
    """Model admin for generic relations. """


class GenericTabularInline(BaseGenericModelAdmin, GenericTabularInline):
    """Model admin for generic tabular inlines. """ 


class GenericStackedInline(BaseGenericModelAdmin, GenericStackedInline):
    """Model admin for generic stacked inlines. """


class TabularInlineWithGeneric(BaseGenericModelAdmin, admin.TabularInline):
    """"Normal tabular inline with a generic relation"""


class StackedInlineWithGeneric(BaseGenericModelAdmin, admin.StackedInline):
    """"Normal stacked inline with a generic relation"""

@@ -108,18 +108,8 @@
 port
- patterns,
  url
@@ -3591,20 +3591,9 @@
 s = 
-patterns('',
+%5B
 %0A   
@@ -3802,17 +3802,17 @@
         
-)
+%5D
 %0A       

Remove deprecated `django.conf.urls.patters`