import os
import shutil
from contextlib import closing

from parallels.core.logging import get_logger
from parallels.core import messages
from parallels.core.utils.common import mkdir_p, is_run_on_windows, open_no_inherit
from parallels.core.actions.base.common_action import CommonAction
from parallels.core.dump import dump

logger = get_logger(__name__)


class Unpack(CommonAction):
    def get_description(self):
        return messages.ACTION_UNPACK_BACKUPS

    def get_failure_message(self, global_context):
        return messages.FAILED_TO_UNPACK_BACKUPS

    def run(self, global_context):
        """
        :type global_context: parallels.core.global_context.GlobalMigrationContext
        """
        for plesk_id in global_context.source_servers:
            session_files = global_context.session_files
            for backup_filename in [
                session_files.get_converted_dump_filename(plesk_id),
                session_files.get_raw_dump_filename(plesk_id)
            ]:
                self._extract_plesk_backup(global_context, backup_filename)

    @staticmethod
    def _extract_plesk_backup(global_context, backup_filename):
        extracted_files = []
        if os.path.exists(backup_filename):
            extract_dirname = global_context.session_files.get_file_path(
                'unpacked', os.path.basename(backup_filename)
            )
            logger.info(
                messages.EXTRACTING_FILES_FROM_BACKUP_S_S,
                backup_filename, extract_dirname
            )
            mkdir_p(extract_dirname)
            archive = dump.PleskBackupContainer(backup_filename).archive
            for member in archive.get_members():
                if member.is_file:
                    extract_filename = os.path.join(extract_dirname, member.name.decode('utf-8'))
                    extracted_files.append(extract_filename)
                    mkdir_p(os.path.dirname(extract_filename))
                    if is_run_on_windows():
                        # Workaround issue with Windows maximum full path
                        # length, which is equal to 260 symbols. We exceed it
                        # on domains with long names, that are owned by
                        # customers owned by resellers
                        # Details are there:
                        # http://stackoverflow.com/questions/14075465/copy-a-file-with-a-too-long-path-to-another-directory-in-python
                        # http://stackoverflow.com/questions/1880321/why-does-the-260-character-path-length-limit-exist-in-windows
                        target_path = "\\\\?\\" + os.path.abspath(
                            extract_filename
                        )
                    else:
                        target_path = extract_filename
                    with closing(archive.extract(member.name)) as source, open_no_inherit(target_path, 'wb') as target:
                        shutil.copyfileobj(source, target)
            archive.close()
        return extracted_files
