import tempfile
import os.path
import shutil
from blinkster.utils import zipfileext
import blinkster.utils.log
import blinkster.utils.xml
from blinkster import settings
from blinkster.ldt.models import Content, LdtProject
import Ft
import xml.dom.minidom
import xml.dom.ext
import xml.xpath
import fnmatch
import lucene
import uuid
from blinkster.ldt import STORE
from blinkster.ldt import ANALYZER
from blinkster.ldt.contentindexer import ContentIndexer

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

class IriInfo(object):

    
    def __init__(self, id, basepath, order, titledesc, decoupage_blacklist=settings.DECOUPAGE_BLACKLIST):
        self.id = id
        self.basepath = basepath
        self.order = order
        self.src = ""
        self.annotations = None
        self.videopath = settings.STREAM_URL
        self.videourl = ""
        self.title = None
        self.desc = None
        self.duration = None
        self.decoupageId = None
        self.ensembleId = None
        self.created = False
        self.content = None
        self.decoupage_blacklist = decoupage_blacklist
        if self.decoupage_blacklist is None:
            self.decoupage_blacklist = ()
        
        
    
    def processIri(self):
        
        path = os.path.join(self.basepath, self.src)
        doc = xml.dom.minidom.parse(path)
        doc = Ft.Xml.Domlette.ConvertDocument(doc)        
        
        con = xml.xpath.Context.Context(doc, 1, 1, None)
        
        res = xml.xpath.Evaluate("/iri/head/meta[@name='title']/@content", context=con)
        self.title = res[0].value
        
        res = xml.xpath.Evaluate("/iri/body/ensembles", context=con)
        ensemblesnode = res[0]

        if self.annotations is not None:
            newensemble = doc.createElement('ensemble')
            self.ensembleId = self.id + "_" + str(uuid.uuid1())
            newensemble.setAttributeNS(None, 'id', self.ensembleId)
        
            newensemble.setAttributeNS(None, 'title', self.annotations.getAttributeNS(None, 'title'))
            newensemble.setAttributeNS(None, 'author', self.annotations.getAttribute('author'))
            newensemble.setAttributeNS(None, 'date', self.annotations.getAttribute('date'))
            newensemble.setAttributeNS(None, 'abstract', self.annotations.getAttribute('abstract'))
            
            decoupageNode = None
            for node in self.annotations.childNodes:
                if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.tagName == "decoupage":
                    decoupageNode = node
                    newDecoupageNode = decoupageNode.cloneNode(True)
                    newensemble.appendChild(newDecoupageNode)
            
            if not decoupageNode is None:
                self.decoupageId = decoupageNode.getAttribute(u"id")
        
            ensemblesnode.appendChild(newensemble)
        else:
            # find an ensemble child node
            ensemble = None
            for node in ensemblesnode.childNodes:
                if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.tagName == "ensemble":
                    ensemble = node
                    break
            if ensemble is not None:
                self.ensembleId = ensemble.getAttributeNS(None, u"id")
                decoupageNode = None
                for node in ensemble.childNodes:
                    if node.nodeType == xml.dom.Node.ELEMENT_NODE and node.tagName == "decoupage":
                        decoupageNode = node
                        break
                if not decoupageNode is None:
                    self.decoupageId = decoupageNode.getAttributeNS(None, u"id")
                
        
        res = xml.xpath.Evaluate("/iri/body/medias/media[@id='video']/video", context=con)
        src_video = res[0].getAttributeNS(None, 'src')
        self.videourl = os.path.basename(src_video)
        self.duration = res[0].getAttributeNS(None, 'dur')
        
        f = open(path, "w")
        try:
            xml.dom.ext.Print(doc, stream=f)
        finally:
            f.close()
        
        
        destPath = os.path.join(os.path.join(os.path.join(blinkster.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)))



    def saveContent(self):
        blinkster.utils.log.debug("ID of object to create : " + str(self.id))
        content, self.created = Content.objects.get_or_create(iri_id=self.id, defaults={ 'iri' : self.id + u"/" + os.path.basename(self.src), 'title':self.title, 'description':self.desc, })#'decoupage_id': self.decoupageId, 'ensemble_id': self.ensembleId});
        if not self.created:
            content.iri = self.id + u"/" + os.path.basename(self.src)
            content.title = self.title
            content.description = self.desc
            content.duration = int(self.duration)
            #content.decoupage_id = unicode(self.decoupageId)
            #content.ensemble_id = unicode(self.ensembleId)
            content.save()
        self.content = content
            
    def indexDecoupage(self, writer):
        indexer = ContentIndexer([self.content], writer, settings.DECOUPAGE_BLACKLIST)
        indexer.index_all()
            
    def process(self, writer):
        self.processIri()
        self.saveContent()
        self.indexDecoupage(writer)
        
class BaseFileImport(object):

    def __init__(self, filepath, author):
        self.__filepath = filepath
        self.__tempdir = ""
        self.__author = author
        self.__writer = lucene.IndexWriter(STORE, ANALYZER, True, lucene.IndexWriter.MaxFieldLength.UNLIMITED)
        self.__writer.setMaxFieldLength(1048576)


        
    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 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())
    
    def writer():            
        def fget(self):
            return self.__writer
                    
        return locals()
        
    writer = property(**writer())
    
    
    def close(self):
        self.__writer.optimize()
        self.__writer.close()


class FileImport(BaseFileImport):

    def __init__(self, filepath, author):
        BaseFileImport.__init__(self, filepath, author)
        self.__checkExistingMedia = False
        
    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 processLdt(self, ldtpath):
        
        # list iri
        # see if there is some comments
        # inject comment in iri
        # copy iri in folder
        # create or update content
        contents = {}
        doc = xml.dom.minidom.parse(ldtpath)
        doc = Ft.Xml.Domlette.ConvertDocument(doc)
        
        con = xml.xpath.Context.Context(doc, 1, 1, None)
        result = xml.xpath.Evaluate("/iri/project", context=con)
        for pnode in result:
            #author = pnode.attributes["user"].value
            if pnode.hasAttributeNS(None, "user"):
                self.author = unicode(pnode.getAttributeNS(None, "user"))
                break 

        result = xml.xpath.Evaluate("/iri/medias/media", context=con)
        
        for i, medianode in  enumerate(result):
            id = medianode.getAttributeNS(None, 'id')
            blinkster.utils.log.debug("FIRST ID : " + str(id))
            if self.checkExistingMedia:
                try:
                    Content.objects.get(iri_id=id)
                    do_pass = True
                except Content.DoesNotExist:
                    do_pass = False
            else:
                    do_pass = False
            if not do_pass:
                if not (contents.has_key(id)):
                    blinkster.utils.log.debug("CREATE IRI INFO ID : " + str(id))
                    contents[id] = IriInfo(id, os.path.dirname(ldtpath), i, "")
                contents[id].src = medianode.getAttributeNS(None, 'src')
        
        result = xml.xpath.Evaluate("/iri/annotations/content", context=con)

        blinkster.utils.log.debug("content xpath result : " + str(len(result)))        
        for contentnode in result:
            id = contentnode.getAttributeNS(None, 'id')
            blinkster.utils.log.debug("ID : " + str(id))
            if contents.has_key(id):
                if self.author:
                    contentnode.setAttributeNS(None, "author", unicode(self.author))
                contents[id].annotations = contentnode
        
        #go throught values
        for iriinfo in contents.values():
            
            iriinfo.process(self.writer)
            
            # if yes update
            # if no create
            # move iri file to the proper place
            #return list of iriInfo
        
    
    def processFile(self):
        # create temp directory
        self.__tempdir = tempfile.mkdtemp()
        openfiles = []
        flvfiles = []
        processedids = []
        
        try:
            zipfile = zipfileext.ZipFileExt(self.filepath)
            zipfile.unzip_into_dir(self.__tempdir)
            #load ldt
            blinkster.utils.log.debug("Processing files : ")
            blinkster.utils.log.debug(os.listdir(self.__tempdir))
            foldersToProcess = [self.__tempdir]
            while len(foldersToProcess):
                blinkster.utils.log.debug("folder stack length : " + str(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)):
                        blinkster.utils.log.debug("Push folder : " + entryPath)
                        foldersToProcess.append(entryPath)
                    elif fnmatch.fnmatch(entry, "*.ldt"):
                        blinkster.utils.log.debug("Process file : " + entryPath)
                        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
    

class ProjectFileImport(BaseFileImport):
    

    def processLdt(self):
        
        self.contents = []
        
        doc = xml.dom.minidom.parse(self.filepath)
        
        con = xml.xpath.Context.Context(doc, 1, 1, None)
        result = xml.xpath.Evaluate("/iri/project", context=con)
        for pnode in result:
            pnode.setAttribute("user", unicode(self.author))
            break
 
        result = xml.xpath.Evaluate("/iri/medias/media", context=con)
        
        for i, medianode in  enumerate(result):
            id = medianode.attributes['id'].value
            blinkster.utils.log.debug("FIRST ID at " + str(i) + " : " + str(id))
            content = Content.objects.get(iri_id=id)
            self.contents.append(content)
            
            medianode.setAttribute('src', content.iri_url_template())
            medianode.setAttribute('video', "${stream_url}")
            
        return doc.toprettyxml(encoding="utf-8")
        
    def processFile(self):
         
        ldt_id = unicode(uuid.uuid1())
        ldt = self.processLdt()
        authors = [self.author]
        contents = self.contents         
        
        ldtproject = LdtProject(ldt_id=ldt_id, ldt=ldt)
        ldtproject.save()
        idldt = ldtproject.id
        blinkster.utils.log.debug("ProjectFileImport.processFile ID : " + str(idldt))
        for author in authors:
            ldtproject.authors.add(author)
        for content in contents:
            ldtproject.contents.add(content)
        ldtproject.save()
        
        return [idldt]
        


class ZipProjectFileImport(FileImport):
    
    def __init__(self, filepath, author):
        FileImport.__init__(self, filepath, author)
        self.checkExistingMedia = True
    
    def processLdt(self, ldtPath):
        fi = ProjectFileImport(ldtPath, self.author)
        FileImport.processLdt(self, ldtPath)
        idproject = fi.processFile()
        blinkster.utils.log.debug("ZipProjectFileImport.processLdt ID : " + str(idproject))
        fi.close()
        
        return idproject
                
    
