from django.conf import settings
from django.contrib.auth.models import User, Group
from django.db import models
from django.utils.translation import ugettext_lazy as _
#from ldt.core.models import Document, Owner
from ldt.core.models import Document
from guardian.shortcuts import assign, remove_perm
import ldt.indexation
from utils import (create_ldt, copy_ldt, create_empty_iri, update_iri, 
    generate_uuid)
import lucene
import lxml.etree
import mimetypes
import os.path
import tagging.fields
import uuid

class Author(models.Model):

    handle = models.CharField(max_length=512, unique=True, blank=True, null=True)
    email = models.EmailField(unique=False, blank=True, null=True)
    firstname = models.CharField(max_length=512, blank=True, null=True)
    lastname = models.CharField(max_length=512, blank=True, null=True)
    
    def __unicode__(self):
        return unicode(self.id) + " - " + self.handle + ", " + self.email + ", " + self.firstname + " " + self.lastname

class Media(models.Model):
    external_id = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.external_id'))
    external_permalink = models.URLField(max_length=1024, verify_exists=False, null=True, blank=True, verbose_name=_('media.external_permalink'))
    external_publication_url = models.URLField(max_length=1024, verify_exists=True, null=True, blank=True, verbose_name=_('media.external_publication_url'))
    external_src_url = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.external_src_url'))
    creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('media.creation_date'))
    media_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('media.media_creation_date'))
    update_date = models.DateTimeField(auto_now=True, verbose_name=_('media.update_date'))
    videopath = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('media.videopath'))
    duration = models.IntegerField(null=True, blank=True, verbose_name=_('media.duration'))
    creator = models.ForeignKey(User, blank=True, null=True, verbose_name=_('media.creator'))
    description = models.TextField(null=True, blank=True, verbose_name=_('description'))
    title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('title'))
    src = models.CharField(max_length=1024, unique=True, verbose_name=_('media.src'))
    mimetype_field = models.CharField(max_length=512, null=True, blank=True, verbose_name=_('media.mimetype'))
    
    def mimetype(): #@NoSelf
        def fget(self):
            if self.mimetype_field :
                return self.mimetype_field
            elif self.src:
                return mimetypes.guess_type(self.src.rstrip())[0]
            else:
                return None
        
        def fset(self, value):
            self.mimetype_field = value
        
        return locals()
    mimetype = property(**mimetype())
    
    def stream_src(): #@NoSelf
        
        def fget(self):
            res_src = self.src.rstrip()
            if self.videopath and self.videopath.startswith("rtmp://") and "mp3:" not in res_src and "mp4:" not in res_src:
                extension = res_src.split(".")[-1]
                res_src = {
                    'flv': lambda s: s,
                    'mp3': lambda s: "%s:%s" % ("mp3", res_src[:-4]),
                    'mp4': lambda s: "%s:%s" % ("mp4", res_src),
                    'f4v': lambda s: "%s:%s" % ("mp4", res_src),
                    'mov': lambda s: "%s:%s" % ("mp4", res_src),
                }.get(extension, lambda s:s)(res_src)
            return res_src
        
        return locals()
    
    stream_src = property(**stream_src())
    
    def save(self, *args, **kwargs):
        super(Media, self).save(*args, **kwargs)
        for content in self.content_set.all():
            content.sync_iri_file()
    
    def __unicode__(self):
        strings = []
        if self.title:
            strings.append(unicode(self.title))
        else:
            strings.append(unicode(self.src))
        if self.external_id:
            strings.append(unicode(self.external_id))
        return "|".join(strings)


class ContentManager(models.Manager):
    def get_by_natural_key(self, iri_id):
        return self.get(iri_id=iri_id)

class Content(models.Model):
    objects = ContentManager()
    
    iri_id = models.CharField(max_length=1024, unique=True, default=generate_uuid, verbose_name=_('content.iri_id'))
    iriurl = models.CharField(max_length=1024, verbose_name=_('content.iriurl'))
    creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('content.creation_date'))
    update_date = models.DateTimeField(auto_now=True, verbose_name=_('content.update_date'))
    title = models.CharField(max_length=1024, null=True, blank=True, verbose_name=_('content.title'))
    description = models.TextField(null=True, blank=True, verbose_name=_('content.description'))
    authors = models.ManyToManyField(Author, blank=True, verbose_name=_('content.authors'))
    duration = models.IntegerField(null=True, blank=True, verbose_name=_('content.duration'))
    content_creation_date = models.DateTimeField(null=True, blank=True, verbose_name=_('content.content_creation_date'))
    tags = tagging.fields.TagField(max_length=2048, null=True, blank=True)
    media_obj = models.ForeignKey('Media', blank=True, null=True)
    
    class Meta:
        ordering = ["title"]
        permissions = (
                       ('view_content', 'Can view Content'),
                       )
    
    def natural_key(self):
        return self.iri_id
        
    # added for import
    def get_by_natural_key(self, iri_id):
        return self.get(iri_id=iri_id)

    def get_duration(self):
        if self.duration is None:
            doc = lxml.etree.parse(self.iri_file_path())
            res = doc.xpath("/iri/body/medias/media[@id='video']/video")
            if len(res) > 0:
                try:
                    self.duration = int(res[0].get(u'dur', 0) or 0)
                except:
                    self.duration = 0
            else:
                self.duration = 0
            self.save()
        return self.duration
    
    def mimetype(): #@NoSelf
        def fget(self):
            if self.media_obj:
                return self.media_obj.mimetype
            else:
                return None
        return locals()
    
    mimetype = property(**mimetype())
    
    def delete(self):
        super(Content, self).delete()
        writer = ldt.indexation.get_writer()
        try:
            writer.deleteDocuments(lucene.Term("iri_id", self.iri_id))
            writer.commit()
        finally:
            writer.close()
        
    def sync_iri_file(self):
        # create iri file if needed
        created = False
        try:
            iri_file_path = self.iri_file_path()
            if not os.path.exists(iri_file_path):
                dir = os.path.dirname(iri_file_path)
                if not os.path.exists(dir):
                    os.makedirs(dir)
                created = True
                file = open(iri_file_path, "w")
                create_empty_iri(file, self, "IRI")
            else:
                created = False
                update_iri(iri_file_path, self, "IRI")
                
        except Exception, e:
            if created:
                if os.path.exists(iri_file_path):
                    os.remove(iri_file_path)
            raise e
        
        
    #TODO: better manage the change in .iri name and error scenario (save in temp file + rename
    def save(self, *args, **kwargs):
        
        self.sync_iri_file()        
        # update it 
        super(Content, self).save(*args, **kwargs)
            
    def __unicode__(self):
        return str(self.id) + ": " + self.iri_id
        
    def iri_url(self, web_url=settings.WEB_URL):
        if 'http' in self.iriurl or 'https' in self.iriurl:
            return self.iriurl
        else:
            return unicode(web_url) + unicode(settings.MEDIA_URL) + u"ldt/" + unicode(self.iriurl)
    
    def iri_file_path(self):
        return os.path.join(os.path.join(os.path.join(settings.MEDIA_ROOT, "ldt"), self.iri_id), os.path.basename(self.iriurl))

    def iri_url_template(self):
        return "${web_url}${media_url}ldt/" + unicode(self.iri_id) + "/" + os.path.basename(self.iriurl)


    def __get_empty_media(self):
        if settings.EMPTY_MEDIA_EXTERNALID:
            empty_media = Media.objects.get(external_id=settings.EMPTY_MEDIA_EXTERNALID)
            return empty_media
        else:
            return None
            
    
    def stream_src(): #@NoSelf
        
        def fget(self):
            if self.media_obj is not None:
                return self.media_obj.stream_src
            else:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.stream_src
                else:
                    return ""
        
        return locals()
    
    stream_src = property(**stream_src())
    
    def videopath(): #@NoSelf
        doc = """simulate videopath""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.videopath
                else:
                    return None
            else:
                return self.media_obj.videopath
           
        def fset(self, value):
            if self.media_obj is not None:
                self.media_obj.videopath = value
                      
        return locals()
       
    videopath = property(**videopath())

    def src(): #@NoSelf
        doc = """simulate videopath""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.src
                else:
                    return None
            else:
                return self.media_obj.src
           
        def fset(self, value):
            if self.media_obj is None or self.media_obj.src != value:
                media, created = Media.objects.get_or_create(src=value, defaults={'src':value})                #@UnusedVariable
                self.media_obj = media
                self.save()
                      
        return locals()
       
    src = property(**src())

    def external_id(): #@NoSelf
        doc = """simulate externalid""" #@UnusedVariable
       
        def fget(self):
            if self.media_obj is None:
                empty_media = self.__get_empty_media()
                if empty_media:
                    return empty_media.external_id
                else: 
                    return None
            else:
                return self.media_obj.external_id
           
        def fset(self, value):
            if self.media_obj is not None:
                self.media_obj.external_id = value
                      
        return locals()
       
    external_id = property(**external_id())
    
class Project(Document):  
    STATE_CHOICES = (
    (1, 'edition'),
    (2, 'published'),
    (3, 'moderated'),
    (4, 'rejected'),
    (5, 'deleted')
    )
    ldt_id = models.CharField(max_length=1024, unique=True)
    ldt = models.TextField(null=True)
    title = models.CharField(max_length=1024)
    contents = models.ManyToManyField(Content)
    creation_date = models.DateTimeField(auto_now_add=True)
    modification_date = models.DateTimeField(auto_now=True)
    created_by = models.CharField(_("created by"), max_length=70)
    changed_by = models.CharField(_("changed by"), max_length=70)
    state = models.IntegerField(choices=STATE_CHOICES, default=1)
    description = models.TextField(null=True, blank=True)
    objects = models.Manager()
    
    class Meta:
        ordering = ["title"]
        permissions = (
                       ('view_project', 'Can view project'),
                       )

    
    def __unicode__(self):
        return unicode(self.id) + u"::" + unicode(self.ldt_id) + u"::" + unicode(self.title)
    
    def get_description(self, doc=None):
        
        if doc is None:
            doc = lxml.etree.fromstring(self.ldt)
        
        res = doc.xpath("/iri/project")
        if len(res) > 0:
            return res[0].get(u'abstract')
        else:
            return None
        
    def publish(self):
        self.state = 2 
        self.save()
        public_group = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
        assign('view_project', public_group, self)
        
    def unpublish(self):
        self.state = 1
        self.save()
        public_group = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
        remove_perm('view_project', public_group, self)

    def stream_mode(): #@NoSelf
        def fget(self):
            modes = []
            for content in self.contents.all():
                mimetype = content.mimetype
                if mimetype:
                    mode = mimetype.split("/")[0]
                    if "audio" == mode or "video" == mode:
                        modes.append(mode)
                    else:
                        modes.append("video")
                else:
                    modes.append("video")
            def filter_video(current, item):
                if not current:
                    return item
                elif current == item:
                    return item
                else:
                    return "video"
            return reduce(filter_video, modes)
        return locals()
    
    stream_mode = property(**stream_mode())

    @staticmethod
    def create_project(user, title, contents, description=''):
#        owner = Owner.objects.get(user=user) #@UndefinedVariable
        owner = user
        project = Project(title=title, owner=owner, description=description)
        project.ldt_id = str(uuid.uuid1()) #@UndefinedVariable
        project.created_by = user.username
        project.changed_by = user.username
        project.state = 1
        project.save()
        assign('view_project', user, project)
        assign('change_project', user, project)
        for g in user.groups.all():
            assign('view_project', g, project)
            assign('change_project', g, project)
        for content in contents:
            project.contents.add(content)
        project.save()
        return create_ldt(project, user)

    def copy_project(self, user, title, description=''):
#        owner = Owner.objects.get(user=user) #@UndefinedVariable
        owner = user
        project = Project(title=title, owner=owner, description=description)
        project = copy_ldt(self, project, user)
        project.save()
        assign('view_project', user, project)
        assign('change_project', user, project)
        for content in self.contents.all():
            project.contents.add(content)
        project.save()
        return project
    
    def check_access(self, user):
        if (user and user.is_staff) or self.state == 2: 
            return True
        else:
            return False
        

class Segment(models.Model):
    
    project_obj = models.ForeignKey(Project, null=True)
    content = models.ForeignKey(Content)
    project_id = models.CharField(max_length=1024, unique=False, blank=True, null=True)
    iri_id = models.CharField(max_length=1024, unique=False)
    ensemble_id = models.CharField(max_length=1024, unique=False)
    cutting_id = models.CharField(max_length=1024, unique=False)    
    element_id = models.CharField(max_length=1024, unique=False)
    tags = tagging.fields.TagField(max_length=2048, null=True, blank=True, unique=False)
    title = models.CharField(max_length=2048, unique=False, null=True, blank=True)
    duration = models.IntegerField(null=True)
    start_ts = models.IntegerField(null=True)
    author = models.CharField(max_length=1024, unique=False, null=True, blank=True)
    date = models.CharField(max_length=128, unique=False, null=True, blank=True)
    abstract = models.TextField(null=True, blank=True)
    
    def __unicode__(self):
        return "/".join((unicode(self.project_id), unicode(self.iri_id), unicode(self.ensemble_id), unicode(self.cutting_id), unicode(self.element_id)))
    
    class Meta:
        unique_together = (('project_id', 'iri_id', 'ensemble_id', 'cutting_id', 'element_id'),)


