from django.db import models
from core.models import PlCoreBase,SingletonModel,PlCoreBaseManager
from core.models.plcorebase import StrippedCharField
from xos.exceptions import *
import json

class Service(PlCoreBase):
    # when subclassing a service, redefine KIND to describe the new service
    KIND = "generic"

    description = models.TextField(max_length=254,null=True, blank=True,help_text="Description of Service")
    enabled = models.BooleanField(default=True)
    kind = StrippedCharField(max_length=30, help_text="Kind of service", default=KIND)
    name = StrippedCharField(max_length=30, help_text="Service Name")
    versionNumber = StrippedCharField(max_length=30, help_text="Version of Service Definition")
    published = models.BooleanField(default=True)
    view_url = StrippedCharField(blank=True, null=True, max_length=1024)
    icon_url = StrippedCharField(blank=True, null=True, max_length=1024)
    public_key = models.TextField(null=True, blank=True, max_length=1024, help_text="Public key string")

    def __init__(self, *args, **kwargs):
        # for subclasses, set the default kind appropriately
        self._meta.get_field("kind").default = self.KIND
        super(Service, self).__init__(*args, **kwargs)

    @classmethod
    def get_service_objects(cls):
        return cls.objects.filter(kind = cls.KIND)

    def __unicode__(self): return u'%s' % (self.name)

class ServiceAttribute(PlCoreBase):
    name = models.SlugField(help_text="Attribute Name", max_length=128)
    value = StrippedCharField(help_text="Attribute Value", max_length=1024)
    service = models.ForeignKey(Service, related_name='serviceattributes', help_text="The Service this attribute is associated with")

class Tenant(PlCoreBase):
    """ A tenant is a relationship between two entities, a subscriber and a
        provider.

        The subscriber can be a User, a Service, or a Tenant.

        The provider is always a Service.
    """

    CONNECTIVITY_CHOICES = (('public', 'Public'), ('private', 'Private'), ('na', 'Not Applicable'))

    # when subclassing a service, redefine KIND to describe the new service
    KIND = "generic"

    kind = StrippedCharField(max_length=30, default=KIND)
    provider_service = models.ForeignKey(Service, related_name='tenants')
    subscriber_service = models.ForeignKey(Service, related_name='subscriptions', blank=True, null=True)      # can we drop this ?
    subscriber_tenant = models.ForeignKey("Tenant", related_name='subscriptions', blank=True, null=True)
    subscriber_user = models.ForeignKey("User", related_name='subscriptions', blank=True, null=True)
    service_specific_id = StrippedCharField(max_length=30)
    service_specific_attribute = models.TextField()
    connect_method = models.CharField(null=False, blank=False, max_length=30, choices=CONNECTIVITY_CHOICES, default="na")

    def __init__(self, *args, **kwargs):
        # for subclasses, set the default kind appropriately
        self._meta.get_field("kind").default = self.KIND
        super(Tenant, self).__init__(*args, **kwargs)

    def __unicode__(self):
        if not hasattr(self, "provider_service"):
           # When the REST API does a POST on a CordSubscriber object, for
           # some reason there is no provider_service field. All of the other
           # fields are there. Provider_service is even in the dir(). However,
           # trying to getattr() on it will fail.
           return "confused-tenant-object"

        if self.subscriber_service:
            return u'%s service %s on service %s' % (str(self.kind), str(self.subscriber_service.id), str(self.provider_service.id))
        elif self.subscriber_tenant:
            return u'%s tenant %s on service %s' % (str(self.kind), str(self.subscriber_tenant.id), str(self.provider_service.id))
        else:
            return u'%s on service %s' % (str(self.kind), str(self.provider_service.id))

    # helper for extracting things from a json-encoded service_specific_attribute
    def get_attribute(self, name, default=None):
        if self.service_specific_attribute:
            attributes = json.loads(self.service_specific_attribute)
        else:
            attributes = {}
        return attributes.get(name, default)

    def set_attribute(self, name, value):
        if self.service_specific_attribute:
            attributes = json.loads(self.service_specific_attribute)
        else:
            attributes = {}
        attributes[name]=value
        self.service_specific_attribute = json.dumps(attributes)

    @classmethod
    def get_tenant_objects(cls):
        return cls.objects.filter(kind = cls.KIND)

    # helper function to be used in subclasses that want to ensure service_specific_id is unique
    def validate_unique_service_specific_id(self):
        if self.pk is None:
            if self.service_specific_id is None:
                raise XOSMissingField("subscriber_specific_id is None, and it's a required field", fields={"service_specific_id": "cannot be none"})

            conflicts = self.get_tenant_objects().filter(service_specific_id=self.service_specific_id)
            if conflicts:
                raise XOSDuplicateKey("service_specific_id %s already exists" % self.service_specific_id, fields={"service_specific_id": "duplicate key"})

class CoarseTenant(Tenant):
    class Meta:
        proxy = True

    KIND = "coarse"

    def save(self, *args, **kwargs):
        if (not self.subscriber_service):
            raise XOSValidationError("subscriber_service cannot be null")
        if (self.subscriber_tenant or self.subscriber_user):
            raise XOSValidationError("subscriber_tenant and subscriber_user must be null")

        super(CoarseTenant,self).save()

@@ -4632,24 +4632,142 @@
  cls.KIND)%0A%0A
+    @classmethod%0A    def get_deleted_tenant_objects(cls):%0A        return cls.deleted_objects.filter(kind = cls.KIND)%0A%0A
     # helper

add method to get deleted tenant objects