from threading import local

from django import forms
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _

from plata.discount import models
from plata.utils import jsonize


# Internal state tracking helper for config fields
_discount_admin_state = local()


class DiscountAdminForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(DiscountAdminForm, self).__init__(*args, **kwargs)

        # Seems to be necessary because of the custom validation
        self.fields['config'].required = False

        choices = [(key, cfg.get('title', key)) for key, cfg
            in self._meta.model.CONFIG_OPTIONS]

        self.fields['config_options'] = forms.MultipleChoiceField(
            choices=choices,
            label=_('Configuration options'),
            help_text=_('Save and continue editing to configure options.'),
            )

        _discount_admin_state._plata_discount_config_fieldsets = []

        # Determine the list of selected configuration options
        # 1. POST data
        # 2. get data from the instance we are editing
        # 3. fall back to allowing all products in the discount

        try:
            selected = self.data.getlist('config_options')
        except AttributeError:
            if self.instance.pk:
                selected = self.instance.config.keys()
            else:
                selected = None

        selected = selected or ('all',)
        self.fields['config_options'].initial = selected

        for s in selected:
            cfg = dict(self._meta.model.CONFIG_OPTIONS)[s]

            # Always create a fieldset for selected configuration options,
            # even if we do not have any form fields.
            fieldset = [
                _('Discount configuration: %s') % cfg.get('title', s),
                {'fields': []},
                ]

            for k, f in cfg.get('form_fields', []):
                self.fields['%s_%s' % (s, k)] = f

                # Set initial value if we have one in the configuration
                if k in self.instance.config.get(s, {}):
                    f.initial = self.instance.config[s].get(k)

                fieldset[1]['fields'].append('%s_%s' % (s, k))

            _discount_admin_state._plata_discount_config_fieldsets.append(
                fieldset)

    def clean(self):
        data = self.cleaned_data

        if 'config' in self.changed_data:
            return data

        selected = data.get('config_options', [])
        config_options = {}

        for s in selected:
            cfg = dict(self._meta.model.CONFIG_OPTIONS)[s]

            option_item = {}
            for k, f in cfg.get('form_fields', []):
                key = '%s_%s' % (s, k)
                if key in data:
                    option_item[k] = data.get(key)

            config_options[s] = option_item

        self.instance.config = jsonize(config_options)
        data['config'] = self.instance.config
        return data


class DiscountAdmin(admin.ModelAdmin):
    form = DiscountAdminForm
    list_display = ('name', 'type', 'is_active', 'valid_from',
        'valid_until', 'code', 'value')
    list_filter = ('type', 'is_active')
    ordering = ('-valid_from',)
    search_fields = ('name', 'code', 'config')

    def get_fieldsets(self, request, obj=None):
        fieldsets = super(DiscountAdmin, self).get_fieldsets(request, obj)
        fieldsets[0][1]['fields'].remove('config')

        fieldsets.append((_('Raw configuration'), {
            'fields': ('config',),
            'classes': ('collapse',),
            }))
        fieldsets.append((_('Configuration'), {
            'fields': ('config_options',),
            }))

        fieldsets.extend(
            _discount_admin_state._plata_discount_config_fieldsets)
        del _discount_admin_state._plata_discount_config_fieldsets

        return fieldsets

admin.site.register(models.Discount, DiscountAdmin)

@@ -1,33 +1,4 @@
-from threading import local%0A%0A
 from
@@ -18,16 +18,16 @@
 t forms%0A
+
 from dja
@@ -180,93 +180,8 @@
 e%0A%0A%0A
-# Internal state tracking helper for config fields%0A_discount_admin_state = local()%0A%0A%0A
 clas
@@ -793,46 +793,8 @@
     
-_discount_admin_state._plata_discount_
 conf
@@ -2093,37 +2093,71 @@
         
-_discount_admin_state
+config_fieldsets.append(fieldset)%0A%0A        self.request
 ._plata_
@@ -2185,41 +2185,26 @@
 sets
-.append(%0A                
+ = config_
 fieldset
 )%0A%0A 
@@ -2195,25 +2195,25 @@
 fig_fieldset
-)
+s
 %0A%0A    def cl
@@ -3149,24 +3149,364 @@
  'config')%0A%0A
+    def get_form(self, request, obj=None, **kwargs):%0A        form_class = super(DiscountAdmin, self).get_form(%0A            request, obj=obj, **kwargs)%0A        # Generate a new type to be sure that the request stays inside this%0A        # request/response cycle.%0A        return type(form_class.__name__, (form_class,), %7B'request': request%7D)%0A%0A
     def get_
@@ -3616,16 +3616,115 @@
 t, obj)%0A
+        if not hasattr(request, '_plata_discount_config_fieldsets'):%0A            return fieldsets%0A%0A
         
@@ -4058,97 +4058,15 @@
     
-_discount_admin_state._plata_discount_config_fieldsets)%0A        del _discount_admin_state
+request
 ._pl
@@ -4086,32 +4086,33 @@
 config_fieldsets
+)
 %0A%0A        return

Implement the config fieldsets in the discount administration without thread locals