import re
import urllib.parse

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


class RegexABCParser(object):

	def __init__(self, app, regex):
		self.Regex = re.compile(regex)

	def __call__(self, context, value):
		return dict(self.Regex.findall(value))


class KeyValueSpaceParser(RegexABCParser):

	def __init__(self, app):
		super().__init__(app, r"\b(\w+)=(.*?)(?=\s\w+=\s*|$)")


class KeyValueDoubleQuotesSpaceParser(RegexABCParser):

	def __init__(self, app):
		super().__init__(app, r'\b(\w+)="(.*?)(?="\s\w+=\s*|"$)')


class QueryStringParser(object):

	def __init__(self, app):
		pass

	def __call__(self, context, value):
		return dict(urllib.parse.parse_qsl(value))


class DICT_PARSE(Expression):

	Attributes = {
		"Value": ["*"],  # TODO: This ...
		"Type": ["*"],  # TODO: This ...
		"Unset": [],  # TODO: This ...
		"Update": ["*"],  # TODO: This ...
	}

	def __init__(self, app, *, arg_what, arg_type=None, arg_set=None, arg_unset=None, arg_update=None):
		super().__init__(app)

		self.Value = arg_what
		self.Type = arg_type
		self.Parser = {
			'kvs': KeyValueSpaceParser,
			'kvdqs': KeyValueDoubleQuotesSpaceParser,
			'qs': QueryStringParser,
		}.get(arg_type, 'kvs')(app)

		self.ArgSet = arg_set
		self.Set = None

		if arg_unset is not None:
			assert(isinstance(arg_unset, list))
		self.Unset = arg_unset

		self.Update = arg_update

	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):
		value = self.Value(context, event, *args, **kwargs)
		ret = self.Parser(context, value)

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

		if self.Update is not None:
			update_dict = self.Update(context, event, ret, *args, **kwargs)
			if update_dict is not None and update_dict is not False:
				ret.update(update_dict)

		if self.Unset is not None:
			for key in self.Unset:
				ret.pop(key, None)

		return ret
