from Ft.Xml import Sax
from Ft.Xml.InputSource import DefaultFactory
from Ft.Server.Server import FTSERVER_SERVER_NS        

import Modules, ServerConfig

class ConfigParser:

    def __init__(self):
        # All servers support the core interface
        core = Modules.CoreModule()
        self._modules = [core]
        self._limitedNss = [FTSERVER_SERVER_NS]
        return

    def addModule(self, module):
        if not issubclass(module, Modules.Module):
            raise Exception('module is not of type ' + str(Modules.Module))
        added = module()
        self._modules.append(added)

        # Search for defined namespaces in commands
        for (namespace, name) in added.commands.keys():
            if namespace not in self._limitedNss:
                self._limitedNss.append(namespace)

        added.initialize(self, self.config)
        return

    def findHandler(self, name):
        # Modules added later have higher precedence
        for i in range(0, len(self._modules)+1):
            module = self._modules[-i]
            if module.handlers.has_key(name):
                return module.handlers[name]

        # Nothing found, signal such
        raise Exception("Invalid handler '%s', perhaps mis-spelled "
                        "or defined by a module not included in the "
                        "server configuration" % name)

    def findCommand(self, qname, nameparts):
        # Modules added later have higher precedence
        for i in range(0, len(self._modules)+1):
            module = self._modules[-i]
            if module.commands.has_key(nameparts):
                cmd = module.commands[nameparts]
                start = end = None
                if isinstance(cmd, (tuple, list)):
                    start = getattr(module, cmd[0])
                    cmd = cmd[1]
                if cmd is not None:
                    end = getattr(module, cmd)
                return (start, end)

        # Nothing found, signal such
        raise Exception("Invalid command '%s', perhaps mis-spelled "
                        "or defined by a module not included in the "
                        "server configuration" % qname)

    def startDocument(self):
        self._processing = []
        return

    def endDocument(self):
        del self._processing
        return

    def startElementNS(self, (namespaceURI, localName), qualifiedName, attrs):
        if namespaceURI in self._limitedNss:
            startFunc, endFunc = self.findCommand(qualifiedName,
                                                  (namespaceURI, localName))
            startFunc and startFunc(self, self.config, qualifiedName, attrs)
        else:
            endFunc = None

        self._processing.append([(endFunc, qualifiedName, attrs)])
        return

    def endElementNS(self, (namespaceURI, localName), qualifiedName):
        parts = self._processing.pop()

        command, qname, attrs = parts[0]

        # Concatenate text chunks and remove leading & trailing whitespace
        data = ''.join(parts[1:]).strip()

        command and command(self, self.config, qname, data, attrs)
        return
        
    def characters(self, data):
        self._processing[-1].append(data)
        return

    def readConfig(self, path, source):
        self.config = ServerConfig.ServerConfig(path)

        # Create an InputSource to pass to the parser
        isrc = DefaultFactory.fromString(source, path)
        
        parser = Sax.CreateParser()
        parser.setContentHandler(self)
        parser.parse(isrc)
        
        return self.config
