from containers.DeviceContainer import DeviceContainer
from dbconnectors.DeviceDB import DeviceDB
from containers.DataContainer import DataContainer
from dbconnectors.DataDB import DataDB
from AccessController import AccessController
import settings
import traceback

class Handler:    
    
    def __init__(self, req_msg):
        
        self.request_msg = req_msg
        self.response_msg = ''
            
    def __del__(self):
        pass
        #self.logger.debug("__del__ Handler")
        #del self.logger
    
    # handles <setDevice>
    def handleSetDevice(self):

        settings.logger.debug('Handler: entered handleSetDevice()')

        deviceContainer = DeviceContainer()
        deviceContainer.setResponseTypeNode('setDevice')
        
        # there are two ways an invalid xml message can manifest: missing XML node or
        # missing attribute. The first causes a parsing exception but a missing attribute 
        # has to be caught manually by checking the parsed values for None-values
    
        try:
            deviceContainer.readXMLSetRequest(self.request_msg)               
        except Exception as e:
            settings.logger.error(str(e))
            deviceContainer.appendStatusCodeNode('INVALID_XML')
            self.response_msg=deviceContainer.getResponseMsg()
            return 

        if deviceContainer.invalidXMLFlag:
            deviceContainer.appendStatusCodeNode('INVALID_XML')
            self.response_msg = deviceContainer.getResponseMsg()
            return 
        
        
        # check if an empty string was found when reading the attribute values 
        if deviceContainer.missingValue!=None:
            deviceContainer.appendStatusCodeNode('MISSING_' + deviceContainer.missingValue.upper())
            self.response_msg = deviceContainer.getResponseMsg()
            return 
        
        newFormatStr = '%(asctime)s - ' + deviceContainer.loggerId + ' - %(process)s - %(name)s - %(levelname)s - %(message)s'
        settings.logger.changeFormatter(newFormatStr)
        
        try:
            settings.logger.debug('Access control')
            accessCntr = AccessController(deviceContainer.auth, deviceContainer.loggerId) 
            permissionCheck = accessCntr.check_auth()
            # check permission
            if not permissionCheck:
                settings.logger.error('AUTHENTICATION_FAIL for user with token: ' + deviceContainer.auth)
                deviceContainer.appendStatusCodeNode('AUTHENTICATION_FAIL')
                self.response_msg = deviceContainer.getResponseMsg()
                return 
            
            # check if logger exists; if not - return a 'LOGGER_NOT_ASSIGNED' status code
            loggerCheck = accessCntr.check_logger()
            if not loggerCheck:
                settings.logger.debug('LOGGER_NOT_ASSIGNED for logger ' + deviceContainer.loggerId + ' and token ' + deviceContainer.auth)
                deviceContainer.appendStatusCodeNode('LOGGER_NOT_ASSIGNED')
                self.response_msg = deviceContainer.getResponseMsg()
                return
            
            routingInfoDict = accessCntr.get_routing_info()
            accessCntr.disconnect()
        except Exception as e:
            settings.logger.error(str(e))
            deviceContainer.appendStatusCodeNode('AUTHENTICATION_FAIL')
            self.response_msg = deviceContainer.getResponseMsg()
            return
            
        # check permission
        if not permissionCheck:
            settings.logger.error('AUTHENTICATION_FAIL for user with token: ' + deviceContainer.auth)
            deviceContainer.appendStatusCodeNode('AUTHENTICATION_FAIL')
            self.response_msg = deviceContainer.getResponseMsg()
            return 
                    
        
        # try writing the data into the DB 
        try:
            master_db_info = routingInfoDict.get('master')
            settings.logger.debug('Handler: building DeviceDB connector for master db ' + master_db_info.get('db_name'))
            connector = DeviceDB(master_db_info.get('host'), master_db_info.get('username'),
                                master_db_info.get('psw'), master_db_info.get('db_name'))
            connector.connect()
            listStatusCodes = connector.setData(deviceContainer)
            connector.disconnect()
            
            deviceContainer.listStatusCodes.update(listStatusCodes)
            deviceContainer.writeXMLSetResponse()
            
            for mirror_db_info in routingInfoDict.get('mirror'):
                settings.logger.info('Handler: building DataDB connector for mirror db ' + mirror_db_info.get('db_name'))
                connector = DeviceDB(mirror_db_info.get('host'), mirror_db_info.get('username'),
                                mirror_db_info.get('psw'), mirror_db_info.get('db_name'))
                connector.connect()
                connector.setData(deviceContainer)
                connector.disconnect()
        except Exception as e:
            settings.logger.error(str(e))
            deviceContainer.appendStatusCodeNode('SERVER_SIDE_ERROR')
            self.response_msg = deviceContainer.getResponseMsg()
            return
            
        self.response_msg = deviceContainer.getResponseMsg()

    # handles <setData>
    def handle_set_data(self):
        settings.logger.debug('Handler: entered handleSetData()')  
        dataContainer = DataContainer()
        dataContainer.setResponseType('setData')
        
        # there are two ways an invalid xml message can manifest: missing XML node or
        # missing attribute. The first causes a parsing exception but a missing attribute 
        # has to be caught manually by checking the parsed values for None-values
        try:
            dataContainer.readSetXMLRequest(self.request_msg)
        except Exception as e:
            settings.logger.error(str(e))
            dataContainer.responseAppendStatusCodeNode('INVALID_XML')
            self.response_msg = dataContainer.getResponseMsg()
            return 
        if dataContainer.invalidXMLFlag:            
            dataContainer.responseAppendStatusCodeNode('INVALID_XML')
            self.response_msg = dataContainer.getResponseMsg()
            return 

        # check if an empty string was found when reading the attribute values        
        if dataContainer.missingValue!=None:
            dataContainer.responseAppendStatusCodeNode('MISSING_' + dataContainer.missingValue.upper())
            self.response_msg = dataContainer.getResponseMsg()
            return  

        newFormatStr = '%(asctime)s - ' + dataContainer.loggerId + ' - %(process)s - %(name)s - %(levelname)s - %(message)s'
        settings.logger.changeFormatter(newFormatStr)

	# check if the authentication token and the user in the request message are valid
        # by querying the authentication table
        try:
            accessCntr = AccessController(dataContainer.auth, dataContainer.loggerId ) 
            permissionCheck = accessCntr.check_auth()
            if not permissionCheck:
                settings.logger.debug('AUTHENTICATION_FAIL for user  with token ' + dataContainer.auth)
                dataContainer.responseAppendStatusCodeNode('AUTHENTICATION_FAIL')
                self.response_msg = dataContainer.getResponseMsg()
                return 
            
            # check if logger exists; if not - return a 'LOGGER_NOT_ASSIGNED' status code
            loggerCheck = accessCntr.check_logger()
            if not loggerCheck:
                settings.logger.debug('LOGGER_NOT_ASSIGNED for logger ' + dataContainer.loggerId + ' and token ' + dataContainer.auth)
                dataContainer.responseAppendStatusCodeNode('LOGGER_NOT_ASSIGNED')
                self.response_msg = dataContainer.getResponseMsg()
                return
            routingInfoDict = accessCntr.get_routing_info()
            accessCntr.disconnect()
        except Exception as e:
            print str(e)
            settings.logger.error(str(e))
            dataContainer.responseAppendStatusCodeNode('AUTHENTICATION_FAIL')
            self.response_msg = dataContainer.getResponseMsg()
            return
         
        # try writing the data into the DB    
        try:
            master_db_info = routingInfoDict.get('master')
            settings.logger.debug('Handler: building DataDB connector for master db ' + master_db_info['db_name'])
            connector = DataDB(master_db_info.get('host'), master_db_info.get('username'),
                                master_db_info.get('psw'), master_db_info.get('db_name'))
            
            connector.connect()        
            listFailed = connector.setData(dataContainer)
            connector.disconnect()
            
            dataContainer.writeXMLSetResponse(listFailed)
            
            for mirror_db_info in routingInfoDict.get('mirror'):
                settings.logger.info('Handler: building DataDB connector for mirror db ' + mirror_db_info.get('db_name'))
                connector = DataDB(mirror_db_info.get('host'), mirror_db_info.get('username'),
                                mirror_db_info.get('psw'), mirror_db_info.get('db_name'))
                connector.connect()
                connector.setData(dataContainer)
                connector.disconnect()
                
                
        except Exception as e:
            settings.logger.error(str(e))
            settings.logger.error(traceback.format_exc())
            dataContainer.responseAppendStatusCodeNode('SERVER_SIDE_ERROR')
            self.response_msg = dataContainer.getResponseMsg()
            return 
            
        self.response_msg = dataContainer.getResponseMsg()
        
    '''def handleSetLogger(self): 
        
        settings.logger.info('enetered setLogger()')
        
        
        loggerContainer = LoggerContainer()
        loggerContainer.setResponseTypeNode('setLogger')
        
        try:
            loggerContainer.readXMLSetRequest(self.request_msg)
        except Exception as e:
            settings.logger.error('Handler: Failed parsing msg: ' + str(e))
            loggerContainer.responseAppendStatusCodeNode('INVALID_XML')
            self.response_msg = loggerContainer.getResponseMsg()
            return
        
        if loggerContainer.invalidXMLFlag:
            loggerContainer.responseAppendStatusCodeNode('INVALID_XML')
            self.response_msg = loggerContainer.getResponseMsg()
            return
        
        if loggerContainer.missingValue!=None:
            settings.logger.error('Handler: MISSING_' + loggerContainer.missingValue.upper())
            loggerContainer.responseAppendStatusCodeNode('MISSING_' + loggerContainer.missingValue.upper())
            self.response_msg = loggerContainer.getResponseMsg()
            return
        
        settings.logger.info('Handler: checking auth token...')
        # check if the authentication token and the user in the request message are valid
        # by querying the authentication table
        try:
            accessCntr = AccessController(loggerContainer.auth, )   
            permissionCheck = accessCntr.checkAuth()          
        except Exception as e:
            settings.logger.error(str(e))
            loggerContainer.responseAppendStatusCodeNode('SERVER_SIDE_ERROR')
            self.response_msg = loggerContainer.getResponseMsg()
            return

        if not permissionCheck:
            settings.logger.info('AUTHENTICATION_FAIL for user with token ' + loggerContainer.auth)
            loggerContainer.responseAppendStatusCodeNode('AUTHENTICATION_FAIL')
            self.response_msg = loggerContainer.getResponseMsg()
            return 
        
        settings.logger.info('Handler: getting routing data...')
        routingConnector = RoutingDB(settings.hostname, settings.username, settings.psw, settings.commondb)
        try:         
            routingConnector.getConnection()
            for log in loggerContainer.listLogger:   
                log.routingInfo = routingConnector.getData(log.id, accessCntr.defaulDB)         
        except Exception as e:
            settings.logger.error('Handler: ' + str(e))
            loggerContainer.responseAppendStatusCodeNode('SERVER_SIDE_ERROR')
            self.response_msg = loggerContainer.getResponseMsg()
            return                               
           
        loggerConnector = LoggerDB(settings.hostname, settings.username, settings.psw)
        
        loggerConnector.getConnection()

        try:
            listFailed = loggerConnector.setData(loggerContainer)
            settings.logger.info('listFailed: ' + str(listFailed))  
            loggerContainer.writeXMLSetResponse(listFailed) 
        except Exception as e:
            settings.logger.error('Handler: ' + str(e)) 
            loggerContainer.responseAppendStatusCodeNode('SERVER_SIDE_ERROR')
            self.response_msg = loggerContainer.getResponseMsg()
            return
        
        self.response_msg = loggerContainer.getResponseMsg()  '''
        
    '''def generateLoggerSerial(self):
        
        randomSerial = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(10)])
        
        
        response = "<response></response>" '''
    
    def print_response(self):
        
        #print "Content-type: application/xml"
        #print "Status: 200"
        #print
        print self.response_msg
