from bspump.declarative.abc import Expression

from ..value.eventexpr import ARG
from ..value.valueexpr import VALUE

import logging

#

L = logging.getLogger(__name__)

#


class CAST(Expression):
	"""
	Casts "value" to "type"
	"""

	Attributes = {
		"What": ["*"],
		"Default": ["*"],
	}

	CastMap = {
		'bool': (bool, bool.__name__),
		'ui1': (bool, bool.__name__),
		'si1': (bool, bool.__name__),

		'int': (int, int.__name__),
		'si8': (int, 'si8'),
		'si16': (int, 'si16'),
		'si32': (int, 'si32'),
		'si64': (int, 'si64'),
		'si128': (int, 'si128'),
		'si256': (int, 'si256'),

		'ui8': (int, 'ui8'),
		'ui16': (int, 'ui16'),
		'ui32': (int, 'ui32'),
		'ui64': (int, 'ui64'),
		'ui128': (int, 'ui128'),
		'ui256': (int, 'ui256'),

		'float': (float, float.__name__),
		'fp16': (float, float.__name__),
		'fp32': (float, float.__name__),
		'fp64': (float, float.__name__),
		'fp128': (float, float.__name__),

		'str': (str, str.__name__),
		'dict': (dict, dict.__name__),
		'list': (list, list.__name__),

	}


	def __init__(self, app, *, arg_what=None, arg_type=None, arg_default=None, value=None):
		super().__init__(app)

		if value is not None:
			# Scalar variant
			# TODO (Dec 2020, AT): This one (scalar variant) is weird, not sure if used anywhere

			self.What = ARG(app=app, value='')
			self.Conversion, self.OutletType = self.CastMap[value]

		else:
			if isinstance(arg_what, Expression):
				self.What = arg_what
			else:
				self.What = VALUE(app, value=arg_what)

			# Detect type cast function
			self.Conversion, self.OutletType = self.CastMap[arg_type]


		if isinstance(arg_default, Expression):
			self.Default = arg_default
		else:
			self.Default = VALUE(app, value=arg_default)


	def __call__(self, context, event, *args, **kwargs):
		try:
			return self.Conversion(self.What(context, event, *args, **kwargs))
		except (ValueError, AttributeError, TypeError):
			if self.Default is None:
				return None
			return self.Default(context, event, *args, **kwargs)


	def get_outlet_type(self):
		return self.OutletType


	def consult_inlet_type(self, key, child):
		return self.OutletType
