# -*- coding: UTF-8 -*-


# Expression
# By: Frederic Peters <fpeters@entrouvert.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#
# Copyright (C) 2004 Entr'ouvert, Frederic Peters & Emmanuel Raviart
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

import os
import time

import libxml2

import expression.core.dataholders as dataholders
import expression.core.documents as documents
import expression.core.elements as elements
import expression.core.environs as environs
import expression.core.filesystems as filesystems
import expression.core.namespaces as namespaces
import expression.core.strings as strings


class Catalog(elements.Element):
    def __init__(self, node = None, previous = None, parent = None, uriPathFragment = None,
                 owner = "undefined"):
        elements.Element.__init__(
            self, node = node, previous = previous, parent = parent,
            uriPathFragment = uriPathFragment, owner = owner)
        if environs.getVar("inCatalog", default = False):
            return
        environs.setVar("inCatalog", True)
        
        rootElementName = self.evaluateXpath("yep:rootElementName")[0].content
        rootElementNamespace = self.evaluateXpath("yep:rootElementNamespace")[0].content

        doc = libxml2.newDoc('1.0') 
        rootNode = doc.newTextChild(None, rootElementName, None)
        rootNode.setNs(rootNode.newNs(rootElementNamespace, None))

        rootStation = environs.getVar("rootStation")
        if self.evaluateXpath("yep:root"):
            roots = []
            for x in self.evaluateXpath("yep:root"):
                if x.hasProp("rel") and x.prop("rel") == "relative":
                    baseStation = self.getParent().getParent()
                else:
                    baseStation = rootStation
                if not x.content:
                    roots.append( ("", baseStation) )
                    continue
                roots.append( (x.content, baseStation.walkToLocation(x.content)) )
        else:
            roots = [('', rootStation)]

        if self.evaluateXpath("yep:extensions"):
            extensions = [x.content for x in self.evaluateXpath("yep:extensions")]
        else:
            extensions = [".xml"]

        contentAllowedElements = None
        if self.evaluateXpath("yep:contentElementName"):
            contentAllowedElements = []
            for node in self.evaluateXpath("yep:contentElementName"):
                if node.hasProp("ns"):
                    ns = node.prop("ns")
                else:
                    ns = None
                contentAllowedElements.append( (ns, node.content) )

        maxModificationTime = 0
        t = self.evaluateXpath("yep:maxModificationTime[@type='abs']")
        if t:
            maxModificationTime = time.strptime(t[0].content, "%Y-%m-%d %H:%M:%S")
        else:
            t = self.evaluateXpath("yep:maxModificationTime[@type='rel']")
            if t:
                maxModificationTime = time.localtime(time.time() + float(t[0].content))

        minModificationTime = 0
        t = self.evaluateXpath("yep:minModificationTime[@type='abs']")
        if t:
            minModificationTime = time.strptime(t[0].content, "%Y-%m-%d %H:%M:%S")
        else:
            t = self.evaluateXpath("yep:minModificationTime[@type='rel']")
            if t:
                minModificationTime = time.localtime(time.time() + float(t[0].content))

        xpathExpression = None
        if self.evaluateXpath("yep:xpathExpression"):
            xpathExpression = self.evaluateXpath("yep:xpathExpression")[0].content

        pathDones = []
        everything = []
        for rootName, top in roots:
            if not top:
                continue
            filesystem = top.getFileSystem()
            path = top.getFileSystemPath()
            systemPath = os.path.normpath(os.path.join(filesystem.path, path))

            walkTuples = os.walk(systemPath)
            for t in walkTuples:
                for fileName in [x for x in t[2] if os.path.splitext(x)[1] in extensions]:
                    itemPath = os.path.join(systemPath, t[0], fileName)
                    if itemPath in pathDones:
                        continue
                    pathDones.append(itemPath)
                    if minModificationTime:
                        if filesystem.getModificationTime(itemPath) < minModificationTime:
                            continue
                    if maxModificationTime:
                        if filesystem.getModificationTime(itemPath) > maxModificationTime:
                            continue
                    item = dataholders.DataHolder(
                        pathFragment = itemPath, mimeType = "text/xml", isRootElder = True,
                        containedFileSystem = filesystems.PartialFileSystem(itemPath))
                    if not isinstance(item, dataholders.XmlHolder):
                        continue
                    rootElement = item.getRootElement()
                    if contentAllowedElements is not None:
                        node = rootElement.node
                        if (node.ns().content, node.name) not in contentAllowedElements and \
                                (None, node.name) not in contentAllowedElements:
                            continue
                    if xpathExpression and not item.evaluateXpath(xpathExpression):
                        continue
                    everything.append(rootElement)
                    rootElement.node.setProp("rootName", strings.simplify(rootName))

        if self.evaluateXpath("yep:sort"):
            elem = self.evaluateXpath("yep:sort")[0]
            sortKey, reverse = elem.content, elem.hasProp("reverse")
            everything.sort(lambda x,y: cmp(
                x.evaluateXpath(sortKey)[0].content,
                y.evaluateXpath(sortKey)[0].content))
            if reverse:
                everything.reverse()

        if self.evaluateXpath("yep:count"):
            everything = everything[:int(self.evaluateXpath("yep:count")[0].content)]

        for rootElement in everything:
            rootNode.addChild(rootElement.node)

        if self.evaluateXpath("yep:xsltParam"):
            d = {}
            for element in self.evaluateXpath("yep:xsltParam"):
                d[element.prop("name")] = repr(element.prop("value"))
            environs.setVar("xsltParams", d)

        elements.Element.__init__(
            self, node = rootNode, previous = previous, parent = parent,
            uriPathFragment = uriPathFragment, owner = owner)

        environs.setVar("inCatalog", False)

elements.registerElement(namespaces.yep.uri, "catalog", Catalog)
