import re
from django.core.exceptions import ValidationError

try:
    from collections import OrderedDict
except ImportError:  # Py2.6, fall back to Django's implementation
    from django.utils.datastructures import SortedDict as OrderedDict

try:
    from django.utils import six
except ImportError:
    import six

__all__ = ["ChoiceItem", "DjangoChoices", "C"]

### Support Functionality (Not part of public API ###

class Labels(dict):
    def __getattribute__(self, name):
        result = dict.get(self, name, None)
        if result is not None:
            return result
        else:
            raise AttributeError("Label for field %s was not found." % name)
    def __setattr__(self, name, value):
        self[name] = value

### End Support Functionality ###

class ChoiceItem(object):
    """
    Describes a choice item.  The label is usually the field name so label can
    normally be left blank.  Set a label if you need characters that are illegal
    in a python identifier name (ie: "DVD/Movie"). 
    """
    order = 0
    def __init__(self, value=None, label=None, order=None):
        self.value = value
        if order:
            self.order = order
        else:
            ChoiceItem.order += 1
            self.order = ChoiceItem.order 
        self.label = label

# Shorter convenience alias.
C = ChoiceItem
        
class DjangoChoicesMeta(type):
    """
    Metaclass that writes the choices class.
    """
    name_clean = re.compile(r"_+")
    def __new__(cls, name, bases, attrs):
        class StaticProp(object):
            def __init__(self, value):
                self.value = value
            def __get__(self, obj, objtype):
                return self.value
                
        fields = {}
        labels = Labels()
        values = {}
        choices = []
        
        # Get all the fields from parent classes. 
        parents = [b for b in bases if isinstance(b, DjangoChoicesMeta)]
        for kls in parents:
            for field_name in kls._fields:
                fields[field_name] = kls._fields[field_name] 

        # Get all the fields from this class.
        for field_name in attrs:
            val = attrs[field_name]
            if isinstance(val, ChoiceItem):
                fields[field_name] = val 
                
        fields = OrderedDict(sorted(fields.items(), key=lambda x: x[1].order))
        
        for field_name in fields:
            val = fields[field_name]
            if isinstance(val, ChoiceItem):
                if not val.label is None:
                    label = val.label
                else:
                    label = cls.name_clean.sub(" ", field_name)
                
                val0 = label if val.value is None else val.value
                choices.append((val0, label))
                attrs[field_name] = StaticProp(val0)
                setattr(labels, field_name, label)
                values[val.value or label] = label
            else:
                choices.append((field_name, val.choices))

        attrs["choices"] = StaticProp(tuple(choices))
        attrs["labels"] = labels
        attrs["values"] = values
        attrs["_fields"] = fields

        return super(DjangoChoicesMeta, cls).__new__(cls, name, bases, attrs)

class DjangoChoices(six.with_metaclass(DjangoChoicesMeta)):
    order = 0
    choices = ()
    labels = Labels()
    values = {}

    @classmethod
    def validator(cls, value):
        if value not in cls.values:
            raise ValidationError('Select a valid choice. %(value)s is not '
                                  'one of the available choices.')


@@ -1012,18 +1012,17 @@
 Movie%22).
- 
 %0A
+
     %22%22%22%0A
@@ -1260,17 +1260,16 @@
 em.order
- 
 %0A       
@@ -1333,25 +1333,17 @@
 iceItem%0A
-        
 %0A
+
 class Dj
@@ -1690,33 +1690,17 @@
 f.value%0A
-                
 %0A
+
         
@@ -1778,24 +1778,16 @@
 es = %5B%5D%0A
-        
 %0A       
@@ -1828,17 +1828,16 @@
 classes.
- 
 %0A       
@@ -2033,17 +2033,16 @@
 ld_name%5D
- 
 %0A%0A      
@@ -2234,34 +2234,17 @@
 e%5D = val
- %0A                
+%0A
 %0A       
@@ -2315,25 +2315,17 @@
 order))%0A
-        
 %0A
+
         
@@ -2601,25 +2601,9 @@
 me)%0A
-                
 %0A
+
     
@@ -2843,23 +2843,9 @@
 %5Bval
-.value or label
+0
 %5D = 

Fix zero value