from StringIO import StringIO
from copy import deepcopy #@UnresolvedImport
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction
from ldt.utils import zipfileext
from ldt.utils.url import request_with_auth
from models import Content, Media
import fnmatch
import lxml.etree #@UnresolvedImport
import mimetypes #@UnresolvedImport
import os.path
import shutil #@UnresolvedImport
import tempfile #@UnresolvedImport
import uuid #@UnresolvedImport

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, iri_id, order, titledesc, basepath="", videopath=settings.STREAM_URL, decoupage_blacklist=settings.DECOUPAGE_BLACKLIST, flatten=True):
        self.id = iri_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 process_iri(self):
        # for just import a file ldt and get the title for every media
        if 'http' in self.src:
            path = self.src
        #for import a zip, get title and copy file .iri in the media directory
        else:
            path = os.path.join(self.basepath, self.src)
        
        if 'http' in path:
            _,content = request_with_auth(path)
            path = StringIO(content)
        
        doc = lxml.etree.parse(path) #@UndefinedVariable
        
        
        #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")
                ens_id = node.attrib["id"]
                if ens_id not in ensembleids:
                    ensembleids.append(ens_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, #@UndefinedVariable
                                                            '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(settings.MEDIA_ROOT, "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)


    @transaction.atomic
    def save_content(self):

        
        defaults_media = {
            'src':unicode(self.videourl),
            'mimetype_field': mimetypes.guess_type(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 = { 
            'title':unicode(self.title),
            'description':unicode(self.desc),
            'media_obj':media,
            'iriurl':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.process_iri()
        self.save_content()
        
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.__check_existing_media = False
        self.__flatten = flatten
        
    def check_existing_media(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return self.__check_existing_media
           
        def fset(self, value):
            self.__check_existing_media = value
           
        def fdel(self):
            del self.__check_existing_media
           
        return locals()

    check_existing_media = property(**check_existing_media())    

    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 process_ldt(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) #@UndefinedVariable
        #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
            iri_id = medianode.attrib['id']
            if self.check_existing_media:
                try:
                    Content.objects.get(iri_id=iri_id)
                    do_pass = True
                except ObjectDoesNotExist: #Content.DoesNotExist
                    do_pass = False
            else:
                    do_pass = False
            if not do_pass:
                if not (contents.has_key(iri_id)):
                    # Create instance iriInfo(id, order, titledesc, basepath="", videopath=settings.STREAM_URL)
                    if ldtpath:
                        contents[iri_id] = IriInfo(iri_id, i, "", os.path.dirname(ldtpath), flatten=self.flatten)
                    else: 
                        contents[iri_id] = IriInfo(iri_id, i, "", flatten=self.flatten)
                    # Get iri file's url from ldt. This url can be relative path or absolute path.
                contents[iri_id].src = medianode.attrib['src']
                if medianode.attrib['video'] != "":
                    contents[iri_id].videopath = medianode.attrib['video']
                elif self.videopath != "" or self.videopath:
                    contents[iri_id].videopath = self.videopath
                else:
                    contents[iri_id].videopath = settings.STREAM_URL
                    
                
        #get annotation of file ldt
        result = doc.xpath("/iri/annotations/content")
        
        for contentnode in result:
            content_id = contentnode.attrib['id']
            if contents.has_key(content_id):
                if self.author:
                    contentnode.set("author", unicode(self.author))
                contents[content_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 process_file(self):
        if self.filepath.name.endswith(".ldt"):
            self.process_ldt()
        elif self.filepath.name.endswith(".zip"):
            self.process_zip()
        else:
            raise FileImportError("Bad file type")


    def process_zip(self):
    # """ extraire .zip, pass to method process_ldt"""
        # 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.process_ldt(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 process_file_ldt(self):
        # processedids = []
        # ldtid = self.process_ldt(self.filepath)
        # processedids.append(ldtid)
        # return processedids
