class ProductCategory(models.Model):

    # ------------------------------------------------------------------------
    # Fields
    # ------------------------------------------------------------------------
    name = models.CharField(
        max_length=32,
        primary_key=True,
        help_text='The name of this category.'
    )

    description = models.CharField(
        max_length=1024,
        help_text='A description of what this product category is used for.'
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.name)

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Category'
        verbose_name_plural = 'Categories' class Product(models.Model):

    # ------------------------------------------------------------------------
    # Fields:
    # ------------------------------------------------------------------------
    ptask = models.ForeignKey(
        PTask,
        db_index=True,
        help_text='The ptask that owns this product.',
        related_name='products',
    )

    name = models.CharField(
        max_length=256,
        db_index=True,
        help_text='The name of this product.'
    )

    category = models.ForeignKey(
        ProductCategory,
        db_index=True,
        help_text="The product's category.",

    )

    description = models.CharField(
        max_length=1024,
        help_text='A description of this product.'
    )

    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this product.',
        blank=True,
        editable = False,
    )

    official_version_number = models.IntegerField(
        help_text="The official version number of this product",
        default=0,
    )

    creator = models.ForeignKey(
        User,
        help_text='The user who created this product.',
    )

    created = models.DateTimeField(
        auto_now_add=True,
        help_text='Date the product was created.',
    )
    
    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Product'
        verbose_name_plural = 'Products'
        index_together = [['ptask', 'name', 'category'],]
        unique_together = (('ptask', 'name', 'category'),)

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""

        # populate the spec field
        self.spec = SPEC_SEPARATOR.join([
            self.ptask.spec,
            "products",
            self.name,
            self.category.name ,
        ])

        super(Product, self).save() class ProductVersion(models.Model):

    # ------------------------------------------------------------------------
    # Fields:
    # ------------------------------------------------------------------------
    ptask_version = models.ForeignKey(
        PTaskVersion,
        db_index=True,
        help_text='The ptask version associated with his product version.',
    )

    product = models.ForeignKey(
        Product,
        db_index=True,
        help_text='The product this version is associated with.',
        related_name='versions',
    )

    release_note = models.CharField(
        max_length=1024,
        help_text='A note regarding this version of the product.'
    )

    number = models.IntegerField(
        help_text="The version number of this product version.",
        blank=True,
        null=True,
        editable=False,
    )

    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this version.',
        blank=True,
        editable = False,
    )

    published = models.BooleanField(
        default=False,
        help_text='True if the version is published, False otherwise.',
    )

    deprecated = models.BooleanField(
        default=False,
        help_text='True if the version is deprecated, False otherwise.',
    )

    creator = models.ForeignKey(
        User,
        help_text='The user who created this version.',
    )

    created = models.DateTimeField(
        auto_now_add=True,
        help_text='The date this product version was created.',
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""

        ptask_ver = self.ptask_version.number
    
        # populate the spec field
        self.spec = SPEC_SEPARATOR.join([
            self.product.spec,
            str(ptask_ver).zfill(4),
        ])

        # populate the number field
        self.number = ptask_ver
            
        super(ProductVersion, self).save(*args, **kwargs) 

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Version'
        verbose_name_plural = 'Versions'
        unique_together = (('product', 'ptask_version'),) class ProductRepresentation(models.Model):

    # ------------------------------------------------------------------------
    # Fields:
    # ------------------------------------------------------------------------
    product_version = models.ForeignKey(
        ProductVersion,
        db_index=True,
        help_text='The product version this representation is associated with.',
        related_name='representations',
    )

    resolution = models.CharField(
        max_length=32,
        help_text='Resolution for this representation.',
        default="none"
    )

    representation_type = models.CharField(
        max_length=32,
        help_text='Type for this representation.',
    )

    frame_range = models.CharField(
        max_length=1024,
        help_text='Frame range for this representation.',
        blank=True,
        null=True,
    )

    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this representation.',
        blank=True,
        editable = False,
    )

    creation_location = models.ForeignKey(
        Location,
        blank=True,
        help_text='The creation locations of the representation.',
    )

    creator = models.ForeignKey(
        User,
        help_text='The user who created this representation.',
    )

    created = models.DateTimeField(
        auto_now_add=True,
        help_text='The date this representation was created.',
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""
    
        self.spec = SPEC_SEPARATOR.join([
            self.product_version.spec,
            self.representation_type,
            self.resolution,
        ])
            
        super(ProductRepresentation, self).save(*args, **kwargs) 

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Representation'
        verbose_name_plural = 'Respresentations'
        unique_together = (
            (
                'product_version', 
                'resolution', 
                'representation_type'
            ),
        ) class ProductGrouping(models.Model):

    parent_product_version = models.ForeignKey(
        ProductVersion,
        help_text="The parent product version in this relationship.",
        related_name='parent_groupings',
    )

    child_product_version = models.ForeignKey(
        ProductVersion,
        help_text="The child product version in this relationship.",
        related_name='child_groupings',
    )

    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this representation status.',
        blank=True,
        editable = False,
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""
    
        self.spec = self.parent_product_version.spec + ',' + \
            self.child_product_version.spec
            
        super(ProductGrouping, self).save(*args, **kwargs) 

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Grouping'
        verbose_name_plural = 'Groupings' class ProductRepresentationStatus(models.Model):

    # status choices enum
    ONLINE = 0
    DELETED = 1
    NEARLINE = 2
    TO_BE_DELETED = 3

    # XXX create a separate table for these
    # XXX maybe include an RGB for each ?
    STATUS_CHOICES = (
        (ONLINE, 'Online'),
        (DELETED, 'Deleted'),
        (NEARLINE, 'Nearline'),
        (TO_BE_DELETED, 'To be deleted'),
    )

    product_representation = models.ForeignKey(
        ProductRepresentation,
        help_text="The product representation in a given location.",
    )

    location = models.ForeignKey(
        Location,
        blank=True,
        help_text='The location of the representation.',
    )

    status = models.IntegerField(
        choices=STATUS_CHOICES,
        default=ONLINE,
        help_text='The status of a representation in a specific location.'
    )
    
    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this representation status.',
        blank=True,
        editable = False,
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""
    
        self.spec = self.product_representation.spec + ',' + \
            self.location.code
            
        super(ProductRepresentationStatus, self).save(*args, **kwargs) 

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Representation Status'
        verbose_name_plural = 'Representation Statuses'
        unique_together = (('product_representation', 'location'),) class ProductSubscription(models.Model):
    
    product_version = models.ForeignKey(
        ProductVersion,
        db_index=True,
        help_text='The product version being subscribed to.',
        related_name='subscriptions',
    )

    ptask_version = models.ForeignKey(
        PTaskVersion,
        db_index=True,
        help_text='The ptask version associated with his product version.',
        related_name='subscriptions',
    )

    locked = models.BooleanField(
        default=False,
        help_text='True if the subscription is locked, False otherwise.',
    )

    spec = models.CharField(
        max_length=1024,
        help_text='Specification for this subscription.',
        blank=True,
        editable = False,
    )

    # ------------------------------------------------------------------------
    # Special methods:
    # ------------------------------------------------------------------------
    def __unicode__(self):
        return unicode(self.spec)

    # ------------------------------------------------------------------------
    # Public methods:
    # ------------------------------------------------------------------------
    def save(self, *args, **kwargs):
        """Make sure the spec is set properly."""
    
        self.spec = self.ptask_version.spec + ',' + \
            self.product_version.spec 
            
        super(ProductSubscription, self).save(*args, **kwargs) 

    # ------------------------------------------------------------------------
    # Internal classes:
    # ------------------------------------------------------------------------
    class Meta:
        managed = True
        verbose_name = 'Subscription'
        verbose_name_plural = 'Subscriptions'
        unique_together = (('product_version', 'ptask_version'),) class ProductCategorySerializer(serializers.ModelSerializer):

    class Meta:
        model = ProductCategory class ProductSerializer(serializers.ModelSerializer):

    ptask = serializers.SlugRelatedField(slug_field="spec")
    category = serializers.SlugRelatedField(slug_field="name")
    creator = serializers.SlugRelatedField(slug_field="username")
    versions = serializers.RelatedField(many=True, required=False)

    class Meta:
        model = Product class ProductVersionSerializer(serializers.ModelSerializer):

    ptask_version = serializers.SlugRelatedField(slug_field="spec")
    product = serializers.SlugRelatedField(slug_field="spec")
    creator = serializers.SlugRelatedField(slug_field="username")

    class Meta:
        model = ProductVersion class ProductRepresentationSerializer(serializers.ModelSerializer):

    product_version = serializers.SlugRelatedField(slug_field="spec")
    creation_location = serializers.SlugRelatedField(slug_field="code")
    creator = serializers.SlugRelatedField(slug_field="username")

    class Meta:
        model = ProductRepresentation class ProductGroupingSerializer(serializers.ModelSerializer):
    
    parent_product_version = serializers.SlugRelatedField(slug_field="spec")
    child_product_version = serializers.SlugRelatedField(slug_field="spec")

    class Meta:
        model = ProductGrouping class ProductRepresentationStatusSerializer(serializers.ModelSerializer):

    product_representation = serializers.SlugRelatedField(slug_field="spec")
    location = serializers.SlugRelatedField(slug_field="code")
    status = ProductRepresentationStatusField(
        choices=ProductRepresentationStatus.STATUS_CHOICES)

    class Meta:
        model = ProductRepresentationStatus class ProductSubscriptionSerializer(serializers.ModelSerializer):
    
    product_version = serializers.SlugRelatedField(slug_field="spec")
    ptask_version = serializers.SlugRelatedField(slug_field="spec")

    class Meta:
        model = ProductSubscription
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.http import Http404
from django.shortcuts import get_object_or_404
from rest_framework import filters, mixins, status, viewsets
from rest_framework.response import Response
from .models import (
    ProductCategory,
    Product,
    ProductVersion,
    ProductRepresentation,
    ProductGrouping,
    ProductRepresentationStatus,
    ProductSubscription,
)
from .serializers import (
    ProductCategorySerializer,
    ProductSerializer,
    ProductVersionSerializer,
    ProductRepresentationSerializer,
    ProductGroupingSerializer,
    ProductRepresentationStatusSerializer,
    ProductSubscriptionSerializer,
)
import django_filters
# ----------------------------------------------------------------------------
class ProductRepresentationStatusFilterSet(django_filters.FilterSet):

    ids = ListFilter(name="id")
    location = django_filters.CharFilter(name="location__code")
    product_representation = django_filters.CharFilter(
        name="product_representation__spec")
    specs = ListFilter(name="spec")

    class Meta:
        model = ProductRepresentationStatus
        fields = [
            "id",
            "ids",
            "location",
            "product_representation",
            "spec",
            "specs",
            "status",
        ]

# ----------------------------------------------------------------------------
class ProductGroupingFilterSet(django_filters.FilterSet):

    child = django_filters.CharFilter(name="child_product_version__spec")
    ids = ListFilter(name="id")
    parent = django_filters.CharFilter(name="parent_product_version__spec")
    ptask = django_filters.CharFilter(
        name="parent_product_version__ptask_version__ptask__spec"
    )
    ptask_version = django_filters.CharFilter(
        name="parent_product_version__ptask_version__spec"
    )
    specs = ListFilter(name="spec")
    
    class Meta:
        model = ProductGrouping
        fields = [
            "child",
            "id",
            "ids",
            "parent",
            "ptask",
            "ptask_version",
            "spec",
            "specs",
        ]

# ----------------------------------------------------------------------------
class ProductSubscriptionFilterSet(django_filters.FilterSet):
        
    ids = ListFilter(name="id")
    product_version = django_filters.CharFilter(name="product_version__spec")
    ptask_version = django_filters.CharFilter(name="ptask_version__spec")
    product = django_filters.CharFilter(name="product_version__product__spec")
    ptask = django_filters.CharFilter(name="ptask_version__ptask__spec")

    class Meta:
        model = ProductSubscription
        fields = [
            "id",
            "ids",
            "product_version",
            "ptask_version",
            "product",
            "ptask",
            "locked",
        ]

# ----------------------------------------------------------------------------
# ViewSets:
# ----------------------------------------------------------------------------
class ProductCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):

    queryset = ProductCategory.objects.all()
    serializer_class = ProductCategorySerializer

# ----------------------------------------------------------------------------
class ProductViewSet(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    viewsets.GenericViewSet,
):

    filter_backends = (
        filters.DjangoFilterBackend,
        filters.SearchFilter,
        filters.OrderingFilter,
    )

    filter_class = ProductFilterSet
    filter_fields = ('id',)
    lookup_field = "spec"
    ordering = ("spec",)
    ordering_fields = ("spec",)
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    search_fields = ("spec",)

# ----------------------------------------------------------------------------
class ProductVersionViewSet(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    viewsets.GenericViewSet,
):

    filter_backends = (
        filters.DjangoFilterBackend,
        filters.OrderingFilter,
    )

    filter_class = ProductVersionFilterSet
    filter_fields = ('id','number')
    lookup_field = "spec"
    ordering = ("spec",)
    ordering_fields = ("spec",)

    queryset = ProductVersion.objects.all()