from ...abc import Expression
from ..value.valueexpr import VALUE


class CONTEXT(Expression):
    """
    The current context.

    Usage:
    ```
    !CONTEXT
    ``
    """

    Attributes = {}

    def __init__(self, app, *, value):
        super().__init__(app)
        assert value == ""

    def __call__(self, context, event, *args, **kwargs):
        return context


class CONTEXT_SET(Expression):
    Attributes = {
        "What": ["*"],  # TODO: This ...
    }

    def __init__(self, app, *, arg_set, arg_what=None):
        super().__init__(app)
        self.What = arg_what

        self.ArgSet = arg_set
        self.Set = None

    def set(self, key, value):
        setattr(self, key, value)

        if "Set" in key:
            self.Set[key[3:]] = value

    def initialize(self):
        if self.ArgSet is None:
            self.Set = None
        else:
            assert isinstance(self.ArgSet, dict)
            self.Set = dict()
            self._set_value_or_expression_to_attribute(self.ArgSet, self.Set, "Set")

    def _set_value_or_expression_to_attribute(self, _from, _to, name):
        for key, value in _from.items():
            # Parse value to attribute, if not expression
            if isinstance(value, Expression):
                _to[key] = value
            else:
                assert (
                    isinstance(value, (int, str, bytes, bool, tuple, list))
                    or value is None
                )
                value = VALUE(self.App, value=value)
                _to[key] = value

            # Set the value to the class attribute
            attr_name = "{}{}".format(name, key)
            setattr(self, attr_name, value)
            self.Attributes[attr_name] = value.get_outlet_type()

    def __call__(self, context, event, *args, **kwargs):
        if self.Set is not None:
            for key, value in self.Set.items():
                v = value(context, event, *args, **kwargs)
                if v is not None:
                    context[key] = v

        # TODO: Optimize
        if self.What is None:
            return None

        return self.What(context, event, *args, **kwargs)
