from parallels.core.logging import get_logger
from parallels.core.reports.model.issue import Issue
from parallels.core.utils.common import cached, safe_string_repr
from parallels.core.utils.safe_object import SafeObject

logger = get_logger(__name__)


class Safe(object):
    def __init__(self, status_storage):
        """
        :type status_storage: parallels.plesk.source.web.utils.status_storage.StatusStorage
        """
        self._status_storage = status_storage

    def add_overall_issue(self, failure_message, exception, applications, folders, databases):
        """
        :type failure_message: str | unicode
        :type exception: Exception
        :type applications: list[parallels.plesk.source.web.migrated_application.MigratedApplication]
        :type folders: list[parallels.plesk.source.web.migrated_folder.MigratedFolder]
        :type databases: list[parallels.plesk.source.web.migrated_database.WebMigratedDatabase]
        """
        issue = Issue(
            'overall_issue', Issue.SEVERITY_ERROR,
            problem_text=failure_message,
            details_text=safe_string_repr(exception)
        )

        for application in applications:
            self.get_application(application).add_issue(issue)

        for folder in folders:
            self.get_folder(folder).add_issue(issue)

        for database in databases:
            self.get_database(database).add_issue(issue)

    @cached
    def get_application(self, application):
        """Get safe object for specified migrated application

        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        :rtype: parallels.core.utils.safe_object.SafeObject
        """
        return SafeApplication(self._status_storage, application)

    @cached
    def get_folder(self, folder):
        """Get safe object for specified migrated folder

        :type folder: parallels.plesk.source.web.migrated_folder.MigratedFolder
        :rtype: parallels.core.utils.safe_object.SafeObject
        """
        return SafeFolder(self._status_storage, folder)

    @cached
    def get_database(self, database):
        """Get safe object for specified migrated database

        :type database: parallels.plesk.source.web.migrated_database.WebMigratedDatabase
        :rtype: parallels.core.utils.safe_object.SafeObject
        """
        return SafeDatabase(self._status_storage, database)


class SafeApplication(SafeObject):
    def __init__(self, status_storage, application):
        """
        :type status_storage: parallels.plesk.source.web.utils.status_storage.StatusStorage
        :type application: parallels.plesk.source.web.migrated_application.MigratedApplication
        """
        super(SafeApplication, self).__init__()
        self._status_storage = status_storage
        self._application = application

    def _add_issue_to_storage(self, issue, issue_type=None):
        """Add issue to persistent issue storage, which is used by GUI to display object issues

        :type issue: parallels.core.reports.model.issue.Issue
        :type issue_type: str | unicode | None
        :rtype: None
        """
        self._status_storage.add_application_issue(
            self._application.application_model.name,
            self._application.source_path,
            issue,
            issue_type=issue_type
        )

    def _add_issues_to_storage(self, issues, issues_type=None):
        """Add issue to persistent issue storage, which is used by GUI to display object issues

        :type issues: list[parallels.core.reports.model.issue.Issue]
        :type issues_type: str | unicode | None
        :rtype: None
        """
        self._status_storage.add_application_issues(
            self._application.application_model.name,
            self._application.source_path,
            issues,
            issues_type=issues_type
        )


class SafeFolder(SafeObject):
    def __init__(self, status_storage, folder):
        """
        :type status_storage: parallels.plesk.source.web.utils.status_storage.StatusStorage
        :type folder: parallels.plesk.source.web.migrated_folder.MigratedFolder
        """
        super(SafeFolder, self).__init__()
        self._status_storage = status_storage
        self._folder = folder

    def _add_issue_to_storage(self, issue, issue_type=None):
        """Add issue to persistent issue storage, which is used by GUI to display object issues

        :type issue: parallels.core.reports.model.issue.Issue
        :type issue_type: str | unicode | None
        :rtype: None
        """
        self._status_storage.add_folder_issue(
            self._folder.source_absolute_path,
            issue
        )


class SafeDatabase(SafeObject):
    def __init__(self, status_storage, database):
        """
        :type status_storage: parallels.plesk.source.web.utils.status_storage.StatusStorage
        :type database: parallels.plesk.source.web.migrated_database.WebMigratedDatabase
        """
        super(SafeDatabase, self).__init__()
        self._status_storage = status_storage
        self._database = database

    def _add_issue_to_storage(self, issue, issue_type=None):
        """Add issue to persistent issue storage, which is used by GUI to display object issues

        :type issue: parallels.core.reports.model.issue.Issue
        :type issue_type: str | unicode | None
        :rtype: None
        """
        self._status_storage.add_database_issue(
            self._database.source_name, self._database.source_host, self._database.source_port,
            issue
        )
