from parallels.common.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("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(
				"Can not replace entry point '%s' which does not exist" % name
			)
		self._entry_points[name] = entry_point

	def get_entry_point(self, name):
		if name not in self._entry_points:
			raise Exception(
				"Migrator internal error. "
				"Entry point with ID '%s' does not exist. "
				"Check entry point ID spelling, "
				"or add entry point with such ID to workflow." % (
				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(
				"Migrator internal error. "
				"Shared action with ID '%s' does not exist. "
				"Check action ID spelling, "
				"or add shared action with such ID to workflow." % (
					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(
				"Can not replace shared action: "
				"shared action with ID '%s' not found in workflow" % (
					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)
