########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Http/__init__.py,v 1.13 2005/04/06 06:19:15 mbrown Exp $
"""
HTTP and SOAP server for the repostiory

Copyright 2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

__all__ = ['FtServerHttpException', 'HttpModule']

import os

from Ft.Server import FtServerBaseException
from Ft.Server import SCHEMA_NSS
from Ft.Server.Common import Schema
from Ft.Server.Server import FTSERVER_SERVER_NS, Module

import MessageSource


class FtServerHttpException(FtServerBaseException):
    """
    Exception class for errors specific to the HTTP and SOAP servers
    """
    MessageSource = MessageSource

Error = MessageSource.Error


import Basic

class HttpModule(Module):

    commands = {
        (FTSERVER_SERVER_NS, 'DocumentRoot'): 'setDocumentRoot',
        (FTSERVER_SERVER_NS, 'Redirect'): 'setRedirect',
        (FTSERVER_SERVER_NS, 'AuthName'): 'setAuthName',
        (FTSERVER_SERVER_NS, 'MandatoryAuth'): 'setMandatoryAuth',
        (FTSERVER_SERVER_NS, 'DefaultXslt'): 'setDefaultXslt',
        (FTSERVER_SERVER_NS, 'SessionMethod'): 'setSessionMethod',
        (FTSERVER_SERVER_NS, 'SessionUserName'): 'setSessionUserName',
        (FTSERVER_SERVER_NS, 'SessionPassword'): 'setSessionPassword',
        (FTSERVER_SERVER_NS, 'SessionTtl'): 'setSessionTtl',
        (FTSERVER_SERVER_NS, 'SessionAnonymousFlag'): 'setSessionAnonymousFlag',
        (FTSERVER_SERVER_NS, 'SessionInvalidUri'): 'setSessionInvalidUri',
        (FTSERVER_SERVER_NS, 'SessionLoginUri'): 'setSessionLoginUri',
        (FTSERVER_SERVER_NS, 'SessionInvalidLoginUri'): 'setSessionInvalidLoginUri',
        (FTSERVER_SERVER_NS, 'SessionPermissionDeniedUri'): 'setSessionPermissionDeniedUri',
        (FTSERVER_SERVER_NS, 'Rule'): 'setRule',
        (FTSERVER_SERVER_NS, 'HttpPostEncodingVar'): 'setHttpPostEncodingVar',
        }

    handlers = {'http_basic' : Basic.BasicHttpHandler}

    def initialize(self, parser, config):
        # initialize container-style properties
        config.redirects = {}
        config.defaultXslt = {}
        config.processing_rules = []
        return

    def setDocumentRoot(self, parser, config, name, data, attrs):
        if not data:
            raise ValueError('%s requires path argument' % name)

        if data[0] != '/':
            raise ValueError('%s path must be absolute' % name)

        # Normalize it, borrowed mostly from posixpath.normpath()
        steps = []
        comps = data.split('/')
        for comp in comps:
            if comp in ('', '.'):
                # Either a duplicate slash ('') or a do nothing step
                continue
            if comp != '..':
                steps.append(comp)
            elif steps:
                # A dot-dot, remove previous path
                steps.pop()
        path = '/'.join(steps)
        if path:
            config.documentRoot = '/' + path
        else:
            config.documentRoot = ''
        return

    def setRedirect(self, parser, config, name, data, attrs):
        if not data:
            raise ValueError('%s requires path argument' % name)

        try:
            src = attrs[(None, 'src')]
        except KeyError:
            raise ValueError('%s must have src attribute' % name)

        if not src[0] == '/':
            raise ValueError('%s src must be absolute' % name)

        config.redirects[src] = data
        return

    def setAuthName(self, parser, config, name, data, attrs):
        config.authName = data
        return

    def setMandatoryAuth(self, parser, config, name, data, attrs):
        config.mandatoryAuth = data
        return

    def setDefaultXslt(self, parser, config, name, data, attrs):
        try:
            rdf_type = attrs[(None, 'type')]
        except KeyError:
            raise ValueError('%s must have type attribute' % name)

        try:
            resource_type = Schema.g_resourceTypeFromRdf[SCHEMA_NSS + rdf_type]
        except KeyError:
            print "Unknown Type mapping: %s" % rdf_type
        else:
            config.defaultXslt[resource_type] = str(data)
        return

    def setSessionMethod(self, parser, config, name, data, attrs):
        config.session_method = data
        return

    def setSessionUserName(self, parser, config, name, data, attrs):
        config.session_user_name = data
        return

    def setSessionPassword(self, parser, config, name, data, attrs):
        config.session_password = data
        return

    def setSessionTtl(self, parser, config, name, data, attrs):
        config.session_ttl = data
        return

    def setSessionAnonymousFlag(self, parser, config, name, data, attrs):
        config.session_anonymous_flag = data
        return

    def setSessionInvalidUri(self, parser, config, name, data, attrs):
        config.session_invalid_uri = data
        return

    def setSessionPermissionDeniedUri(self, parser, config, name, data, attrs):
        config.session_permission_denied_uri = data
        return

    def setSessionLoginUri(self, parser, config, name, data, attrs):
        config.session_post_login_uri_qs = data
        return

    def setSessionInvalidLoginUri(self, parser, config, name, data, attrs):
        config.session_post_invalid_login_uri_qs = data
        return

    def setRule(self, parser, config, name, data, attrs):
        try:
            pattern = attrs[(None, 'pattern')]
        except KeyError:
            raise ValueError('%s must have pattern attribute' % name)

        source = attrs.get((None, 'xslt-source'))

        try:
            transform = attrs[(None, 'xslt-transform')]
        except KeyError:
            raise ValueError('%s must have xslt-transform attribute' % name)

        args = attrs.get((None, 'extra-args'), '')
        chain = attrs.get((None, 'chain-multiple-transforms'), 'yes')

        rule = (pattern, source, transform, args, chain)
        config.processing_rules.append(rule)
        return

    def setHttpPostEncodingVar(self, parser, config, name, data, attrs):
        config.http_post_encoding_var = data
        return


## This stuff needs to be added to the HttpModule

##class ConfigParser(BaseConfigParser):

##    entries = BaseConfigParser.entries + ['LogFormat',
##                                          'TransferLog']

##    required_entries = BaseConfigParser.required_entries + ['DocumentRoot']

##    # Overridden
##    def setup(self):
##        # Ensure that these will be in list format
##        self.config['LogFormat'] = []
##        self.config['TransferLog'] = []
##        return

##    # Overridden
##    def finish(self):
##        self._finish_formats()
##        self._finish_logs()
##        return

##    def handle_LogFormat(self, node):
##        name = node.getAttributeNS('', 'name')
##        if not name:
##            print 'LogFormat missing (or empty) required name attribute'
##            return
##        format = self._handle_unknown(node)
##        if not format:
##            return None
##        return (name, format)

##    def handle_TransferLog(self, node):
##        format = node.getAttributeNS('', 'format')
##        if not format:
##            format = 'common'
##        logfile = self._handle_unknown(node)
##        if not logfile:
##            return None
##        return (format, logfile)

##    def _finish_formats(self):
##        log_formats = self.config['LogFormat']
##        formats = {}
##        for name, format in log_formats:
##            formats[name] = format

##        # Add default formats if not already provided
##        if not formats.has_key('common'):
##            formats['common'] = TransferLog.COMMON_LOG_FORMAT
##        if not formats.has_key('combined'):
##            formats['combined'] = TransferLog.COMBINED_LOG_FORMAT

##        self.config['LogFormat'] = formats
##        return

##    def _finish_logs(self):
##        # Make sure that the log formats are already processed
##        if type(self.config['LogFormat']) is not type({}):
##            self._finish_formats()

##        formats = self.config['LogFormat']
##        transfers = self.config['TransferLog']
##        accesses = []
##        for name, filename in transfers:
##            # The controller ensures that each filename has only one lock
##            # and that the filename is absolute
##            filename, lock = self.controller.getFileLock(filename)
##            format, fields = TransferLog.MakeFormatString(formats[name])
##            accesses.append((filename, lock, format, fields))

##        self.config['TransferLog'] = accesses
##        return

