"""Catalog module."""

from .providers import Provider
from .errors import Error


class AbstractCatalog(object):

    """Abstract object provides catalog."""

    __slots__ = ('__used_providers__',)

    def __init__(self, *used_providers):
        """Initializer."""
        self.__used_providers__ = set(used_providers)

    def __getattribute__(self, item):
        """Return providers."""
        attribute = super(AbstractCatalog, self).__getattribute__(item)
        if item in ('__used_providers__',):
            return attribute

        if attribute not in self.__used_providers__:
            raise Error('Provider \'{0}\' '.format(item) +
                        'is not listed in dependencies')
        return attribute

    @classmethod
    def all_providers(cls, provider_type=Provider):
        """Return set of all class providers."""
        providers = set()
        for attr_name in set(dir(cls)) - set(dir(AbstractCatalog)):
            provider = getattr(cls, attr_name)
            if not isinstance(provider, provider_type):
                continue
            providers.add((attr_name, provider))
        return providers

    @classmethod
    def override(cls, overriding):
        """
        Override current catalog providers by overriding catalog providers.

        :param overriding: AbstractCatalog
        """
        overridden = overriding.all_providers() - cls.all_providers()
        for name, provider in overridden:
            overridden_provider = getattr(cls, name)
            overridden_provider.override(provider)


def override(catalog):
    """Catalog overriding decorator."""
    def decorator(overriding_catalog):
        """Overriding decorator."""
        catalog.override(overriding_catalog)
        return overriding_catalog
    return decorator