from parallels.plesk.source.plesk import messages
import logging
import re
import xml.etree.ElementTree as et

from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.utils import subscription_filter
from parallels.plesk.source.plesk.actions.content.web.utils import list_security_files
from parallels.core.utils import windows_utils

logger = logging.getLogger(__name__)


class FixSecurityFiles(SubscriptionAction):
	def get_description(self):
		return messages.ACTION_FIX_SECURITY_FILES_DESCRIPTION

	def get_failure_message(self, global_context, subscription):
		return messages.ACTION_FIX_SECURITY_FILES_FAILURE % 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.windows_with_virtual_hosting(
			subscription
		)

	def run(self, global_context, subscription):
		"""
		:type subscription: parallels.core.migrated_subscription.MigratedSubscription
		:type global_context: parallels.core.global_context.GlobalMigrationContext
		"""
		vhost_name = subscription.name_idn
		source_server = subscription.web_source_server
		target_server = subscription.web_target_server

		logger.debug(messages.LOG_GET_IIS_DEDICATED_APPLICATION_POOL_USER)
		iis_app_user = global_context.import_api.get_dedicated_app_pool_user(subscription)
		logger.debug(messages.LOG_IIS_DEDICATED_APPLICATION_POOL_USER_ON_TARGET, iis_app_user)

		with target_server.runner() as runner_target:
			vhost_dir = u"%s/%s" % (target_server.vhosts_dir, vhost_name)
			source_plesk_version = source_server.plesk_version

			for i, security_file in enumerate(list_security_files(subscription, include_subdomains=True)):
				local_security_file = global_context.migrator_server.get_session_file_path(
					'windows-security-%s-%s.xml' % (vhost_name, i)
				)
				fixed_security_file = global_context.migrator_server.get_session_file_path(
					'windows-security-%s-%i.fixed.xml' % (vhost_name, i)
				)

				logger.debug(messages.LOG_GET_FILE_TO_CHANGE_IIS_POOL_USER, security_file, local_security_file)
				if source_plesk_version >= (11, 5):
					security_file_on_source = windows_utils.path_join(
						target_server.vhosts_dir, vhost_name, '.plesk', security_file
					)
				else:
					security_file_on_source = windows_utils.path_join(
						target_server.vhosts_dir, vhost_name, security_file
					)

				with source_server.runner() as runner_source:
					if windows_utils.file_exists(runner_source, security_file_on_source):
						runner_source.get_file(
							security_file_on_source,
							local_security_file
						)

						logger.debug(messages.LOG_FIX_SECURITY_FILE, security_file, fixed_security_file)
						with open(local_security_file, 'r') as security_fh:
							tree = et.ElementTree(file=security_fh)
							to_remove = []
							for entry in tree.getroot().findall('Entry'):
								if (
									iis_app_user is not None and 
									re.match('^IWPD_\d+\(.*\)$', entry.attrib['Account'])
								):
									entry.attrib['Account'] = iis_app_user

								# Fix issue when migrating from Windows 2003
								# with IIS 6 for domains that have ASP.NET
								# disabled on Plesk <= 9.5.3. For such domains
								# if you won't remove NoAccess permission from
								# .Security file, sites will response with 500
								# error because of insufficient permissions to
								# access httpdocs directory.
								if (
									target_server.plesk_version >= (12, 0) and 
									source_server.plesk_version <= (9, 5, 2) and
									re.match('^(IWAM|IWPC)_', entry.attrib['Account']) and
									entry.attrib['AccessMask'] == 'NoAccess'
								):
										to_remove.append(entry)

								source_user_name = subscription.raw_dump.get_phosting_sysuser_name()
								target_user_name = subscription.target_sysuser_name

								if target_user_name is not None:
									if (
										source_user_name != target_user_name and
										entry.attrib['Account'] == source_user_name
									):
										entry.attrib['Account'] = target_user_name

							for entry in to_remove:
								tree.getroot().remove(entry)

						tree.write(fixed_security_file, encoding='UTF-8', xml_declaration=True)

						logger.debug(messages.LOG_UPLOAD_FIXED_FILE_TO_TARGET, security_file)
						with open(fixed_security_file, 'r') as fixed_security_fh:
							if not security_file.startswith('subdomains\\'):
								# put file to a new location
								target_path = windows_utils.path_join(
									vhost_dir, '.plesk', security_file
								)
							else:
								# put file to an old location - it will be
								# merged further with repair utility
								target_path = windows_utils.path_join(
									vhost_dir, security_file
								)
							runner_target.upload_file_content(target_path, fixed_security_fh.read())
					else:
						logger.debug(messages.LOG_SKIP_PROCESSING_SECURITY_FILE % (security_file,))
