# coding: utf-8
"""\
Пробуем упростить работу с объектами конфигурации при работе с приложениями.
"""
from threading import Lock
from typing import Optional, Dict

from .error import Error


class AppConfManagerError(Error):
    """\
    Базовый класс ошибок работы с хранилищем конфигураций
    """


class AppConfNotFound(AppConfManagerError):
    """\
    Исключение, возникающее когда в хранилище не найдена нужная конфигурация
    """


_CONFIG: Optional[Dict] = None
_CONFIG_GUARD = Lock()


def init_configs():
    """\
    Инициализируем хранилище конфигураций
    """
    global _CONFIG
    with _CONFIG_GUARD:
        if _CONFIG is None:
            _CONFIG = {}


def add_config(conf_selector, conf_obj):
    """\
    Добавляет в хранилище объект конфигурации. Затем его можно извлечь по селектору. Удобно указывать
    в качестве такого селектора класс, объектом которого является данный объект конфигурации
    """
    global _CONFIG
    with _CONFIG_GUARD:
        if _CONFIG is None:
            raise AppConfManagerError(f'При попытке добавить конфигурацию "{conf_selector}" в хранилище '
                                      f'оказалось, что оно не инициализировано')

        if conf_selector in _CONFIG:
            raise AppConfManagerError(f'Селектор "{conf_selector}" дублируется.')

        _CONFIG[conf_selector] = conf_obj


def replace_config(conf_selector, conf_obj):
    """\
    Заменяем добавленный ранее объект конфигурации
    """
    global _CONFIG
    with _CONFIG_GUARD:
        if _CONFIG is None:
            raise AppConfManagerError(f'При попытке заменить конфигурацию "{conf_selector}" в хранилище '
                                      f'оказалось, что оно не инициализировано')

        elif conf_selector in _CONFIG:
            _CONFIG[conf_selector] = conf_obj

        else:
            raise AppConfManagerError(f'Не найдена предыдущая конфигурация "{conf_selector}" при попытке её замены')


def del_config(conf_selector):
    """\
    Удаляет добавленный ранее объект конфигурации
    """
    global _CONFIG
    with _CONFIG_GUARD:
        if _CONFIG is None:
            raise AppConfManagerError(f'При попытке заменить конфигурацию "{conf_selector}" в хранилище '
                                      f'оказалось, что оно не инициализировано')

        elif conf_selector in _CONFIG:
            del _CONFIG[conf_selector]


def get_config(conf_selector):
    """\
    Получаем из хранилища добавленный ранее объект конфигурации по селектору.
    """
    if _CONFIG is None:
        raise AppConfManagerError('Попытка работать с неинициализированным хранилищем конфигураций')

    else:
        try:
            return _CONFIG[conf_selector]

        except KeyError:
            raise AppConfNotFound(f'Не найдена конфигурация "{conf_selector}" в хранилище')

        except (ValueError, TypeError) as e:
            raise AppConfManagerError(f'Ошибка получения конфигурации "{conf_selector}" из хранилища: {e}')
