import os, string, re, sys
import functions, head, body, footer, picturemanager
import threading, Queue, time
try:
    import taghandler
except:
    pass # ok we don't have a SAX parser, but we can still create galleries
try:
    import xml
except:
    pass # ok we don't have a SAX parser, but we can still create galleries

class Galleries(threading.Thread):
    """The real worker. Continually polls the requestqueue and processes
    requests defined by the 'props' dictionary placed on the queue either
    by the commandline or from the gui"""
    
    def __init__(self, requestqueue, resultqueue, props):
        threading.Thread.__init__(self)
        self.setDaemon(1)
        self.requestqueue = requestqueue
        self.resultqueue = resultqueue
        self.requestID = 0
        self.currentID = 0
        self.props = props
        self.head = None
        self.body = None
        self.footer= None
        self.picturemanager = None

        self.start()

    def run(self):
        """Continually checks if requestqueue contains job,
           and executes it if so"""
        while 1:
            try:
                (self.currentID, self.props) = self.requestqueue.get()
                if self.props is not None:
                    if self.props["recurse"]:
                        self._recurse()
                    else:
                        self._process()
                    self.putresult("Job '%s' finished" % self.currentID, functions.status_finished_ok)
            except Queue.Empty:
                pass
            except:
                functions.printTraceback()
                self.putresult("Job '%s' failed." % self.currentID, functions.status_finished)
                sys.exit(1)
            self.props = None
            time.sleep(1)
                

    def perform(self):
        """Put request on queue and return ID"""
        self.requestID = self.requestID + 1
        self.currentID = self.requestID
        self.requestqueue.put((self.requestID, self.props))
        self.putresult("Job has been scheduled", functions.status_info)
        return self.requestID


    def putresult(self, message, jobstatus=functions.status_working):
        """
        Put messages on resultqueue
        ID used is the current requestID we are working on
        message is a message which can be displayed by client
        jobstatus signals state: states are defined in functions module
        """
        self.resultqueue.put_nowait((self.currentID, message, jobstatus)) 


    def  iscreate(self, srcdirectory, destinationdir):
        "Preparations for creating gallery, returns true if gallery is to be generated. Only creates gallery if sourcefiles are younger than (possible) existing gallery/index.html file"

        filelist = functions.globFiles(srcdirectory)
        if filelist is None:
            self.props["numberOfPics"] = 0
        else:
            self.props["numberOfPics"] = len(filelist)
        isprinting = 0 # klugde for now

        subdirs =  self.getChildrenNavigation(isprinting)

        if filelist or subdirs:
            # check if sourcefiles are younger than gallery
            youngestTime = 0
            galleryTime = 0
            if not self.props["forcecreate"]:
                youngestTime = functions.findYoungest(filelist)
            indexfile = os.path.join(destinationdir, "index.html")
            if os.path.exists(indexfile):
                galleryTime =  os.path.getmtime(indexfile)
            # create gallery
            if self.props["forcecreate"] or (youngestTime >= galleryTime):
                self.head = head.Head(self.props)    
                self.footer = footer.Footer(self.props)
                self.body =  body.Body(self.props)
                self.picturemanager = picturemanager.PictureManager(srcdirectory, self.props, self.putresult)
                if subdirs:
                    self.picturemanager.addSubdirslist(subdirs)
                self.picturemanager.createLinkedPictureList(filelist)
            else:
                self.putresult("Gallery younger than source pictures, skipping.", functions.status_info)
                return 0
        else:
            self.putresult("No pictures.", functions.status_info)
            return 0

        return 1


    def  updatefromxml(self, srcdirectory):
        "Update existing gallery from xml file"
        curdir = os.getcwd()
        os.chdir(srcdirectory)
        try: 
            handler = None
            self.putresult("Parsing xml, updating '%s'" % srcdirectory, functions.status_info)
            parser = xml.sax.make_parser()
            handler = taghandler.TagHandler()
            parser.setContentHandler(handler)
            try:
                parser.parse(self.props["xmlfile"])
                self.head = handler.getHead()
                self.body = handler.getBody()
                self.footer = handler.getFooter()
                self.picturemanager = handler.getPictureManager()
                if self.picturemanager:
                    self.picturemanager.createPictureHTMLs(self.footer)
            except IOError:
                pass # gallery.xml was not found, keep going
        finally:
            os.chdir(curdir)


    def isParentNavigation(self):
        """Determine if we must print a link to parent directory in navigation line
           Conditions: recursion enabled, a separate destination hierarchy has been set,
           working dir not topmost"""
        result = 0
        if self.props["recurse"]:
            if os.path.abspath(self.props["baseDestinationDir"]) != os.path.abspath(self.props["sourcedir"]):
                if os.path.abspath(self.props["baseDestinationDir"]) != os.path.abspath(self.props["galleryDirectory"]):
                    result = 1
        return result


    def getChildrenNavigation(self, doprint=1):
        """Determine if we must print links to subdirectories in navigation line
           Condition: recursion enabled and subdirs with pictures exists

           result is sorted list of subdirs or None"""

        result = None
        if self.props["recurse"]:
                result = functions.getSubdirsWithPics(self.props["recurseSrcDir"])

        if result:
            try:
                result = [item for item in result if not
                          os.path.abspath(os.path.join(self.props["recurseSrcDir"],item)) == self.props["baseDestinationDir"]]
            except OSError:
                pass
        return result


    def createGallery(self):
        functions.createDirectories(self.props["galleryDirectory"], self.props["fullsize"])

        functions.createStylesheet(self.props)

        self.picturemanager.FillPictureDirectories()

        # build XML and HTML files
        # create index.html
        html = [ "" ]
        html.append(self.head.getHTML())
        html.append(self.body.getHTML(self.picturemanager.getPicture()))

        # up/down navigation
        navigation = None
        hasHr = 0

        if self.isParentNavigation():
            if not navigation:
                navigation = []
            navigation.append("<hr>")
            hasHr =1
            navigation.append("[<A href=\"../index.html\">Up one level</A>]")
            if not navigation:
                navigation = []


        subdirs = self.picturemanager.getSubdirs()
        if subdirs:
            if not navigation:
                navigation = []
            if not hasHr:
                navigation.append("<hr>")
            for subdir in subdirs:    
                navigation.append("<A href=\"" + functions.quoteUrl(os.path.basename(subdir)) + "/index.html\">[" + functions.getTitle(os.path.join(self.props["recurseSrcDir"],subdir), self.props) + "]</A>")

        if navigation:
            html.append("".join(navigation))

        html.append(self.footer.getHTML())

        file = open(os.path.join(self.props["galleryDirectory"], "index.html"), 'w')
        file.write(string.joinfields(html))
        file.close()

        # create picture html pages
        self.picturemanager.createPictureHTMLs(self.footer)

        # create xml file
        xml = [ "" ]
        xml.append(self.head.getXML())
        xml.append(self.body.getXML(self.picturemanager))
        xml.append(self.picturemanager.getXML())
        xml.append(self.footer.getXML())
        xml.append("\n    </index>")
        xmlfile = open(os.path.join(self.props["galleryDirectory"], "gallery.xml"), 'w')
        xmlfile.write(string.joinfields(filter(None,xml))[0:])
        xmlfile.close()



    def processDir(self, dummy, srcdirectory, files):
        "Process directory. Dummy is placeholder for argument supplied  by os.path.walk()"

        version =  os.sys.version_info
        if self.props["updateFromXML"]:
            if version[0]>=self.props["major"] and version[1]>=self.props["minor"]:
                self.updatefromxml(srcdirectory)
                return
            else:
                self.putresult("XML updating requires at least Python %d.%d" % (self.props["major"],self.props["minor"]), functions.status_finished)
        else:
            # don't create galleries of destination....
            if srcdirectory == self.props["baseDestinationDir"]:
                if files:
                    files[:] = []
                self.putresult("Doesn't traverse destination dir hierarchy: '%s'" % srcdirectory, functions.status_info)    
                return

            # this convoluted way of building the path is for recursion support
            self.props["galleryDirectory"] = os.path.join(self.props["baseDestinationDir"], srcdirectory[len(self.props["sourcedir"])+1:])

            if self.props["recurse"]:
                self.props["recurseSrcDir"] = os.path.abspath(srcdirectory)
                self.props["title"] = functions.getTitle(srcdirectory, self.props)
            else:        
                if not self.props["title"]:    
                    self.props["title"]=functions.getTitle(srcdirectory, self.props)

            if self.iscreate(srcdirectory, self.props["galleryDirectory"]):
                self.putresult("---", functions.status_info)    
                self.putresult("Source directory: %s" % srcdirectory, functions.status_info)    
                self.putresult("Destination directory: %s" % self.props["galleryDirectory"] , functions.status_info)    
                self.putresult("Title: %s" % functions.getTitle(srcdirectory, self.props) , functions.status_info)    
                self.createGallery()

    def _process(self):
        "Wrapper which calls processDir with necessary Nones"
        self.processDir(None, self.props["sourcedir"], None)



    def _recurse(self):
        os.path.walk(self.props["sourcedir"], self.processDir, None)
