import logging
import ntpath

from parallels.core.actions.content.web.copy_windows_content_base import TargetWebPathConverter, PathWindowsRsyncAdapter
from parallels.core.utils.paths import web_paths
from parallels.plesk.source.custom import messages
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils.paths.copy_web_content import BaseWebPathConverter
from parallels.core.utils.windows_utils import cmd_command, convert_path_to_cygwin
from parallels.core.windows_rsync import RsyncInstaller

from parallels.plesk.source.custom.web_files import CustomPanelWebFiles

logger = logging.getLogger(__name__)


class CustomPanelCopyWindowsWebContentLocal(SubscriptionAction):
	"""Put Windows web files that are already on target server to correct locations

	This action is applicable when access to the server was not provided in configuration file, and customer
	has already copied files from the source server to the target server
	"""

	def get_description(self):
		"""Get short description of action as string

		:rtype: str
		"""
		return messages.ACTION_COPY_LOCAL_WEB_FILES

	def get_failure_message(self, global_context, subscription):
		"""Get message for situation when action failed

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

	def filter_subscription(self, global_context, subscription):
		"""Check if we should run this action on given subscription or not

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.plesk.source.custom.migrated_subscription.CustomPanelMigratedSubscription
		"""
		return (
			global_context.conn.has_hosting_description_config(subscription.model.source)
			and
			# source web server is not specified, we don't have access to it, so
			# if customer has specified some files to copy, we consider that they all are already
			# on the target server
			subscription.web_source_server is None
			and
			subscription.web_target_server is not None
			and
			subscription.is_windows
		)

	def run(self, global_context, subscription):
		"""Run action on given subscription

		:type global_context: parallels.core.global_context.GlobalMigrationContext
		:type subscription: parallels.plesk.source.custom.migrated_subscription.CustomPanelMigratedSubscription
		"""
		files = CustomPanelWebFiles().list_files_to_copy(global_context, subscription)

		rsync_installer = RsyncInstaller(subscription.web_target_server)
		base_path = rsync_installer.install()

		for item in files:
			cmd = cmd_command(
				u'{rsync_bin} --no-perms -t -r {source_path} {target_path}'
			)
			if item.exclude is not None and len(item.exclude) > 0:
				cmd += u"".join([u" --exclude %s" % ex for ex in item.exclude])
			server = subscription.web_target_server
			with subscription.web_target_server.runner() as runner:
				runner.sh(
					cmd, args=dict(
						rsync_bin=ntpath.join(base_path, 'panel-migrator-rsync.exe'),
						source_path=LocalSourceRsyncWebPathConverter().expand(item.source_path, server),
						target_path=PathWindowsRsyncAdapter(TargetWebPathConverter()).expand(item.target_path, server)
					)
				)


class LocalSourceRsyncWebPathConverter(BaseWebPathConverter):
	"""Class to convert abstract path descriptor to concrete path for rsync on source server"""

	def expand(self, path, server):
		"""Convert abstract path descriptor to concrete absolute path for source server

		:type path: parallels.core.utils.web_paths.WebHostingPath
		:rtype: str | unicode
		"""
		if isinstance(path, web_paths.AbsolutePath):
			return convert_path_to_cygwin(path.absolute_path) + '/'
		else:
			assert False, messages.UNSUPPORTED_SOURCE_WEB_PATH_TYPE