import os

from parallels.core import messages
from parallels.core import safe_format
from parallels.core.actions.base.subscription_action import SubscriptionAction
from parallels.core.logging import get_logger
from parallels.core.migrator_config import read_adjust_applications_enabled, \
    read_adjust_applications_remove_absent_handlers_enabled
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import format_multiline_list, is_empty
from parallels.core.utils.web_config_file import WebConfigFile

logger = get_logger(__name__)


class AdjustWebConfigAbsentHandlers(SubscriptionAction):
    """Remove absent handlers from web.config files of the migrated sites

    Example of handler in web config file:
    <handlers>
        <add
            name="PHP_via_FastCGI" path=".php" verb="" modules="FastCgiModule"
            scriptProcessor="C:\PHP5.3\php-cgi.exe" resourceType="Unspecified" requireAccess="Script" />
    </handlers>

    In that example, if "C:\PHP5.3\php-cgi.exe" file is absent on the target server,
    corresponding "add" XML node will be removed from web.config file.
    """

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

        :rtype: str
        """
        return messages.ACTION_ADJUST_WEB_CONFIG_ABSENT_HANDLERS_DESCRIPTION

    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.ACTION_ADJUST_WEB_CONFIG_ABSENT_HANDLERS_FAILURE

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

    def filter_subscription(self, global_context, subscription):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        """
        # filter only subscriptions on windows physical servers
        source_info = subscription.get_source_info()
        if not source_info.is_server or not source_info.is_windows:
            return False

        return (
            read_adjust_applications_enabled(global_context.config) and
            read_adjust_applications_remove_absent_handlers_enabled(global_context.config)
        )

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

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: None
        """
        for domain in subscription.converted_dump.iter_domains():
            if not domain.is_virtual_hosting:
                continue

            for web_config_file in WebConfigFile.iter_for_domain(subscription, domain):
                nodes_to_remove = []
                absent_script_processors = set()

                for handler_node in web_config_file.xml.findall('.//handlers'):
                    for add_node in handler_node:
                        if 'scriptProcessor' not in add_node.attrib:
                            continue

                        if is_empty(add_node.attrib['scriptProcessor']):
                            continue

                        if not os.path.exists(add_node.attrib['scriptProcessor']):
                            absent_script_processors.add(add_node.attrib['scriptProcessor'])
                            nodes_to_remove.append((handler_node, add_node))

                if len(absent_script_processors) > 0:
                    for parent, node_to_remove in nodes_to_remove:
                        parent.remove(node_to_remove)

                    web_config_file.save()

                    subscription_report = global_context.application_adjust_report.subtarget(
                        'Subscription', subscription.name
                    )
                    subscription_report.add_issue(
                        'web_config_absent_handler',
                        Issue.SEVERITY_INFO, safe_format(
                            messages.REMOVED_ABSENT_HANDLER_WEB_CONFIG_FILE, filename=web_config_file.filename,
                            script_processors=format_multiline_list(absent_script_processors)
                        )
                    )
