from parallels.core import messages
from parallels.core.actions.base.action_pointer import ActionPointer


class BaseWorkflow(object):
	def __init__(self):
		self._entry_points = dict()
		self._shared_actions = dict()

	def add_entry_point(self, name, entry_point):
		if name in self._entry_points:
			raise Exception(messages.ENTRY_POINT_S_ALREADY_EXISTS % name)
		self._entry_points[name] = entry_point

	def replace_entry_point(self, name, entry_point):
		if name not in self._entry_points:
			raise Exception(
				messages.CAN_NOT_REPLACE_ENTRY_POINT_S % name
			)
		self._entry_points[name] = entry_point

	def get_entry_point(self, name):
		if name not in self._entry_points:
			raise Exception(
				messages.MIGRATOR_INTERNAL_ERROR_ENTRY_POINT_ID % (
				name
		))
		return self._entry_points[name]

	def get_entry_points(self):
		return self._entry_points

	def get_path(self, path):
		if '/' in path:
			entry_point, action_path = path.split('/', 1)
			return self.get_entry_point(entry_point).get_path(action_path)
		else:
			return self.get_entry_point(path)

	def get_shared_action(self, action_id):
		"""Get action shared between other actions from registry

		To use such action in other actions, you could use the code like
		the following:
		1) Add and configure action to the registry:
		self.add_common_action('common-action-1', CompoundAction())
		# configure action there
		2) Add it to workflow:
			self
				.get_path('entry-point/action1/subaction1')
				.get_common_action('common-action-1')
			You could add it multiple paths in workflow
		"""
		return self.get_shared_action_pointer(action_id).resolve()

	def get_shared_action_pointer(self, action_id):
		"""Get pointer to action shared between other actions from registry

		Pointer allows to link to shared action dynamically,
		so even if you replace an action, all usages of that pointer
		are up-to-date.

		To use such action in other actions, you could use the code like
		the following:
		1) Add and configure action to the registry:
		self.add_common_action('common-action-1', CompoundAction())
		# configure action there
		2) Add it to workflow:
			self
				.get_path('entry-point/action1/subaction1')
				.get_common_action('common-action-1')
			You could add it multiple paths in workflow
		"""
		if action_id not in self._shared_actions:
			raise Exception(
				messages.MIGRATOR_INTERNAL_ERROR_SHARED_ACTION_ID % (
					action_id
				)
			)
		return self._shared_actions[action_id]

	def add_shared_action(self, action_id, action):
		"""Add action that could be shared between other actions to registry

		To use such action in other actions, you could use the code like
		the following:
		1) Add and configure action to the registry:
		self.add_common_action('common-action-1', CompoundAction())
		# configure action there
		2) Add it to workflow:
			self
				.get_path('entry-point/action1/subaction1')
				.get_common_action('common-action-1')
			You could add it multiple paths in workflow
		"""
		self._shared_actions[action_id] = ActionPointer(action)

	def replace_shared_action(self, action_id, action):
		"""Replace existing shared action with another one

		See "add_shared_action" and "get_shared_action" functions for more details on
		shared actions.
		"""
		if action_id not in self._shared_actions:
			raise Exception(
				messages.CAN_NOT_REPLACE_SHARED_ACTION_SHARED % (
					action_id
				)
			)
		self._shared_actions[action_id].set(action)

	def insert_first_shared_action_to_all_entries(self, action_id, action):
		"""
		Method adds specified action to all entries at the first position in their actions list

		See "add_shared_action" and "get_shared_action" functions for more details on
		shared actions.

		:param action_id: string
		:param action: BaseAction instance of action
		:return: None
		"""
		for entry_point_action in self._entry_points.values():
			entry_point_action.insert_first_action(action_id, action)
