from parallels.core.global_context import GlobalMigrationContext, SourceInfo
from parallels.core.logging import get_logger
from parallels.core.utils.common import cached, default
from parallels.plesk.source.web.migrated_application import MigratedApplication
from parallels.plesk.source.web.migrated_database import WebMigratedDatabase
from parallels.plesk.source.web.migrated_folder import MigratedFolder

logger = get_logger(__name__)


class WebGlobalMigrationContext(GlobalMigrationContext):
    """
    :type conn: parallels.plesk.source.web.connections.WebConnections
    :type session_files: parallels.plesk.source.web.session_files.WebSessionFiles
    :type site_info_storage: parallels.plesk.source.web.utils.site_info_storage.SiteInfoStorage
    :type status_storage: parallels.plesk.source.web.utils.status_storage.StatusStorage
    :type site_migration_list: parallels.plesk.source.web.site_migration_list.SiteMigrationList
    :type site_migration_lock: parallels.core.utils.locks.session_file_lock.SessionFileLock
    :type site_objects_safe: parallels.plesk.source.web.utils.safe.Safe
    :type statistics_get_site_info: parallels.plesk.source.web.statistics.StatisticsGetSiteInfo
    :type statistics_transfer_site: parallels.plesk.source.web.statistics.StatisticsTransferSite
    :type db_dumps_size: int
    """
    def __init__(self):
        super(WebGlobalMigrationContext, self).__init__()
        self.conn = None
        self.session_files = None
        self.site_info_storage = None
        self.status_storage = None
        self.site_migration_list = None
        # Per-session file lock - must be global to avoid garbage collection on it, which causes lock release
        self.site_migration_lock = None
        self.site_objects_safe = None
        self.statistics_get_site_info = None
        self.statistics_transfer_site = None
        self.db_dumps_size = 0

    def get_primary_sources_info(self):
        """
        :rtype: list[parallels.plesk.source.web.global_context.WebSourceInfo]
        """
        return self._sources_info

    @cached
    def list_migrated_applications(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_application.MigratedApplication]
        """
        migrated_applications = []

        migration_list_applications = self.site_migration_list.filter_applications
        for migration_list_application in default(migration_list_applications, []):
            migrated_applications.append(MigratedApplication(self, migration_list_application))

        return migrated_applications

    @cached
    def list_independent_migrated_databases(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_database.WebMigratedDatabase]
        """
        migrated_databases = []

        target_subscription = self.get_subscription(self.site_info_storage.get_target_subscription())

        include_databases = self.site_migration_list.include_databases
        if include_databases is not None:
            for database in include_databases:
                migrated_databases.append(
                    WebMigratedDatabase(
                        self, target_subscription,
                        database.name, database.host, database.port, database.username, database.password
                    )
                )

        return migrated_databases

    @cached
    def list_all_migrated_databases(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_database.WebMigratedDatabase]
        """
        migrated_databases = []

        migrated_databases.extend(self.list_independent_migrated_databases())

        for application in self.list_migrated_applications():
            migrated_databases.extend(application.databases)

        return migrated_databases

    @cached
    def list_all_migrated_database_users(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_database_user.WebMigratedDatabaseUser]
        """
        migrated_database_users = []

        for database in self.list_all_migrated_databases():
            migrated_database_users.append(database.database_user)

        return migrated_database_users

    @cached
    def list_independent_migrated_folders(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_folder.MigratedFolder]
        """
        migrated_folders = []

        target_subscription = self.get_subscription(self.site_info_storage.get_target_subscription())

        include_folders = self.site_migration_list.include_files
        if include_folders is not None:
            for folder in include_folders:
                migrated_folders.append(
                    MigratedFolder(
                        self, target_subscription,
                        folder.source_path, folder.target_path
                    )
                )

        return migrated_folders

    @cached
    def list_all_migrated_folders(self):
        """
        :rtype: list[parallels.plesk.source.web.migrated_folder.MigratedFolder]
        """
        migrated_folders = []

        migrated_folders.extend(self.list_independent_migrated_folders())
        for application in self.list_migrated_applications():
            migrated_folders.extend(application.folders)

        return migrated_folders


class WebSourceInfo(SourceInfo):
    @property
    def source(self):
        """
        :rtype: parallels.plesk.source.web.source.WebSource
        """
        return super(WebSourceInfo, self).source
