# -*- coding: utf8 -*-
'''
**********************************************
*       P R O T O C O L - C L A S S
*       for the biocase protocol
**********************************************
$RCSfile: biocase_request.py,v $
$Revision: 878 $
$Author: markus $
$Date: 2008-04-24 18:57:28 +0200 (Do, 24. Apr 2008) $

Request and Response classes to support the biocase protocol.
'''

import types
from xml.sax                        import parse, parseString
from cgi                            import FieldStorage
from biocase.wrapper.errorclasses    import *
from biocase.wrapper.protocol.base_request     import RequestBaseClass
from biocase.wrapper.protocol.BioCASe.biocase_handler import requestHandler


import logging
log = logging.getLogger("pywrapper.protocol.biocase")

# ------------------------------------------------------------------------------------
class RequestClass(RequestBaseClass):
    '''REQUEST class, based on the BioCASE Unitlevel Access Protocol version.'''
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def __init__(self, dsaObj):
        # init base class
        RequestBaseClass.__init__(self, dsaObj)
        
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def parseRequest(self, args):
        '''Parses the request hash "args" and fills this object.'''
        # test for CGI parameters:
        if len(args) < 1 or (len(args) < 2 and args.has_key('dsa') ) or (len(args) < 3 and args.has_key('dsa') and args.has_key('debug') ):
            args = self.getRequestHashFromCGI()
        if len(args.get('request_string',"")) > 0:
            # a full request string exists. parse it directly.
            # use base class method to check for debugging
            # store request string for optional logging
            self.doc = args['request_string']
            # parse the string
            self.parseRequestString(args['request_string'])
        else:
            # seems to be seperate parameters. Use default base class routine
            RequestBaseClass.init(self, args)

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def getRequestHashFromCGI(self, querystringParameters=('query', 'request','search','protocol','biocase','doc') ):
        '''Get the request hash from GET/POST.
        querystringParameters can optionally be set to other parameter names than the default ones.'''
        reqHash={} # resulting hash
        querystring = FieldStorage()
        # 1. get all GET/POST parameters into the hash
        keys = querystring.keys()
        for k in keys:
            reqHash[k]=querystring.getfirst(k)
        # 2. locate and add the XML request string with special care.
        if 1 in [querystring.has_key(key) for key in querystringParameters]:
            # The request has a known parameter:
            for para in querystringParameters:
                if querystring.has_key(para):
                    reqHash['request_string'] = querystring.getfirst(para)
                    log.info("HTTP parameter '%s' used for building the request." %(para))
                    break
        log.debug("All parameters found in the request: %s" %unicode(reqHash) )
        return reqHash

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def parseRequestString(self, RequestString):
        '''parse request string to fill the object.
        If no proper request was found, it defaults to a capabilities request.'''
        # test if request was found.
        # do a capabilities request by default
        if RequestString == None:
            self.type = "capabilities"
            log.info("No request found. Do a default capabilities request.")
        else:
            # parse xml and set object properties
            try:
                handler = requestHandler(self)
                parseString(RequestString, handler)
            except:
                raise RequestParseError()
        #
        #Things to do after parsing the request. Even when this failed.
        # check if host who send the query included itself in the protocol sources
        if len(self.sources) == 0 or self.sources[0].lower()<>self.remoteHost.lower():
            self.sources.append(self.remoteHost)
        # inverse sequence of sources so the last source(closest) is first now
        if len(self.sources) > 0:
            self.sources.reverse()
        # timestamp
        log.debug("parse request")


