# -*- coding: utf8 -*-
'''
R E Q U E S T - C L A S S
**********************************************
*       R E Q U E S T - C L A S S
*       base class for request parsers
**********************************************
$RCSfile: base_request.py,v $
$Revision: 878 $
$Author: markus $
$Date: 2008-04-24 18:57:28 +0200 (Do, 24. Apr 2008) $

Base class to generate a request object with the help of
a protocol specific request parser.
'''

import types
from xml.sax                            import parse, parseString
from biocase.wrapper.errorclasses        import *
from biocase.wrapper.sql.operators        import compressOperator
from biocase.wrapper.protocol.BioCASe.biocase_handler import filterHandler as defaultFilterHandler
from os import environ
import traceback

import biocase.configuration
cfg = biocase.configuration.Cfg()

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

# ------------------------------------------------------------------------------------
class RequestBaseClass(object):
    '''Base request class. Use a protocol parser to fill it.'''
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def __init__(self, dsaObj):
        # the datasource object (and through this also psfObj)
        self.dsaObj = dsaObj
        # PROPERTIES
        self.doc = u''          # holds the request as a string if protocol is string based
        # protocol header & logging information
        self.type = None        
        self.sources = []       
        # environment
        self.remoteHost = environ.get('REMOTE_ADDR', 'unknown Host')
        #
        # only for search requests:
        #---------------
        # info directly taken from request
        self.reqSchema = ''             # holds the name of the requested query-schema
        self.resSchema = ''             # holds the name of the requested response schema
        self.filter = None              # holds WhereClause object of filter part
        self.count = 0                  # only count results ? default = false(0)
        self.start = 0                  # start record of output
        self.limit = 0                  # number of records returned ( 0 = unlimited)
        self.scan  = ''                 # xpath to element meant for scanning (scan type only)

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def init(self, args):
        '''Override this method in the protocol specific request class to
        create the request object from passed parameters.'''
        # build request
        self.type = args.get('request_type', None)
        if self.type is not None:
            log.debug("A " +self.type +" response requested.")
        else:
            log.info("Unknown request type! Default to capabilities.")
            self.type='capabilities'
        self.sources = args.get('sources', [])
        self.reqSchema = args.get('request_schema', None)
        self.resSchema = args.get('response_schema', None)
        self.filter = args.get('filter_obj', None)
        self.count = args.get('count', 0)
        self.start = args.get('start', 0)
        self.limit = args.get('limit', 0)
        self.scan  = args.get('concept_to_scan', None)



    # METHODS CALLED BY PROTOCOL OBJECT.doResponse()
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def parseRequest(self, argHash=None, **args):
        '''Get a request, parse it & create a request object and then process it.'''
        if type(argHash) == types.DictType:
            args=argHash
        if len(args) < 1:
            # try to get the request from CGI environment
            args = self.getRequestHashFromCGI()
        # create request from request hash
        self.init(args)


    # OTHER METHODS
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def getRequestHashFromCGI(self):
        '''Override this method in the protocol specific request class to be able to get http based requests.'''
        raise "this protocol does not support http based requests."

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def areSchemasSupported(self, req=1, resp=0):
        ''' check if requested schemas are supported.
        Set req or resp flags to 1 to check for request or response respectively.'''
        if req == 1:
            if self.psfObj.schemas.has_key(self.resSchema):
                if self.psfObj.schemas[self.resSchema].response > 0:
                    return 1
            raise RequestedSchemaError("response", self.resSchema    )
        if resp == 1:
            if not(self.psfObj.schemas.has_key(schemaname) and self.psfObj.schemas[schemaname].request > 0):
                raise RequestedSchemaError("request", schemaname    )
        pass

    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def getFilterObjFromFilterString(self, CMFobj, filterString, filterHandler=defaultFilterHandler):
        ''' Construct the SQL WHERE clause filter object from the protocol/filter string passed.
        Defaults to the biocase protocol filter handler.
        Needs a CMFobject of the requested namespace.
        Takes care of global CMF filters for each COP generated.'''
        log.debug("Original filter string parsed: %s"%filterString)
        # build object with SAX Handler
        handler = filterHandler(CMFobj)
        parseString(filterString, handler)
        log.debug("Filter created: %s" %unicode(handler.filterObj))
        self.filter = compressOperator( handler.filterObj )
        log.debug("Compressed filter used: %s"%unicode(self.filter))
        return self.filter
                        
    # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    def getPsfObj(self):
        return self.dsaObj.getPSFObj()
    psfObj = property(getPsfObj)
