from typing import Callable, Dict, List, Optional

from risc_lasagna.helper import (
    normalize_variable_prefix,
    prepend_variable_prefix,
    print_dict_like_list,
)
from risc_lasagna.layer.typedef import Layer


class DictLayer(Layer):
    """
    A very simple layer for loading dict configurations. Uses a dict as for it's basis.
    """

    def __init__(
        self,
        map_: Dict[str, any],
        variable_prefix: Optional[str] = None,
        capitalize_keys: bool = True,
        normalize_prefix: Callable[[str], str] = normalize_variable_prefix,
    ):
        self.map = map_
        self._variable_prefix = variable_prefix
        self._capitalize_keys = capitalize_keys
        self._normalize_prefix = normalize_prefix

    def get(self, key: str):
        """
        Searches for the key in the dict. Capitalizes the key if capitalize_keys is set to true in the constructor.
        Adds the prefix if variable_prefix is set in the constructor, the prefix is normalized with the
        normalize_prefix function.
        :param key: The string key
        :return: Returns the value of key if set otherwise None
        """
        return self.map.get(self._normalize_key(key), None)

    def keys(self) -> List[str]:
        """
        :return: Returns list of available keys
        """
        return list(self.map.keys())

    def _normalize_key(self, key: str) -> str:
        if self._capitalize_keys:
            key = key.upper()
        if self._variable_prefix is not None and not key.startswith(
            self._normalize_prefix(self._variable_prefix)
        ):
            # add prefix if not already added to key
            key = prepend_variable_prefix(
                self._normalize_prefix(self._variable_prefix), key
            )
        return key

    def contains(self, key: str) -> bool:
        return self._normalize_key(key) in self.map.keys()

    def __repr__(self):
        """
        :return: the representation of the layer
        """
        return print_dict_like_list(self.map, title=self.__class__.__name__.lstrip("_"))
