from item_patchers import (
    SettingsPatcher, MiddlewarePatcher,
    AppsPatcher, UrlsPatcher, ValidationError)


class Patcher:

    patchers = {
        'middleware': MiddlewarePatcher(),
        'settings': SettingsPatcher(),
        'apps': AppsPatcher(),
        'urls': UrlsPatcher()
    }

    def __init__(self):
        """
        Add patches to Django settings and urls file
        """
        self.files = _Files()

    def patch(self, patch_obj, override_files=True):
        """
        Add code to django settings and urls files
        :param patch_obj: Object, generated by confugurtor.Configurator
        """
        try:
            for patcher_name, patcher_obj in patch_obj.items():
                # Get file content for given file patch
                file_content = self.files.open(patcher_obj['file_path'])
                # Apply patch to file content
                chenged_file_content = self.patchers[patcher_name].apply(file_content, patcher_obj['patch'])
                # Update file content in memory for the next patch
                self.files.update(patcher_obj['file_path'], chenged_file_content)
        except ValidationError:
            #TODO
            pass

        if override_files:
            self.files.write_all()

    @classmethod
    def available_patchers(cls):
        return cls.patchers.keys()


class _Files:
    def __init__(self):
        self.contents = {}

    def open(self, path):
        if not path in self.contents:
            with open(path, 'r') as f:
                self.contents[path] = f.read()

        return self.contents[path]

    def write(self, path):
        if not path in self.contents:
            return

        with open(path, 'w') as f:
            f.write(self.contents[path])

    def write_all(self):
        # Write all changes to files
        for path, content in self.contents.items():
            with open(path, 'w') as f:
                f.write(content)

    def update(self, path, content):
        self.contents[path] = content
