from django.db.models import CharField

from django.utils.encoding import force_unicode

from django.template.defaultfilters import slugify

def _get_field(instance, name):
    try:
        return getattr(instance, name)
    except AttributeError:
        raise ValueError("Model %s has no field '%s'" % \
                             (instance.__class__.__name__, name))

class AutoSlugField(CharField):
    """ A SlugField that automatically populate itself using the value of another
    field.

    In addition to CharField's usual parameters you can specify:

    populate_from (mandatory): the name of the field to be used for the slug
                               creation. ValueError will be raised at the
                               object save() time if the field does not exist.

    slugify_func: the function to apply on the value of the field.
                  If unspecified django.template.defaultfilters.slugify will be
                  used.

    append_field: the name of a field that will be appended to the slug, or
                  None. ValueError will be raised at the object save() time if
                  the field does not exist.

    prepend_field: the name of a field that will be prepended to the slug, or
                   None. ValueError will be raised at the object save() time if
                   the field does not exist.

    field_separator: the separator between the slug and the {pre, ap}pended
                     fields. The default value is u'-'.

    Unless explicitly set otherwise, the field will be created with the
    'editable' and 'db_index' parameters set respectively to False and
    True. """
    
    def __init__(self, *args, **kwargs):
        # Set editable=False if not explicitly set
        if 'editable' not in kwargs:
            kwargs['editable'] = False
            
        # Set db_index=True if not explicitly set
        if 'db_index' not in kwargs:
            kwargs['db_index'] = True

        populate_from = kwargs.pop('populate_from', None)
        slugify_func = kwargs.pop('slugify_func', slugify)
        append_field = kwargs.pop('append_field', None)
        prepend_field = kwargs.pop('prepend_field', None)
        field_separator = kwargs.pop('field_separator', u'-')
            
        if populate_from is None:
            raise ValueError("missing 'populate_from' argument")
        else:
            self._populate_from = populate_from
        
        self._slugify_func = slugify_func

        self._prepend_field = prepend_field
        self._append_field = append_field
        self._field_separator = field_separator

        super(AutoSlugField, self).__init__(*args, **kwargs)
        
    def pre_save(self, model_instance, add):
        populate_from = _get_field(model_instance, self._populate_from)
        
        make_slug = self._slugify_func

        chunks = list()

        if self._prepend_field is not None:
            prepend_field = _get_field(model_instance, self._prepend_field)
            # Prepend the field's value only if it is not empty
            if prepend_field:
                chunks.append(force_unicode(prepend_field))
        
        chunks.append(make_slug(populate_from))
                
        if self._append_field is not None:
            append_field = _get_field(model_instance, self._append_field)
            # Append the field's value only if it is not empty
            if append_field:
                chunks.append(force_unicode(append_field))

        value = self._field_separator.join(chunks)
        
        setattr(model_instance, self.attname, value)

        return value

    def get_internal_type(self):
        return 'SlugField'