# -*- coding: utf-8 -*-
import abc
import re
from pg_requests.exceptions import TokenError
from pg_requests.operators import ConditionOperator, And, QueryObject, Evaluable


class TokenValue(Evaluable):
    """Base class of a parseable unit"""

    def __init__(self, value):
        self.value = self.validate(value)

    @abc.abstractmethod
    def eval(self):
        """Evaluate value depends on the type of it
        For example:
            IterableValue --> ','.join(self.value)

        """
        pass

    def validate(self, value):
        """Validation method. Override it if needed.
        It must return validated value
        """
        return value

    def update(self, value):
        """Update method. By default just replaces old value with a given one

        :param value:
        """
        self.value = self.validate(value)

    def __repr__(self):
        return "%s(value=%s)" % (self.__class__.__name__, self.value)


class Token(Evaluable):
    """Query token representation"""

    TEMPLATE_RE = re.compile(r'\{.*\}')

    def __init__(self, template, value_type, required=False, subtoken=None):
        """

        :param template: str: token template
        :param value: any token value
        """
        self._value = None
        self.value_type = self._validate_value_type(value_type)
        self.template = self._validate_template(template, self.value_type)
        self.is_set = False
        self.required = required
        self.subtoken = self._validate_subtoken(subtoken)

    @classmethod
    def _validate_template(cls, template, value_type):
        """Validate template value

        :param template: str
        :param value_type: TokenValue subclass
        :return: :raise ValueError:
        """
        # Exclude null value checks
        if issubclass(value_type, NullValue):
            return template
        elif not cls.TEMPLATE_RE.search(template):
            raise ValueError("Template must contain '{}'")