from parallels.core import messages
import logging

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.restore_hosting_utils import restore_hosting_settings_lock
from parallels.core.utils.common.threading_utils import synchronized_by_lock

logger = logging.getLogger(__name__)


class TransferErrorDocumentsBase(SubscriptionAction):
	def get_description(self):
		return messages.TRANSFER_CUSTOM_ERROR_DOCUMENTS

	def is_critical(self):
		"""If action is critical or not

		If action is critical and it failed for a subscription, migration tool
		won't run the next operations for the subscription.

		:rtype: bool
		"""
		return False

	def filter_subscription(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		if not subscription.is_windows:
			return False
		if not subscription.converted_backup.is_virtual_hosting:
			logger.debug(
				messages.SKIP_TRANSFER_CUSTOM_ERROR_DOCUMENTS_TYPES % subscription.name
			)
			return False
		return True

	def get_failure_message(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return messages.FAILED_TRANSFER_CUSTOM_ERROR_DOCUMENTS_FOR % subscription.name

	def run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		for site in subscription.converted_backup.iter_domains():
			if not site.is_virtual_hosting:
				logger.debug(
					messages.SKIP_TRANSFER_CUSTOM_ERROR_DOCUMENTS_FOR % (
						site.name, subscription.name
					)
				)
				continue

			with global_context.safe.try_subscription(
				subscription.name,
				messages.TRANSFER_CUSTOM_ERROR_DOCUMENTS_SITE_S % site.name,
				is_critical=False
			):
				self._transfer_site_error_documents(global_context, subscription, site)

	def _transfer_site_error_documents(self, global_context, subscription, site):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		vhost_error_documents = self._get_site_error_documents(global_context, subscription, site)
		vdirs_error_documents = self._get_site_vdir_error_documents(global_context, subscription, site)
		self._restore_site_error_documents(site, subscription, vdirs_error_documents, vhost_error_documents)

	@staticmethod
	# we need to use this lock because calling "websrvmng" when Plesk restore is running could
	# result in "Access is denied. (Error code 5) at create mutex Global" error
	@synchronized_by_lock(lock=restore_hosting_settings_lock)
	def _restore_site_error_documents(site, subscription, vdirs_error_documents, vhost_error_documents):
		with subscription.web_target_server.runner() as runner_target:
			if vhost_error_documents is not None:
				logger.debug(messages.RESTORE_ERROR_DOCUMENTS_VIRTUAL_HOSTS_ROOT)
				runner_target.sh(
					'{websrvmng_path} --set-error-docs --vhost-name={vhost_name} --error-docs="{error_docs}"'.format(
						websrvmng_path=subscription.web_target_server.websrvmng_bin, vhost_name=site.name.encode('idna'),
						error_docs=vhost_error_documents.replace('"', '\\"')
					))

			if vdirs_error_documents is not None:
				for vdir_name, vdir_error_documents in vdirs_error_documents.iteritems():
					logger.debug(messages.RESTORE_ERROR_DOCUMENTS_VIRTUAL_DIRECTORY_S, vdir_name)
					runner_target.sh(
						'{websrvmng_path} --set-error-docs --vhost-name={vhost_name} '
						'--vdir-name={vdir_name} --error-docs="{error_docs}"'.format(
							websrvmng_path=subscription.web_target_server.websrvmng_bin,
							vhost_name=site.name.encode('idna'), vdir_name=vdir_name,
							error_docs=vdir_error_documents.replace('"', '\\"')
						))

	def _get_site_error_documents(self, global_context, subscription, site):
		"""
		Override in child classes

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return None

	def _get_site_vdir_error_documents(self, global_context, subscription, site):
		"""
		Override in child classes

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		return None
