from django.db import models
from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _


class Taxonomy(models.Model):

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=250,
        help_text=_('Taxonomy Name'),
        unique=True,
        db_index=True,
    )
    slug = models.SlugField(
        verbose_name=_('Slug'),
        max_length=250,
        unique=True,  # Should be true already
        db_index=True,  # Should be true by implication
        # https://docs.djangoproject.com/en/1.8/ref/models/fields/#slugfield
    )

    def save(self, *args, **kwargs):
        self.slug = slugify(self.name)
        super(Taxonomy, self).save(*args, **kwargs)

    @property
    def is_optional(self):
        return self.multiplicity == 'optional'

    def __unicode__(self):
        return self.name

    # To do Categories, you use 'optional' and 'closed',
    # to do free tagging use 'multiple' and 'open'
    multiplicity = models.CharField(
        choices=(
            ('optional', _('Zero or One')),
            ('multiple', _('Zero or More')),
        ),
        default='optional',
        max_length=30,
    )

    vocabulary = models.CharField(
        choices=(
            ('fixed', _('Not modifiable by any user, system only')),
            ('closed', _('Only admin users who have permission to define and edit taxonomies')),
            ('open', _('Any user who has permission to use taxonomies')),
        ),
        default='closed',
        max_length=30,
    )

    @property
    def is_open(self):
        return self.vocabulary == 'open'


class TermManager(models.Manager):

    def by_taxonomy(self, taxonomy, name):
        """ Fetch a Term by its name and its
        Taxonomy slug which, together should be unique together.

        args:
            taxonomy: [Taxonomy|string]
                Taxonomy instance or taxonomy slug.

            name: string: the name of an existing term

        returns:
            The term object with the given name in the given Taxonomy.

        throws:
            DoesNotExist if Taxonomy with the given slug does not exist
            DoesNotExist if named Term does not exist, unless the Taxonomy
            vocabulary is open - in this case the Term will be created
            ValueError if taxonomy is not one of the allowed types
        """
        if isinstance(taxonomy, basestring):
            taxonomy = Taxonomy.objects.get(slug=taxonomy)
        elif not isinstance(taxonomy, Taxonomy):
            raise ValueError(
                "taxonomy must be a Taxonomy instance "
                "or a valid taxonomy slug")

        if taxonomy.is_open:
            term, _ = self.select_related('taxonomy').get_or_create(
                taxonomy=taxonomy,
                name=name
            )
        else:
            term = self.select_related('taxonomy').get(
                taxonomy=taxonomy,
                name=name
            )

        return term


class Term(models.Model):

    name = models.CharField(
        verbose_name=_('Name'),
        max_length=250,
        help_text=_('Tag or Category Name'),
        db_index=True,
    )

    taxonomy = models.ForeignKey(
        Taxonomy,
        verbose_name=_('Taxonomy'),
        related_name="%(app_label)s_%(class)s_term"
    )

    long_name = models.TextField(
        verbose_name=_('Long Name'),
        blank=True,
    )

    def __unicode__(self):
        return "{}:{}".format(
            self.taxonomy.name,
            self.name
        )

    # Custom Manager
    objects = TermManager()

    class Meta:
        unique_together = ('name', 'taxonomy')
        index_together = ['name', 'taxonomy']