# auto generated by update_py.py
import datetime
import logging
import logging.config
import os
import queue
from logging.handlers import QueueHandler, QueueListener

from .utility import get_log_default_path


class Logger:

    LogConfig = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '[%(asctime)s.%(msecs)03d] [%(name)s] [%(levelname)s] [%(filename)s:%(lineno)s] %(message)s',
                'datefmt': '%Y-%m-%d %H:%M:%S'
            }
        },
        'filters': {},
        'handlers': {
            'console': {
                'level': None,
                'class': 'logging.StreamHandler',
                'formatter': 'standard'
            },
            'file': {
                'level': None,
                'class': 'logging.handlers.TimedRotatingFileHandler',
                'filename': None,
                'formatter': 'standard',
                'encoding': 'utf-8',
                'when': 'MIDNIGHT',
                'interval': 1,
                'backupCount': 21,
            }
        },
        'loggers': {
            '': {
                'handlers': ['file', 'console'],
                'level': 'NOTSET',
                'propagate': True
            }
        }
    }

    @classmethod
    def _get_log_level_from_env(cls, env_name, default_level=logging.DEBUG):
        log_level = os.environ.get(env_name)
        if log_level:
            log_level = log_level.lower()

        if log_level == "off":
            return logging.CRITICAL
        elif log_level == "critical":
            return logging.CRITICAL
        elif log_level == "err":
            return logging.ERROR
        elif log_level == "warn":
            return logging.WARNING
        elif log_level == "info":
            return logging.INFO
        elif log_level == "debug":
            return logging.DEBUG
        elif log_level == "trace":
            return logging.NOTSET
        else:
            return default_level

    @classmethod
    def _get_log_path_from_env(cls):
        log_path = os.environ.get("FILE_LOG_PATH") or get_log_default_path()
        if not os.path.exists(log_path):
            os.makedirs(log_path)
        if not os.path.isdir(log_path):
            raise TypeError("The log path '{}' is not a directory.".format(log_path))
        return log_path

    @classmethod
    def get_logger(cls, name, async_logging=True):
        cls.LogConfig['handlers']['file']['filename'] = os.path.join(cls._get_log_path_from_env(), '{}.log'.format(name))
        cls.LogConfig['handlers']['console']['level'] = cls._get_log_level_from_env('CONSOLE_LOG_LEVEL', logging.ERROR)
        cls.LogConfig['handlers']['file']['level'] = cls._get_log_level_from_env('FILE_LOG_LEVEL', logging.INFO)
        logging.config.dictConfig(cls.LogConfig)
        if async_logging:
            cls.make_handlers_async()
        return logging.getLogger(name)

    @staticmethod
    def _select_and_disable_console_handler(hdlrs):
        for hdlr in hdlrs:
            if hdlr.name == 'console':
                hdlr.setStream(open('/dev/null', 'w'))
            if isinstance(hdlr, QueueHandler):
                Logger._select_and_disable_console_handler(hdlr.listener.handlers)

    @staticmethod
    def redirect_console_handler_to_DEVNULL():
        root_logger = logging.getLogger()
        Logger._select_and_disable_console_handler(root_logger.handlers)

    @staticmethod
    def make_handlers_async():
        ''' warp root logger's handlers with a queued handler '''
        root_logger = logging.getLogger()
        assert not any([isinstance(h, QueueHandler) for h in root_logger.handlers]), 'exists handlers which have already been made async'
        q = queue.Queue()
        qhandler = QueueHandler(q)
        qhandler.listener = QueueListener(q, *root_logger.handlers, respect_handler_level=True)
        qhandler.listener.start()
        root_logger.handlers = [qhandler]

    @staticmethod
    def stop_async_handlers():
        ''' stop queued handler and flush all pending logs '''
        root_logger = logging.getLogger()
        for hdlr in root_logger.handlers:
            if isinstance(hdlr, QueueHandler):
                hdlr.listener.stop()
