from parallels.core import MigrationNoContextError
from parallels.core.logging import get_logger
from parallels.core.actions.utils.logging_properties import LoggingProperties
from parallels.plesk import messages
from parallels.core.actions.base.common_action import CommonAction

logger = get_logger(__name__)


class CheckComponents(CommonAction):
    """Check that source Plesk has all components required for migration"""

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

        :rtype: str
        """
        return messages.ACTION_CHECK_PLESKS_COMPONENTS_DESCRIPTION

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

        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: str | unicode
        """
        return messages.ACTION_CHECK_PLESKS_COMPONENTS_FAILURE

    def get_logging_properties(self):
        """Get how action should be logged to migration tools end-user

        :rtype: parallels.core.actions.utils.logging_properties.LoggingProperties
        """
        return LoggingProperties(compound=False)

    def run(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        :rtype: None
        """
        for source_id in global_context.conn.get_source_plesks().keys():
            source_server = global_context.conn.get_source_node(source_id)
            source_version = source_server.get_plesk_version()

            # Check that Plesk Backup Manager is installed on Plesk 11.0. For other versions that is not actual:
            # you can not install 11.5 and later without it. For versions below it is not necessary: it is
            # required to decrypt encrypted passwords, and encrypted passwords are in Plesk starting at 11.0.
            if source_version[:2] == (11, 0) and not source_server.is_windows():
                if not self._is_component_installed(source_server, 'psa-backup-manager'):
                    raise MigrationNoContextError(messages.FAILURE_NO_BACKUP_MANAGER.format(
                        server=source_server.description()
                    ))

    @staticmethod
    def _is_component_installed(source_server, component):
        """Check whether component is installed on Plesk server

        Method was tested on Plesk 11.0 only, more recent Plesk versions has quite another database structure.

        :type source_server: parallels.core.connections.plesk_server.PleskServer
        :type component: str | unicode
        :rtype: bool
        """
        query = (
            "SELECT COUNT(*) AS props_count FROM ServiceNodeProperties "
            "WHERE name = 'server.packages.{component}'".format(
                component=component
            )
        )
        count = int(source_server.query_panel_db(query)[0]["props_count"])
        return count > 0
