# -*- coding: utf-8 -*-
from logger.log_repository import LogRepository
from mdstudio.api.api_result import APIResult
from mdstudio.api.comparison import Comparison
from mdstudio.api.endpoint import endpoint, cursor_endpoint
from mdstudio.api.exception import CallException
from mdstudio.component.impl.core import CoreComponentSession
from mdstudio.deferred.chainable import chainable
from mdstudio.deferred.return_value import return_value
from mdstudio.logging.log_type import LogType


class LoggerComponent(CoreComponentSession):
    # type: LogRepository
    logs = None

    # type: LoggerComponent.ComponentWaiter
    db_waiter = None
    # type: LoggerComponent.ComponentWaiter
    schema_waiter = None

    @chainable
    def on_run(self):
        yield self.call('mdstudio.auth.endpoint.ring0.set-status', {'status': True})
        yield super(LoggerComponent, self).on_run()

    def pre_init(self):
        self.logs = LogRepository(self.db)(self.grouprole_context('mdstudio', 'logger'))
        self.db_waiter = self.ComponentWaiter(self, 'db', self.group_context('mdstudio'))
        self.schema_waiter = self.ComponentWaiter(self, 'schema', self.group_context('mdstudio'))
        self.component_waiters.append(self.db_waiter)
        self.component_waiters.append(self.schema_waiter)

        super(LoggerComponent, self).pre_init()

    @cursor_endpoint('mdstudio.logger.endpoint.get-logs', 'get/logs-request/v1', 'get/logs-response/v1')
    def get_logs(self, request, claims, **kwargs):

        with self.grouprole_context('mdstudio', 'logger'):

            logfilter = {}
            if 'level' in request:
                logfilter['level'] = {
                    '${}'.format(Comparison.from_string(logfilter['level']['comparison'])): self._map_level(logfilter['level']['value'])
                }
            if 'source' in request:
                logfilter['source'] = {'$regex': logfilter['source']['pattern']}
                if 'options' in request['source']:
                    logfilter['source']['$options'] = request['source']['options']
            if 'time' in request:
                logfilter['time'] = {}
                if 'since' in request['time']:
                    logfilter['time']['$gte'] = request['time']['since']
                if 'until' in request['time']:
                    logfilter['time']['$lte'] = request['time']['until']
            if 'createdAt' in request:
                logfilter['createdAt'] = {}
                if 'since' in request['createdAt']:
                    logfilter['createdAt']['$gte'] = request['createdAt']['since']
                if 'until' in request['createdAt']:
                    logfilter['createdAt']['$lte'] = request['createdAt']['until']

            return self.logs.get(logfilter, claims, **kwargs)

    @endpoint('push-logs', 'push/logs-request/v1', 'push/logs-response/v1')
    @chainable
    def push_logs(self, request, claims=None):
        try:
            res = yield self.logs.insert(self._clean_claims(claims), [self._map_level(l) for l in request['logs']])
        except CallException as _:
            return_value(APIResult(error='The database is not online, please try again later.'))
        else:
            return_value({
                'inserted': len(res)
            })

    @endpoint('push-event', 'push/event-request/v1', 'push/event-response/v1')
    @chainable
    def push_event(self, request, claims=None):
        try:
            event = request['event']
            tags = event.pop('tags')
            res = yield self.logs.insert(self._clean_claims(claims), [self._map_level(event)], tags)
        except CallException as _:
            return_value(APIResult(error='The database is not online, please try again later.'))
        else:
            return_value(len(res))

    def authorize_request(self, uri, claims):
        connection_type = LogType.from_string(claims['logType'])

        if connection_type == LogType.User:
            return ('username' in claims) is True
        elif connection_type == LogType.Group:
            return ('group' in claims) is True
        elif connection_type == LogType.GroupRole:
            return all(key in claims for key in ['group', 'role'])

        return False

    @staticmethod
    def _map_level(log, from_int=False):
        from_map = {
            'debug': 0,
            'info': 10,
            'warn': 20,
            'error': 30,
            'critical': 40
        }
        to_map = {
            0: 'debug',
            10: 'info',
            20: 'warn',
            30: 'error',
            40: 'critical'
        }
        if from_int:
            log['level'] = to_map[log['level']]
        else:
            log['level'] = from_map[log['level']]
        return log

    @staticmethod
    def _clean_claims(claims):

        return claims

# -*- coding: utf-8 -*-
from logger.log_repository import LogRepository
from mdstudio.api.api_result import APIResult
from mdstudio.api.comparison import Comparison
from mdstudio.api.endpoint import endpoint, cursor_endpoint
from mdstudio.api.exception import CallException
from mdstudio.component.impl.core import CoreComponentSession
from mdstudio.deferred.chainable import chainable
from mdstudio.deferred.return_value import return_value
from mdstudio.logging.log_type import LogType


class LoggerComponent(CoreComponentSession):
    # type: LogRepository
    logs = None

    # type: LoggerComponent.ComponentWaiter
    db_waiter = None
    # type: LoggerComponent.ComponentWaiter
    schema_waiter = None

    @chainable
    def on_run(self):
        yield self.call('mdstudio.auth.endpoint.ring0.set-status', {'status': True})
        yield super(LoggerComponent, self).on_run()

    def pre_init(self):
        self.logs = LogRepository(self.db)(self.grouprole_context('mdstudio', 'logger'))
        self.db_waiter = self.ComponentWaiter(self, 'db', self.group_context('mdstudio'))
        self.schema_waiter = self.ComponentWaiter(self, 'schema', self.group_context('mdstudio'))
        self.component_waiters.append(self.db_waiter)
        self.component_waiters.append(self.schema_waiter)

        super(LoggerComponent, self).pre_init()

    @cursor_endpoint('mdstudio.logger.endpoint.get-logs', 'get/logs-request/v1', 'get/logs-response/v1')
    def get_logs(self, request, claims, **kwargs):

        with self.grouprole_context('mdstudio', 'logger'):

            logfilter = {}
            if 'level' in request:
                logfilter['level'] = {
                    '${}'.format(Comparison.from_string(logfilter['level']['comparison'])): self._map_level(logfilter['level']['value'])
                }
            if 'source' in request:
                logfilter['source'] = {'$regex': logfilter['source']['pattern']}
                if 'options' in request['source']:
                    logfilter['source']['$options'] = request['source']['options']
            if 'time' in request:
                logfilter['time'] = {}
                if 'since' in request['time']:
                    logfilter['time']['$gte'] = request['time']['since']
                if 'until' in request['time']:
                    logfilter['time']['$lte'] = request['time']['until']
            if 'createdAt' in request:
                logfilter['createdAt'] = {}
                if 'since' in request['createdAt']:
                    logfilter['createdAt']['$gte'] = request['createdAt']['since']
                if 'until' in request['createdAt']:
                    logfilter['createdAt']['$lte'] = request['createdAt']['until']

            return self.logs.get(logfilter, claims, **kwargs)

    @endpoint('push-logs', 'push/logs-request/v1', 'push/logs-response/v1')
    @chainable
    def push_logs(self, request, claims=None):
        try:
            res = yield self.logs.insert(self._clean_claims(claims), [self._map_level(l) for l in request['logs']])
        except CallException as _:
            return_value(APIResult(error='The database is not online, please try again later.'))
        else:
            return_value({
                'inserted': len(res)
            })

    @endpoint('push-event', 'push/event-request/v1', 'push/event-response/v1')
    @chainable
    def push_event(self, request, claims=None):
        try:
            event = request['event']
            tags = event.pop('tags')
            res = yield self.logs.insert(self._clean_claims(claims), [self._map_level(event)], tags)
        except CallException as _:
            return_value(APIResult(error='The database is not online, please try again later.'))
        else:
            return_value(len(res))

    def authorize_request(self, uri, claims):
        connection_type = LogType.from_string(claims['logType'])

        if connection_type == LogType.User:
            return ('username' in claims) is True
        elif connection_type == LogType.Group:
            return ('group' in claims) is True
        elif connection_type == LogType.GroupRole:
            return all(key in claims for key in ['group', 'role'])

        return False

    @staticmethod
    def _map_level(log, from_int=False):
        from_map = {
            'debug': 0,
            'info': 10,
            'warn': 20,
            'error': 30,
            'critical': 40
        }
        to_map = {
            0: 'debug',
            10: 'info',
            20: 'warn',
            30: 'error',
            40: 'critical'
        }
        if from_int:
            log['level'] = to_map[log['level']]
        else:
            log['level'] = from_map[log['level']]
        return log

    @staticmethod
    def _clean_claims(claims):

        return claims

# -*- coding: utf-8 -*- # type: LogRepository # type: LoggerComponent.ComponentWaiter # type: LoggerComponent.ComponentWaiter