import logging

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

###

L = logging.getLogger(__name__)

###


class ExpressionOptimizer(object):
	"""
	Optimizes an expression using walk strategy and individual optimize methods.
	"""

	def __init__(self, app):
		self.App = app


	def optimize(self, expression):

		# We run optimizations till we finish tree walk without any optimization found
		retry = True
		counter = 0
		while retry:
			retry = False

			counter += 1

			if not isinstance(expression, Expression):
				expression = VALUE(self.App, value=expression)

			# Walk the syntax tree
			for parent, key, obj in expression.walk():

				if not isinstance(obj, Expression):
					continue

				# Check if the node could be optimized
				opt_obj = obj.optimize()
				if opt_obj is None:
					continue

				assert(obj is not opt_obj)

				if parent is None:
					expression = opt_obj
				else:
					# If yes, replace a given node by the optimized variant
					parent.set(key, opt_obj)

				if counter > 100000:
					raise RuntimeError("Optimization likely stucked at '{}'-'{}'-'{}'/'{}'".format(parent, key, obj, opt_obj))

				# ... and start again
				retry = True
				break

		return expression


	def optimize_many(self, expressions):
		return [self.optimize(expression) for expression in expressions]
