from parallels.plesk.source.plesk import messages
import logging
import posixpath

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.common import replace_str_prefix
from parallels.core.utils import subscription_filter

logger = logging.getLogger(__name__)


class FixUnixPermissions(SubscriptionAction):
	"""Fix file ownership for files in domain directory after moving."""
	def get_description(self):
		return messages.ACTION_FIX_UNIX_PERMISSIONS_DESCRIPTION

	def get_failure_message(self, global_context, subscription):
		return messages.ACTION_FIX_UNIX_PERMISSIONS_FAILED % subscription.name

	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
		"""
		return subscription_filter.unix_with_virtual_hosting(
			subscription
		)

	def run(self, global_context, subscription):
		"""
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		"""
		sysuser_name = subscription.converted_dump.get_phosting_sysuser_name()
		if sysuser_name is None:
			return

		logger.debug(messages.LOG_FIX_FILE_OWNERSHIP_AFTER_MOVING)
		with subscription.web_source_server.runner() as runner_source:
			source_sysuser_name = subscription.raw_dump.get_phosting_sysuser_name()
			source_vhost_dir = global_context.dump_agent.get_vhosts_dir(source_sysuser_name)
			sysuser_files_string = runner_source.run(
				'/usr/bin/find', [source_vhost_dir, '-user', source_sysuser_name]
			)
		source_sysuser_files = filter(None, sysuser_files_string.split('\n'))
		target_vhost_dir = posixpath.join(
			subscription.web_target_server.vhosts_dir, 
			subscription.name_idn
		) 
		domain_xml_node = subscription.converted_dump.node
		psaserv_group_files = self._get_psaserv_group_files(domain_xml_node, target_vhost_dir)
		for filename in source_sysuser_files:
			target_filename = replace_str_prefix(filename, source_vhost_dir, target_vhost_dir)
			if target_filename in psaserv_group_files:
				group = 'psaserv'
			else:
				group = 'psacln'
			with subscription.web_target_server.runner() as runner_target:
				args = dict(filename=target_filename, username=sysuser_name, group=group)
				runner_target.sh(
						"test ! -e {filename} || test -L {filename}"
						"|| /bin/chown {username}:{group} {filename}", args)

	def _get_psaserv_group_files(self, domain_xml_node, vhost_dir):
		"""Return a list of absolute filenames, which group should be set to 'psaserv'."""
		psaserv_directories = ['./'] # include the vhost directory itself
		for xpath in ('.//phosting', './/subdomain'):
			directories = [x.attrib['www-root'] for x in domain_xml_node.findall(xpath)]
			psaserv_directories.extend(directories)
		for xpath in ('.//phosting[@cgi_bin_mode="www-root"]', './/subdomain'):
			directories = [x.attrib['www-root'] for x in domain_xml_node.findall(xpath)]
			cgi_directories = [posixpath.join(d, 'cgi-bin') for d in directories]
			psaserv_directories.extend(cgi_directories)
		return self._prepend_path(vhost_dir, psaserv_directories)

	def _prepend_path(self, absolute_path, relative_dirnames):
		"""Prepend each relative UNIX directory in the list with the given absolute path."""
		raw_filenames = [posixpath.join(absolute_path, d) for d in relative_dirnames]
		return [posixpath.normpath(f) for f in raw_filenames]

