from collections import defaultdict

from parallels.core.session_files import CommonSessionFiles
from parallels.core.utils.common import cached
import hashlib


class MailSessionFiles(CommonSessionFiles):
    def __init__(self, conn, migrator_server, task_id=None):
        """
        :type conn: parallels.core.connections.connections.Connections
        :type migrator_server: parallels.core.connections.migrator_server.MigratorServer
        """
        super(MailSessionFiles, self).__init__(conn, migrator_server)
        self._task_id = task_id
        self._unique_suffixes = defaultdict(int)

    def get_global_status_file(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(u'mail_migration_status.json')

    def get_global_status_file_lock(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(u'mail_migration_status.lock')

    def get_settings_file(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(u'mail_migration_settings.json')

    def get_settings_file_lock(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(u'mail_migration_settings.lock')

    def get_default_mail_migration_list_file(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(u'mail_migration_list.json')

    def get_new_random_mail_migrator_backup_progress_file(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(
             self._get_unique_name(u'mail_migrator_backup_progress', u'json')
        )

    def get_new_random_mail_migrator_restore_progress_file(self):
        """
        :rtype: parallels.core.session_files.SessionFile
        """
        return self.get_file(
             self._get_unique_name(u'mail_migrator_restore_progress', u'json')
        )

    def get_new_random_source_account_description_file(self):
        return self.get_file(
             self._get_unique_name(u'mail_migrator_source_account')
        )

    def get_new_random_target_account_description_file(self):
        return self.get_file(
             self._get_unique_name(u'mail_migrator_target_account')
        )

    def get_new_random_mail_migrator_log_file(self):
        return self.get_file(
             self._get_unique_name(u'mail_migrator_debug', u'log')
        )

    def get_new_random_exclude_message_ids_file(self):
        return self.get_file(
             self._get_unique_name(u'exclude-message-ids')
        )

    def get_message_ids_cache_file(self, source_email, target_email):
        """
        :type source_email: str | unicode
        :type target_email: str | unicode
        :rtype: parallels.core.session_files.SessionFile
        """
        # 1) Use MD5 hash instead of actual source/target e-mail to avoid issues with special symbols
        # and security questions (e.g. when "../../" was specified by malicious user as e-mail)
        # 2) Each source-target pair should have its own file with message IDs to avoid race conditions
        # when reading/writing the same file by different processes (each pair has its own
        # migration or sync process).
        file_id_hash = hashlib.md5()
        file_id_hash.update(source_email.encode('utf-8') + target_email.encode('utf-8'))
        return self.get_file(u'mail_message_ids_cache.%s' % file_id_hash.hexdigest())

    @cached
    def get_path_to_info_log(self):
        return self.get_file_path(
            self._get_unique_name(u"info", u"log")
        )

    @cached
    def get_path_to_debug_log(self):
        return self.get_file_path(
            self._get_unique_name(u"debug", u"log")
        )

    @cached
    def get_path_to_binary_log_index(self):
        return self.get_file_path(
            self._get_unique_name(u"binary_log", u"index")
        )

    @cached
    def get_path_to_binary_log_messages(self):
        return self.get_file_path(
            self._get_unique_name(u"binary_log", u"messages")
        )

    def _get_unique_name(self, name_prefix, extension=None):
        """
        :type name_prefix: str | unicode
        :type extension: str | unicode | None
        :rtype: str | unicode
        """
        name = name_prefix

        if self._task_id is not None:
            name = u"%s_%s" % (name, self._task_id)

        self._unique_suffixes[(name_prefix, extension)] += 1

        name = u"%s_%s" % (name, self._unique_suffixes[(name_prefix, extension)])

        if extension is not None:
            name = u"%s.%s" % (name, extension)

        return name
