# vim: fileencoding=utf-8
#
from .base_format import Format
from calculate.utils.files import Process
from calculate.templates.format.base_format import FormatError
from os import path


class PatchFormat(Format):
    FORMAT = 'patch'
    EXECUTABLE = True

    def __init__(self, patch_text: str,
                 template_path: str,
                 ignore_comments=None):
        self._patch_text = patch_text
        self._cwd_path = '/'
        self._last_level = 0

        # Измененные файлы.
        self.changed_files = dict()

    def execute_format(self, target_path, chroot_path='/'):
        '''Метод для запуска работы формата.'''
        self._cwd_path = target_path
        if not path.isdir(self._cwd_path):
            # Если target_path -- путь к файлу, запускаем все процессы из
            # директории, в которой этот файл находится.
            self._cwd_path = path.dirname(self._cwd_path)

        if not path.exists(self._cwd_path):
            raise FormatError('root path does not exist')

        if self._patch_text:
            self._patch_document()
            return self.changed_files
        else:
            raise FormatError('empty patch file')

    def _patch_document(self):
        '''Метод, производящий наложение патча путем запуска процесса patch.'''
        # Сначала определяем на каком уровне накладываем патч.
        # Для этого запускаем утилиту patch с --dry-run и смотрим результат
        # выполнения.
        for level in range(0, 4):
            patch_dry_run = Process('patch', '--dry-run',
                                    '-p{}'.format(level),
                                    cwd=self._cwd_path)
            patch_dry_run.write(self._patch_text)
            if patch_dry_run.success():
                break

            patch_dry_run = Process('patch', '-R', '--dry-run',
                                    '-p{}'.format(level),
                                    cwd=self._cwd_path)
            patch_dry_run.write(self._patch_text)
            if patch_dry_run.success():
                return ''
        else:
            raise FormatError('correction failed')

        self._last_level = level
        patch_run = Process('patch', '-p{}'.format(level),
                            cwd=self._cwd_path)
        patch_run.write(self._patch_text)

        if patch_run.success():
            for line in patch_run.read_lines():
                if line.startswith('patching file'):
                    changed_file_path = path.join(self._cwd_path,
                                                  line[13:].strip())
                    if path.exists(changed_file_path):
                        self.changed_files.update({changed_file_path:
                                                   'C'})
                    else:
                        self.changed_files.update({changed_file_path:
                                                   'D'})
            return patch_run.read()
        else:
            return ''
