# -*- coding: utf-8 -*-
# Inspired by https://raw.githubusercontent.com/xeroc/python-graphenelib/master/graphenestorage/interfaces.py
class StoreInterface(dict):
    """The store interface is the most general store that we can have.

    It inherits dict and thus behaves like a dictionary. As such any
    key/value store can be used as store with or even without an adaptor.

    .. note:: This class defines ``defaults`` that are used to return
        reasonable defaults for the library.

    .. warning:: If you are trying to obtain a value for a key that does
        **not** exist in the store, the library will **NOT** raise but
        return a ``None`` value. This represents the biggest difference to
        a regular ``dict`` class.

    Methods that need to be implemented:

      * ``def setdefault(cls, key, value)``
      * ``def __init__(self, *args, **kwargs)``
      * ``def __setitem__(self, key, value)``
      * ``def __getitem__(self, key)``
      * ``def __iter__(self)``
      * ``def __len__(self)``
      * ``def __contains__(self, key)``


    .. note:: Configuration and Key classes are subclasses of this to allow
        storing keys separate from configuration.

    """

    defaults = {}

    @classmethod
    def setdefault(cls, key, value):
        """Allows to define default values"""
        cls.defaults[key] = value

    def __init__(self, *args, **kwargs):
        pass

    def __setitem__(self, key, value):
        """Sets an item in the store"""
        return dict.__setitem__(self, key, value)

    def __getitem__(self, key):
        """Gets an item from the store as if it was a dictionary

        .. note:: Special behavior! If a key is not found, ``None`` is
            returned instead of raising an exception, unless a default
            value is found, then that is returned.
        """
        if key in self:
            return dict.__getitem__(self, key)
        elif key in self.defaults:
            return self.defaults[key]
        else:
            return None

    def __iter__(self):
        """Iterates through the store"""
        return dict.__iter__(self)

    def __len__(self):
        """return lenght of store"""
        return dict.__len__(self)

    def __contains__(self, key):
        """Tests if a key is contained in the store."""
        return dict.__contains__(self, key)

    def items(self):
        """Returns all items off the store as tuples"""
        return dict.items(self)

    def get(self, key, default=None):
        """Return the key if exists or a default value"""
        return dict.get(self, key, default)

    # Specific for this library
    def delete(self, key):
        """Delete a key from the store"""
        raise NotImplementedError

    def wipe(self):
        """Wipe the store"""
        raise NotImplementedError


class KeyInterface(StoreInterface):
    """The KeyInterface defines the interface for key storage.

    .. note:: This class inherits
        :class:`nectarstorage.interfaces.StoreInterface` and defines
        additional key-specific methods.
    """

    def is_encrypted(self):
        """Returns True/False to indicate required use of unlock"""
        return False

    # Interface to deal with encrypted keys
    def getPublicKeys(self):
        """Returns the public keys stored in the database"""
        raise NotImplementedError

    def getPrivateKeyForPublicKey(self, pub):
        """Returns the (possibly encrypted) private key that
         corresponds to a public key

        :param str pub: Public key

        The encryption scheme is BIP38
        """
        raise NotImplementedError

    def add(self, wif, pub=None):
        """Add a new public/private key pair (correspondence has to be
         checked elsewhere!)

        :param str pub: Public key
        :param str wif: Private key
        """
        raise NotImplementedError

    def delete(self, pub):
        """Delete a pubkey/privatekey pair from the store

        :param str pub: Public key
        """
        raise NotImplementedError


class EncryptedKeyInterface(KeyInterface):
    """The EncryptedKeyInterface extends KeyInterface to work with encrypted
    keys
    """

    def is_encrypted(self):
        """Returns True/False to indicate required use of unlock"""
        return True

    def unlock(self, password):
        """Tries to unlock the wallet if required

        :param str password: Plain password
        """
        raise NotImplementedError

    def locked(self):
        """is the wallet locked?"""
        return False

    def lock(self):
        """Lock the wallet again"""
        raise NotImplementedError


class ConfigInterface(StoreInterface):
    """The BaseKeyStore defines the interface for key storage

    .. note:: This class inherits
        :class:`nectarstorage.interfaces.StoreInterface` and defines
        **no** additional configuration-specific methods.
    """

    pass


class TokenInterface(StoreInterface):
    """The TokenInterface defines the interface for token storage.

    .. note:: This class inherits
        :class:`nectarstorage.interfaces.StoreInterface` and defines
        additional key-specific methods.
    """

    def is_encrypted(self):
        """Returns True/False to indicate required use of unlock"""
        return False

    # Interface to deal with encrypted keys
    def getPublicKeys(self):
        """Returns the public keys stored in the database"""
        raise NotImplementedError

    def getPrivateKeyForPublicKey(self, pub):
        """Returns the (possibly encrypted) private key that
         corresponds to a public key

        :param str pub: Public key

        The encryption scheme is BIP38
        """
        raise NotImplementedError

    def add(self, wif, pub=None):
        """Add a new public/private key pair (correspondence has to be
         checked elsewhere!)

        :param str pub: Public key
        :param str wif: Private key
        """
        raise NotImplementedError

    def delete(self, pub):
        """Delete a pubkey/privatekey pair from the store

        :param str pub: Public key
        """
        raise NotImplementedError


class EncryptedTokenInterface(TokenInterface):
    """The EncryptedKeyInterface extends KeyInterface to work with encrypted
    tokens
    """

    def is_encrypted(self):
        """Returns True/False to indicate required use of unlock"""
        return True

    def unlock(self, password):
        """Tries to unlock the wallet if required

        :param str password: Plain password
        """
        raise NotImplementedError

    def locked(self):
        """is the wallet locked?"""
        return False

    def lock(self):
        """Lock the wallet again"""
        raise NotImplementedError
