"""Base classes."""

import abc

from . import common

log = common.logger(__name__)


class Mappable(metaclass=abc.ABCMeta):

    """Base class for objects with attributes that map to YAML."""

    def __getattribute__(self, name):
        if name.startswith('yorm_'):
            return object.__getattribute__(self, name)

        try:
            value = object.__getattribute__(self, name)
        except AttributeError:
            self.yorm_mapper.fetch(self, self.yorm_attrs)
            value = object.__getattribute__(self, name)
        else:
            if name in self.yorm_attrs:
                self.yorm_mapper.fetch(self, self.yorm_attrs)
                value = object.__getattribute__(self, name)

        return value

    def __setattr__(self, name, value):
        if hasattr(self, 'yorm_attrs') and name in self.yorm_attrs:
            converter = self.yorm_attrs[name]
            value = converter.to_value(value)

        object.__setattr__(self, name, value)

        if hasattr(self, 'yorm_attrs') and name in self.yorm_attrs:
            if hasattr(self, 'yorm_mapper') and self.yorm_mapper.auto:
                self.yorm_mapper.store(self, self.yorm_attrs)
            else:
                log.trace("automatic storage is off")

    def __enter__(self):
        log.debug("turning off automatic storage...")
        self.yorm_mapper.auto = False

    def __exit__(self, *_):
        log.debug("turning on automatic storage...")
        self.yorm_mapper.store(self, self.yorm_attrs)


class Converter(metaclass=abc.ABCMeta):

    """Base class for attribute converters."""

    TYPE = None  # type for inferred converters (set in subclasses)
    DEFAULT = None  # default value for conversion (set in subclasses)

    @abc.abstractclassmethod
    def to_value(cls, obj):  # pylint: disable=E0213
        """Convert the loaded value back to its original attribute type."""
        raise NotImplementedError("method must be implemented in subclasses")

    @abc.abstractclassmethod
    def to_data(cls, obj):  # pylint: disable=E0213
        """Convert the attribute's value for optimal dumping to YAML."""
        raise NotImplementedError("method must be implemented in subclasses")
