from copy import deepcopy
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from ldt.utils import zipfileext
from models import Content, Media
import fnmatch
import lxml.etree
import os.path
import shutil
import tempfile
import urllib
import uuid

class FileImportError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)


def Property(func):
    return property(**func()) 

class IriInfo(object):

    
    def __init__(self, id, order, titledesc, basepath="", videopath=settings.STREAM_URL, decoupage_blacklist = settings.DECOUPAGE_BLACKLIST, flatten = True):
        self.id = id
        self.basepath = basepath
        self.order = order
        self.src = ""
        self.annotations = None
        self.videopath = videopath
        self.videourl = ""
        self.title = None
        self.desc = None
        self.duration = None
        self.created = False
        self.content = None
        self.decoupage_blacklist = decoupage_blacklist
        if self.decoupage_blacklist is None:
            self.decoupage_blacklist = ()
        self.flatten = flatten
        
        
    
    def processIri(self):
        # for just import a file ldt and get the title for every media
        if 'http' in self.src:
            #url = urllib.urlopen(self.src)
            path = url
            #doc = xml.dom.minidom.parse(url)
        #for import a zip, get title and copy file .iri in the media directory
        else:
            path = os.path.join(self.basepath, self.src)
            #doc = xml.dom.minidom.parse(path)
            
        doc = lxml.etree.parse(path)
        
        
        #doc = Ft.Xml.Domlette.ConvertDocument(doc) 
        #con = xml.xpath.Context.Context(doc, 1, 1, None)
        
        res = doc.xpath("/iri/head/meta[@name='title']/@content")
        #res = xml.xpath.Evaluate("/iri/head/meta[@name='title']/@content", context=con)
        #self.title = res[0].value
        self.title = res[0]

            
        #res = xml.xpath.Evaluate("/iri/body/ensembles",context=con)
        res = doc.xpath("/iri/body/ensembles")
        ensemblesnode = res[0]

        ensembleids = []

        for node in ensemblesnode: #ensemblesnode.childNodes:
            #if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.tagName == "ensemble":
            if node.tag == "ensemble":
                #id = node.getAttributeNS(None,u"id")
                id = node.attrib["id"]
                if id not in ensembleids:
                    ensembleids.append(id)

        if self.annotations is not None:
            newEnsemble = None
            #for cnode in self.annotations.childNodes:
            for cnode in self.annotations:
                #if cnode.nodeType == xml.dom.Node.ELEMENT_NODE and cnode.tagName == "decoupage":
                if cnode.tag == "decoupage":
                    if newEnsemble is None:
                        #newensemble = doc.createElementNS(None,'ensemble')
                        ensembleid = self.id+"_"+str(uuid.uuid1())
                        newensemble = lxml.etree.SubElement(ensemblesnode,
                                                            'ensemble',
                                                            {'id' : ensembleid,
                                                             'title' : self.annotations.get('title') or "",
                                                             'author' : self.annotations.get('author') or "",
                                                             'date' : self.annotations.get('date') or "",
                                                             'abstract' : self.annotations.get('abstract') or ""
                                                             }
                                                            )                        
                        ensembleids.append(ensembleid)
                    newDecoupageNode = deepcopy(cnode)
                    newensemble.append(newDecoupageNode)
                #elif cnode.nodeType == xml.dom.Node.ELEMENT_NODE and cnode.tagName == "ensemble":
                elif cnode.tag == "ensemble":
                    #ensembleid = cnode.getAttribute(u"id")
                    ensembleid = cnode.attrib['id']
                    cloneNode = deepcopy(cnode)
                    if ensembleid in ensembleids:
                        ensembleid = self.id+"_"+str(uuid.uuid1())
                        cloneNode.set(u"id", ensembleid)
                    ensembleids.append(ensembleid)
                    ensemblesnode.append(cloneNode)

        res = doc.xpath("/iri/body/medias/media[@id='video']/video")
        if self.flatten:
            src_video = res[0].get('src')
            self.videourl = os.path.basename(src_video)
            res[0].set('src', self.videourl)
        self.duration = res[0].get(u'dur')
            
        f = open(path, "w")
        try:
            #etree = lxml.etree.ElementTree(doc)
            doc.write(f, encoding="UTF-8", pretty_print=True, xml_declaration=True)
#            xml.dom.ext.Print(doc, stream=f)
        finally:
            f.close()
        
        
        destPath = os.path.join(os.path.join(os.path.join(settings.MEDIA_ROOT, "media"), "ldt"), self.id);
        if not os.path.exists(destPath):
            os.makedirs(destPath)
        shutil.move(os.path.join(self.basepath, self.src), os.path.join(destPath, os.path.basename(self.src)))
        self.src = self.id + u"/" + os.path.basename(self.src)



    def saveContent(self):

        defaults_media = {'src':unicode(self.videourl), 'title':unicode(self.title), 'description':unicode(self.desc), 'videopath': unicode(self.videopath.rstrip("/") + "/")}
        media, media_created = Media.objects.get_or_create(src=unicode(self.videourl), defaults = defaults_media)
        if not media_created:
            for key, value in defaults_media.items():
                setattr(media, key, value)

        media.save()

        defaults_content = { 
            'iriurl': unicode(self.src), 
            'title':unicode(self.title),
            'description':unicode(self.desc),
            'media':media,
            'iri':unicode(self.id + u"/" + os.path.basename(self.src)),
            'duration':int(self.duration)
        }
        content, self.created = Content.objects.get_or_create(iri_id=self.id, defaults = defaults_content)
        if not self.created:
            for key, value in defaults_content.items():
                setattr(content, key, value)
        
        content.save()

        self.content = content
            
    def process(self):
        self.processIri()
        self.saveContent()
        
class BaseFileImport(object):

    def __init__(self, filepath, videopath):
        self.__filepath = filepath
        self.__tempdir = ""
        self.__videopath = videopath
        self.__author = None

        
    def filepath(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__filepath
           
        def fset(self, value):
            self.__filepath = value
           
        def fdel(self):
            del self.__filepath
           
        return locals()
       
    filepath = property(**filepath())
    
    def videopath(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__videopath
           
        def fset(self, value):
            self.__videopath = value
           
        def fdel(self):
            del self.__videopath
           
        return locals()
       
    videopath = property(**videopath())

    def author(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__author
           
        def fset(self, value):
            self.__author = value
           
        def fdel(self):
            del self.__author
           
        return locals()

    author = property(**author())
    
       
class FileImport(BaseFileImport):

    def __init__(self, filepath, videopath, flatten):
        BaseFileImport.__init__(self, filepath, videopath)
        self.__checkExistingMedia = False
        self.__flatten = flatten
        
    def checkExistingMedia(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__checkExistingMedia
           
        def fset(self, value):
            self.__checkExistingMedia = value
           
        def fdel(self):
            del self.__checkExistingMedia
           
        return locals()

    checkExistingMedia = property(**checkExistingMedia())    

    def flatten(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__flatten
           
        def fset(self, value):
            self.__flatten = value
           
        def fdel(self):
            del self.__flatten
           
        return locals()
    flatten = property(**flatten())

    def processLdt(self, ldtpath=None):
        
        # list iri
        # see if there is some comments
        # inject comment in iri
        # copy iri in folder
        # create or update content
        contents = {}
        filepath = ldtpath if ldtpath else self.filepath
        doc = lxml.etree.parse(filepath)
        #if ldtpath:
            #doc = xml.dom.minidom.parse(ldtpath)
        #    doc = lxml.etree.parse(ldtpath)
        #else:
            #doc = xml.dom.minidom.parse(self.filepath)
        
        #con = xml.xpath.Context.Context(doc, 1, 1, None)
        
        #get author from file ldt
        #result = xml.xpath.Evaluate("/iri/project", context=con)
        result = doc.xpath("/iri/project")
        for pnode in result:
            #author = pnode.getAttributeNS(None,u"user")
            author = pnode.attrib[u"user"]
            if author:
                self.author = unicode(author)
                break 

        result = doc.xpath("/iri/medias/media")
        
        for i, medianode in  enumerate(result):
        # get iri file's id from file ldt
            #id = medianode.attributes['id'].value
            id = medianode.attrib['id']
            if self.checkExistingMedia:
                try:
                    Content.objects.get(iri_id=id)
                    do_pass = True
                except ObjectDoesNotExist: #Content.DoesNotExist
                    do_pass = False
            else:
                    do_pass = False
            if not do_pass:
                if not (contents.has_key(id)):
                    # Create instance iriInfo(id, order, titledesc, basepath="", videopath=settings.STREAM_URL)
                    if ldtpath:
                        contents[id] = IriInfo(id, i, "", os.path.dirname(ldtpath), flatten=self.flatten)
                    else: 
                        contents[id] = IriInfo(id, i, "", flatten=self.flatten)
                    # Get iri file's url from ldt. This url can be relative path or absolute path.
                #contents[id].src = medianode.attributes['src'].value
                contents[id].src = medianode.attrib['src']
                if medianode.attrib['video'] !="":
                    contents[id].videopath = medianode.attrib['video']
                elif self.videopath !="" or self.videopath:
                    contents[id].videopath = self.videopath
                else:
                    contents[id].videopath =settings.STREAM_URL
                    
                
        #get annotation of file ldt
        result = doc.xpath("/iri/annotations/content")
        
        for contentnode in result:
            id = contentnode.attrib['id']
            if contents.has_key(id):
                if self.author:
                    contentnode.set("author", unicode(self.author))
                contents[id].annotations = contentnode
        
        #go throught values
        for iriinfo in contents.values():
            
            iriinfo.process()
            
            # if yes update
            # if no create
            # move iri file to the proper place
            #return list of iriInfo
        
    def processFile(self):
        if self.filepath.name.endswith(".ldt"):
            self.processLdt()
        elif self.filepath.name.endswith(".zip"):
            self.processZip()
        else:
            raise FileImportError("Bad file type")


    def processZip(self):
    # """ extraire .zip, pass to method processLdt"""
        # create temp directory
        self.__tempdir = tempfile.mkdtemp()
        openfiles = []
        flvfiles = []
        processedids = []
        
        try:
            zipfile = zipfileext.ZipFileExt(self.filepath)
            zipfile.unzip_into_dir(self.__tempdir)
            #load ldt
            foldersToProcess = [self.__tempdir]
            while len(foldersToProcess):
                currentFolder = foldersToProcess.pop()
                for entry in os.listdir(currentFolder):
                    if entry in settings.ZIP_BLACKLIST:
                        continue
                    entryPath = os.path.join(currentFolder, entry)
                    if(os.path.isdir(entryPath)):
                        foldersToProcess.append(entryPath)
                    elif fnmatch.fnmatch(entry, "*.ldt"):
                        ldtid = self.processLdt(entryPath)
                        processedids.append(ldtid)
                    elif fnmatch.fnmatch(entry, "*.flv"):
                        flvfiles.append(entryPath)
             
            if settings.CONTENT_ROOT and os.path.exists(settings.CONTENT_ROOT): 
                for entry in flvfiles:
                    shutil.copy(entry, settings.CONTENT_ROOT)
                    
        finally:
            for f in openfiles:
                f.close()
            shutil.rmtree(self.__tempdir)
        # delete directory
        return processedids
        
    # def processFileLdt(self):
        # processedids = []
        # ldtid = self.processLdt(self.filepath)
        # processedids.append(ldtid)
        # return processedids
