from parallels.core import messages
import logging

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.plesk_utils import set_mime_types
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 TransferMIMETypesBase(SubscriptionAction):
	def get_description(self):
		return "Transfer MIME types"

	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_MIME_TYPES_FOR_SUBSCRIPTION % 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_MIME_TYPES_FOR_SUBSCRIPTION % subscription.name

	def run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		logger.debug(messages.TRANSFER_MIME_TYPES_FOR_SITES_SUBSCRIPTION % subscription.name)

		for site in subscription.converted_backup.iter_domains():
			if not site.is_virtual_hosting:
				logger.debug(
					messages.SKIP_TRANSFER_MIME_TYPES_FOR_SITE % (
						site.name, subscription.name
					)
				)
				continue

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

	def _transfer_site_mime_types(self, global_context, subscription, site):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		# Get MIME types from source panel
		vhost_mime_types = self._get_site_mime_types(global_context, subscription, site)
		vdirs_mime_types = self._get_site_vdir_mime_types(global_context, subscription, site)

		# Set MIME types on target panel
		self._restore_site_mime_types(site, subscription, vdirs_mime_types, vhost_mime_types)

	@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_mime_types(site, subscription, vdirs_mime_types, vhost_mime_types):
		if vhost_mime_types is not None:
			logger.debug(messages.RESTORE_MIME_TYPES_VIRTUAL_HOSTS_ROOT)
			set_mime_types(
				subscription.web_target_server, site.name,
				vhost_mime_types
			)
		if vdirs_mime_types is not None:
			for vdir_name, vdir_mime_types in vdirs_mime_types.iteritems():
				logger.debug(messages.RESTORE_MIME_TYPES_VIRTUAL_DIRECTORY_S, vdir_name)
				set_mime_types(
					subscription.web_target_server, site.name,
					vdir_mime_types, vdir_name
				)

	def _get_site_mime_types(self, global_context, subscription, site):
		"""Get MIME types of a site

		Override in child classes.

		Returns dictionary with keys - extensions, values - corresponding MIME types.
		If there are no MIME types for a site - returns None (default behavior)

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

	def _get_site_vdir_mime_types(self, global_context, subscription, site):
		"""Get MIME types of all virtual directories inside a site

		Override in child classes.

		Returns dictionary with:
		- key - virtual directory path (as it is presented on target server)
		- value - dictionary with:
			- key - extensions
			- values - corresponding MIME types
		If there are no virtual directories with MIME types - returns None (default behavior)

		The dictionary looks in the following way:
		{
			virtual directory name: {
				extension: mime type
			}
		}

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