from parallels.core.utils.common import append_if_not_none, is_string, find_only
from parallels.core.utils.paths import web_paths
from parallels.core.utils.paths.copy_web_content import CopyWebContentItem
from parallels.core.utils.paths.web_files import BaseWebFiles
from parallels.plesk.source.custom import messages
from parallels.plesk.hosting_description.model import iter_all_subscriptions


class HostingDescriptionWebFiles(BaseWebFiles):
    """Files and directories included into Hosting Description"""

    def need_to_copy_files(self, global_context, subscription):
        """Check whether we need to copy files of that subscription

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.MigratedSubscription
        :rtype: bool
        """
        return (
            global_context.conn.has_hosting_description_config(subscription.model.source) and
            super(HostingDescriptionWebFiles, self).need_to_copy_files(global_context, subscription)
        )

    def list_files_to_copy(self, global_context, subscription):
        """Make a list of source server directories and files to be transferred.

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :type subscription: parallels.core.migrated_subscription.HostingDescriptorMigratedSubscription
        :rtype: list[parallels.core.utils.paths.copy_web_content.CopyWebContentItem]
        """
        tocopy = []

        append_if_not_none(tocopy, self._convert_hosting_description_items(
            subscription.hosting_description.source_document_root,
            web_paths.WebspaceDocumentRoot(subscription.converted_dump)
        ))
        append_if_not_none(tocopy, self._convert_hosting_description_items(
            subscription.hosting_description.source_webspace_root,
            web_paths.WebspaceRoot(subscription.converted_dump)
        ))

        for web_files_to_copy in subscription.hosting_description.iter_web_files():
            tocopy.append(CopyWebContentItem(
                source_path=web_paths.AbsolutePath(web_files_to_copy.source),
                target_path=web_paths.WebspacePathTemplate(
                    subscription.converted_dump,
                    web_files_to_copy.target
                ),
                exclude=web_files_to_copy.exclude,
                skip_if_source_not_exists=web_files_to_copy.skip_if_source_not_exists,
                source_system_user_login=web_files_to_copy.source_system_user_login,
                source_system_user_uid=web_files_to_copy.source_system_user_uid,
                source_system_user_gid=web_files_to_copy.source_system_user_gid,
            ))

        for addon_domain in subscription.converted_dump.iter_addon_domains():
            addon_domain_hosting_description = subscription.hosting_description.get_addon_domain(addon_domain.name)
            append_if_not_none(tocopy, self._convert_hosting_description_items(
                addon_domain_hosting_description.source_document_root,
                web_paths.SiteDocumentRoot(subscription.converted_dump, addon_domain)
            ))

            for addon_domain_web_files_to_copy in addon_domain_hosting_description.iter_web_files():
                tocopy.append(CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(addon_domain_web_files_to_copy.source),
                    target_path=web_paths.SitePathTemplate(
                        subscription.converted_dump,
                        addon_domain,
                        addon_domain_web_files_to_copy.target
                    ),
                    exclude=addon_domain_web_files_to_copy.exclude,
                    skip_if_source_not_exists=addon_domain_web_files_to_copy.skip_if_source_not_exists,
                    source_system_user_login=addon_domain_web_files_to_copy.source_system_user_login,
                    source_system_user_uid=addon_domain_web_files_to_copy.source_system_user_uid,
                    source_system_user_gid=addon_domain_web_files_to_copy.source_system_user_gid,
                ))

        for subdomain in subscription.converted_dump.iter_all_subdomains():
            subdomain_hosting_description = subscription.hosting_description.get_subdomain(subdomain.name)
            append_if_not_none(tocopy, self._convert_hosting_description_items(
                subdomain_hosting_description.source_document_root,
                web_paths.SiteDocumentRoot(subscription.converted_dump, subdomain)
            ))

            for subdomain_web_files_to_copy in subdomain_hosting_description.iter_web_files():
                tocopy.append(CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(subdomain_web_files_to_copy.source),
                    target_path=web_paths.SitePathTemplate(
                        subscription.converted_dump,
                        subdomain,
                        subdomain_web_files_to_copy.target
                    ),
                    exclude=subdomain_web_files_to_copy.exclude,
                    skip_if_source_not_exists=subdomain_web_files_to_copy.skip_if_source_not_exists,
                    source_system_user_login=subdomain_web_files_to_copy.source_system_user_login,
                    source_system_user_uid=subdomain_web_files_to_copy.source_system_user_uid,
                    source_system_user_gid=subdomain_web_files_to_copy.source_system_user_gid,
                ))

        return tocopy

    @staticmethod
    def _convert_hosting_description_items(source_value, target_path):
        if source_value is not None:
            if is_string(source_value):
                return CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(source_value),
                    target_path=target_path
                )
            else:
                return CopyWebContentItem(
                    source_path=web_paths.AbsolutePath(source_value['path']),
                    target_path=target_path,
                    exclude=source_value.get('exclude', [])
                )
        else:
            return None

    @staticmethod
    def _get_subscription_hosting_description_data(hosting_description_data, subscription_name):
        return find_only(
            iter_all_subscriptions(hosting_description_data), lambda s: s.get('name') == subscription_name,
            messages.FAILED_TO_FIND_SUBSCRIPTION_IN_DUMP % subscription_name
        )
