"""@package docstring
B-ASIC Core Operations Module.
TODO: More info.
"""

from numbers import Number

from b_asic.port import InputPort, OutputPort
from b_asic.operation import Operation
from b_asic.abstract_operation import AbstractOperation
from b_asic.abstract_graph_component import AbstractGraphComponent
from b_asic.graph_component import Name, TypeName


class Input(Operation, AbstractGraphComponent):
	"""Input operation.
	TODO: More info.
	"""

	# TODO: Implement all functions.

	@property
	def type_name(self) -> TypeName:
		return "in"


class Constant(AbstractOperation):
	"""Constant value operation.
	TODO: More info.
	"""

	def __init__(self, value: Number, **kwds):
		"""Construct a Constant."""
		super().__init__(**kwds)
		self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.
		self._parameters["value"] = value

	def evaluate(self, inputs: list) -> list:
		return [self.param("value")]

	@property
	def type_name(self) -> TypeName:
		return "const"


class Addition(AbstractOperation):
	"""Binary addition operation.
	TODO: More info.
	"""

	def __init__(self, **kwds):
		"""Construct an Addition."""
		super().__init__(**kwds)
		self._input_ports = [InputPort(1, self), InputPort(1, self)] # TODO: Generate appropriate ID for ports.
		self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.

	def evaluate(self, inputs: list) -> list:
		return [inputs[0] + inputs[1]]

	@property
	def type_name(self) -> TypeName:
		return "add"


class ConstantMultiplication(AbstractOperation):
	"""Unary constant multiplication operation.
	TODO: More info.
	"""

	def __init__(self, coefficient: Number, **kwds):
		"""Construct a ConstantMultiplication."""
		super().__init__(**kwds)
		self._input_ports = [InputPort(1), self] # TODO: Generate appropriate ID for ports.
		self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.
		self._parameters["coefficient"] = coefficient

	def evaluate(self, inputs: list) -> list:
		return [inputs[0] * self.param("coefficient")]

	@property
	def type_name(self) -> TypeName:
		return "const_mul"