#
# Copyright 2018 Ettus Research, a National Instruments Company
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
MPM preferences management
"""

import configparser
from usrp_mpm.mpmlog import TRACE, DEBUG, INFO, WARNING, ERROR, CRITICAL

# Store the global preferences object
_PREFS = None

### MPM defaults ##############################################################
MPM_DEFAULT_CONFFILE_PATH = '/etc/uhd/mpm.conf'
MPM_DEFAULT_LOG_LEVEL = 'info'
MPM_DEFAULT_LOG_BUF_SIZE = 100 # Number of log records to buf

# ConfigParser has too many parents for PyLint's liking, but we don't control
# that, so disable that warning
# pylint: disable=too-many-ancestors
class _MPMPrefs(configparser.ConfigParser):
    """
    Container for MPM preferences.

    On initialization, it will read preferences from the system-wide config
    file, if available, and from environment variables.
    Settings can be updated at any time (e.g., because want to factor in
    command line arguments).

    This class also encodes default prefs in the self.default_prefs dictionary.
    Said dictionary needs to be compatible with the ConfigParser.read_dict()
    API call (refer to the Python documentation).
    """
    # Note: When changing this, you might also want to update host/docs/configfiles.dox
    default_prefs = {
        'mpm': {
            'log_level': MPM_DEFAULT_LOG_LEVEL,
            'log_buf_size': MPM_DEFAULT_LOG_BUF_SIZE,
        },
        'overrides': {
            'override_db_pids': '',
        },
    }

    def __init__(self):
        configparser.ConfigParser.__init__(self)
        self.read_dict(self.default_prefs)
        self._errors = []
        try:
            self.read(MPM_DEFAULT_CONFFILE_PATH)
        except configparser.Error as ex:
            self._errors.append('Config file parsing error: {}'.format(str(ex)))

    def get_log_level(self):
        """
        Return the selected default log level as an integer, usable by the
        logging API. This is a safe call, it will always return a useful value.
        Because this gets called as part of the logging API, it can't log any
        error messages. It will store them in the object itself under the
        __ERRORS__ section, key 'log_level'.
        """
        log_level = self.get('mpm', 'log_level').lower()
        log_level_map = {
            'trace': TRACE,
            'debug': DEBUG,
            'info': INFO,
            'warning': WARNING,
            'error': ERROR,
            'critical': CRITICAL,
        }
        if log_level not in log_level_map:
            self._errors.append('Invalid log level: {}'.format(log_level))
            # Note: After this function returns, we can use the logger so we
            # don't need to use this awkward side channel anymore!
        return log_level_map.get(
            log_level,
            log_level_map[MPM_DEFAULT_LOG_LEVEL]
        )

    def get_log_errors(self):
        """
        Returns errors that were generated during init but couldn't be logged
        because the logger isn't ready yet.
        """
        return self._errors
# pylint: enable=too-many-ancestors

def get_prefs():
    """
    Return singleton preferences object. It's an object of type ConfigParser.
    """
    global _PREFS
    if _PREFS is None:
        _PREFS = _MPMPrefs()
    return _PREFS
