# -*- coding: utf8 -*-
'''
ERROR CLASSES
**********************
***  ERROR CLASSES
**********************
$RCSfile: errorclasses.py,v $
$Revision: 911 $
$Author: markus $
$Date: 2008-04-30 23:52:39 +0200 (Mi, 30. Apr 2008) $

Custom errors and their logging message
'''

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

# --------------------------------------------------------------------------------
# SPECIFIC ERROR CLASSES WITH LOGGING ENABLED
# --------------------------------------------------------------------------------
#    LOG_LEVEL = {0:'critical', 1:'performance', 2:'simple debug', 3:'detailed debug'}




class PyWrapperError(Exception):
    def log(self):
        log.exception(self.msg)


class UnknownProtocolError(PyWrapperError):
    """Error raised because of an unknown protocol."""
    def __init__(self, protocol):
        self.code='REQ_UNKNOWN_PROTOCOL'
        self.msg='The requested protocol "%s" is unknown to the wrapper' %(protocol)
        self.log()
        

class NotPossibleToCreateDatasourceError(PyWrapperError):
    """Can't set datasource name. No PSF object created yet!"""
    def __init__(self, dsa):
        self.code='CFG_PSF_NOT_POSSIBLE_SET_DATASOURCE'
        self.msg='Cant create datasource %s. No PSF can be found!'%dsa
        self.log()


class PSFmissingError(PyWrapperError):
    """No PSF object created yet!"""
    def __init__(self):
        self.code='CFG_PSF_MISSING'
        self.msg='No PSF object created yet!'
        self.log()


class MappingObjectTypeNotSupportError(PyWrapperError):
    """A mapping object can only contain strings or dbattribute objects as items. Item should be a string or DBAttribute object."""
    def __init__(self):
        self.code='CFG_CMF_OBJ_NOT_SUPPORTED'
        self.msg='Error in the CMF. Mapping object can only contain strings or dbattribute objects as items.' 
        self.log()
    

class DbModuleNotSpecifiedError(PyWrapperError):
    """Database module not specified"""
    def __init__(self):
        self.code='DBS_DB_MODULE_NOT_SPECIFIED'
        self.msg='No database module has been specified.'
        self.log()


class DbModuleMissingError(PyWrapperError):
    """Database module missing"""
    def __init__(self, db_module):
        self.code='DBS_DB_MODULE_MISSING'
        self.msg='The database module %s is missing.' %(db_module)
        self.log()


class DbOperationNotSupportedError(PyWrapperError):
    """An operation, like alias or outer joins, are not supported by the database"""
    def __init__(self, operation, db_module):
        self.code='DBS_OPERATION_NOT_SUPPORTED'
        self.msg='The module/database %s does not support the next operation: %s' %(operation, db_module)
        self.log()
        

class CMFwrongDefinition(PyWrapperError):
    """Something is wrong defined in the CMF file"""
    def __init__(self, element, value, error_desc):
        self.code='CFG_CMF_WRONG_DEF'
        self.msg='There is a wrong definition a the %s element with value %s. Error: %s' %(element, value, error_desc)
        self.log()
    
            
#-----------------------------------------------------------------------

class DBComplexError(PyWrapperError):
    """temp error for too complex DBs not yet supported."""
    def __init__(self, name, table, attr):
        self.code='CFG_TOO_COMPLEX_DB'
        self.msg='Too complex DBs. Multiple tables linked to one repNode: %s.%s of element %s' %(attr,table,name)
        self.log()


class CGIError(PyWrapperError):
    """Exception raised for errors encountered while retrieving the CGI request XML document."""
    def __init__(self):
        self.code='REQ_NOT_REQUEST_SPECIFIED'
        self.msg='No request found. Search aborted.'
        self.log()


class CMFError(PyWrapperError):
    """Exception raised for errors trying to parse a CMF file."""
    def __init__(self, cmf='?'):
        self.code='CFG_CMF_FILE_CORRUPTED'
        self.msg='The CMF DB mapping file %s was corrupt or could not be interpreted.'%cmf
        self.log()


class CMFMaxAttributeError(PyWrapperError):
    """Exception raised for wrong CMF files, that have more DB attributes mapped to a non or too little repeatable element."""
    def __init__(self, xpath, no_is, no_max):
        self.code='CFG_CMF_MAX_ATTRIBUTE'
        self.msg='In your CMF file the element %s was assigned %s DB attributes, although its maximum repeatability is %s.'%(xpath, str(no_is), str(no_max))
        self.log()


class ConnectionError(PyWrapperError):
    """Exception raised for errors while establishing a DB connection."""
    def __init__(self, os=None, dbms=None):
        self.msg = "No DB connection could be established. Please verify DB state and connection parameters in your provider_setup_file.xml."
        if os!=None:
            self.code='PRG_WRONG_OS'
            self.msg+=" The Providers Operating System %s is not yet supported."%os
        if dbms!=None:
            self.code='PRG_WRONG_DBMS'
            self.msg+=" The Providers DBMS %s is not yet supported or it's database drivers are missing."%dbms
        self.log()


class CouldNotPickleError(PyWrapperError):
    """Could not pickle a file."""
    def __init__(self):
        pass

class MultipleCMFsWithSameNamespaceError(PyWrapperError):
    def __init__(self):
        self.code='CFG_MULTIPLE_CMF_NS'
        self.msg='Multiple CMFs with the same namespace are found in your datasource.'
        self.log()


class DBAttrObjError(PyWrapperError):
    """An expected DB-tuple was not found."""
    def __init__(self):
        self.code='DBS_MISSING_DB_TUPLE'
        self.msg='An expected DB-tuple was not found.'
        self.log()


class MissingRootTableError(PyWrapperError):
    """Exception raised for errors trying to parse a CMF file."""
    def __init__(self):
        self.code='PRG_CMF_MISSING_ROOT_TABLE'
        self.msg='The CMF DB mapping file does not contain a root table.'
        self.log()


class NoFilterError(PyWrapperError):
    """Exception raised for empty request filters."""
    def __init__(self):
        self.code='REQ_NO_FILTER'
        self.msg="No valid filter was given or all filter xpath expressions are unknown to this provider."
        self.log()


class ProviderSetupParseError(PyWrapperError):
    """Exception raised for errors encountered while parsing the ProviderSetup.xml file."""
    def __init__(self, filename):
        self.code='PRG_PSF_PARSING_ERROR'
        self.msg='The Provider Configuration could not be parsed. Please check if "%s" is accesible and a valid XML document.' %(filename)
        self.log()


class RequestParseError(PyWrapperError):
    """Exception raised for errors encountered while parsing the CGI request."""
    def __init__(self):
        self.code='REQ_PARSING_ERROR'
        self.msg='The request could not be parsed. Please check if it is a valid XML document.'
        self.log()


class RequestedSchemaError(PyWrapperError):
    """Exception raised for requested searches against schemas not supported by the provider."""
    def __init__(self, type, schema):
        self.code='REQ_UNKOWN_SCHEMA'
        self.msg='The requested ' +type +' schema "' +schema +'" is not supported by this provider! Please do a capabilities request to see all supported schemas'
        self.log()


class RequestUnknownTypeError(PyWrapperError):
    """Exception raised when encountering an unknown request type."""
    def __init__(self, type='unknown'):
        self.code='REQ_UNKNOWN_TYPE'
        self.msg="The request type '%s' is unknown. Fatal error." %type
        self.log()


class RequestUnknownConceptError(PyWrapperError):
    """Exception raised for requested searches referencing concepts not supported by the provider."""
    def __init__(self, concept):
        self.code='REQ_UNKNOWN_SEARCH_CONCEPT'
        self.msg='The requested concept %s is unknown to this provider! Please do a capabilities request to see all supported concepts' %(concept)
        self.log()


class RequestNotSearchableConceptError(PyWrapperError):
    """Exception raised for requested searches referencing concepts that are not searchable."""
    def __init__(self, concept):
        self.code='REQ_NOT_SEARCHABLE_CONCEPT'
        self.msg='The requested concept %s is not searchable for this provider! Please do a capabilities request to see all searchable concepts' %(concept)
        self.log()


class ResponseError(PyWrapperError):
    """Exception raised for errors encountered while creating the response object."""
    def __init__(self):
        self.code='RSP_NOT_DEFINED_ERROR_WHILE_PROCESSING'
        self.msg='The response object could not be properly established.'
        self.log()


class SQLError(PyWrapperError):
    """Exception raised for DB errors trying executing a SQL statement."""
    def __init__(self, sql='???', paras=None):
        self.code='DBS_SQL_EXEC'
        if paras is None:
            self.msg='A SQL statement produced an error: %s'%sql
        else:
            self.msg='A SQL statement with parameters produced an error: %s   parameter=%s'%(sql,str(paras))
        self.log()


class SQLgenerationError(PyWrapperError):
    """Exception raised for errors encountered while generating a SQL string."""
    def __init__(self):
        self.code='DBS_SQL_GENERATING'
        self.msg='The SQL string to query the DB could not be generated because an error occured.'
        self.log()


class SQLunicodeGenerationError(PyWrapperError):
    """Exception raised for non ANSI characters used in building a SQL string."""
    def __init__(self):
        self.code='DBS_NON_ASCII_CHAR_IN_COLUMNS'
        self.msg='The request, some tables or columns in your database contain non 7bit ASCII characters. Your DB driver cannot handle this !'
        self.log()


class StopSAX(PyWrapperError):
    """Exception raised to stop a SAX parser from parsing any further. No error but intention."""
    def __init__(self):
        pass

class TableConfigError(PyWrapperError):
    """Exception raised for any table configuration errors."""
    def __init__(self):
        self.code='CFG_PSF_TABLEALIAS_ERROR'
        self.msg='The PSF file contains tablealias declaration errors.'
        self.log()


class TableConfigAliasError(PyWrapperError):
    """Exception raised for Table configurations that have a non unique alias name."""
    def __init__(self, alias):
        self.code='CFG_PSF_NON_UNIQUE_TABLEALIAS'
        self.msg='The PSF configuration contains the non unique table-alias "'+alias +'". This is not allowed.'
        self.log()


class TableConfigCircleError(PyWrapperError):
    """Exception raised for Table configurations that have a circular structure."""
    def __init__(self,table):
        self.code='CFG_PSF_CIRCULAR_TABLES'
        self.msg= 'The PSF table configuration contains circular structures with table '+table+'. This is not allowed.'
        self.log()


class UnicodeError(PyWrapperError):
    """Exception raised because of unsupported Unicode funcionality."""
    def __init__(self):
        self.code='PRG_UNICODE_NOT_SUPPORTED'
        self.msg= 'The wrapper can not handle Unicode. Please wait for an improved version.'
        self.log()


class unknownEncodingError(PyWrapperError):
    """Exception raised for errors of unknown encoding entries in the providerConfig file."""
    def __init__(self, encoding):
        self.code='CFG_PSF_UNKNOWN_ENCODING'
        self.msg='Your Python installation does not your configured text-encoding "%s". Please check your providersetup.xml file.' %(encoding)
        self.log()


class unknownTypeError(PyWrapperError):
    """Exception raised for errors of unknown type parameters in SQL strings or DB results."""
    def __init__(self, value):
        self.code='PRG_UNKNOWN_TYPE_PARAMS'
        self.msg="The wrapper cannot deal with parameter of type %s." %(type(value))
        self.log()


class wrongXMLTypeError(PyWrapperError):
    """Exception raised for values of wrong type as specified in the XML schema."""
    def __init__(self, value, XMLtype):
        self.code='RSP_DB_XML_TYPE_CONVERSION_ERROR'
        self.msg= "Unable to convert the DB value '%s' into XML type %s" %(value, XMLtype)
        self.log()

                
class wrongTypeForDBError(PyWrapperError):

    """Exception raised for values that cannot be converted to a specified database type."""
    def __init__(self, value, DBtype):
        self.code='RSP_XML_DB_TYPE_CONVERSION_ERROR'
        try:
            self.msg= "Unable to convert the value '%s' into DB type %s" %(value, DBtype)
        except:
            self.msg= "Unable to convert a value into DB type %s" %(DBtype)
        self.log()
