"""versatileimagefield Field mixins."""
import os
import re

from .datastructures import FilterLibrary
from .registry import autodiscover, versatileimagefield_registry
from .settings import (
    cache,
    VERSATILEIMAGEFIELD_CREATE_ON_DEMAND,
    VERSATILEIMAGEFIELD_SIZED_DIRNAME,
    VERSATILEIMAGEFIELD_FILTERED_DIRNAME
)
from .validators import validate_ppoi

autodiscover()

filter_regex_snippet = r'__({registered_filters})__'.format(
    registered_filters='|'.join([
        key
        for key, filter_cls in versatileimagefield_registry._filter_registry.items()
    ])
)
sizer_regex_snippet = r'-({registered_sizers})-(\d+)x(\d+)(?:-\d+)?'.format(
    registered_sizers='|'.join([
        sizer_cls.get_filename_key_regex()
        for key, sizer_cls in versatileimagefield_registry._sizedimage_registry.items()
    ])
)
filter_regex = re.compile(filter_regex_snippet + '$')
sizer_regex = re.compile(sizer_regex_snippet + '$')
filter_and_sizer_regex = re.compile(
    filter_regex_snippet + sizer_regex_snippet + '$'
)


class VersatileImageMixIn(object):
    """A mix-in that provides the filtering/sizing API."""

    def __init__(self, *args, **kwargs):
        """Construct PPOI and create_on_demand."""
        self._create_on_demand = VERSATILEIMAGEFIELD_CREATE_ON_DEMAND
        super(VersatileImageMixIn, self).__init__(*args, **kwargs)
        # Setting initial ppoi
        if self.field.ppoi_field:
            instance_ppoi_value = getattr(
                self.instance,
                self.field.ppoi_field,
                (0.5, 0.5)
            )
            self.ppoi = instance_ppoi_value
        else:
            self.ppoi = (0.5, 0.5)

    @property
    def url(self):
        """
        Return the appropriate URL.

        URL is constructed based on these field conditions:
            * If empty (not `self.name`) and a placeholder is defined, the
              URL to the placeholder is returned.
            * Otherwise, defaults to vanilla ImageFieldFile behavior.
        """
        if not self.name and self.field.placeholder_image_name:
            return self.storage.url(self.field.placeholder_image_name)

        return super(VersatileImageMixIn, self).url

    @property
    def create_on_demand(self):
        """create_on_demand getter."""
        return self._create_on_demand

    @create_on_demand.setter
    def create_on_demand(self, value):
        if not isinstance(value, bool):
            raise ValueError(
                "`create_on_demand` must be a boolean"
            )
        else:
            self._create_on_demand = value
            self.build_filters_and_sizers(self.ppoi, value)

    @property
    def ppoi(self):
        """Primary Point of Interest (ppoi) getter."""
        return self._ppoi_value

    @ppoi.setter
    def ppoi(self, value):
        """Primary Point of Interest (ppoi) setter."""
        ppoi = validate_ppoi(
            value,
            return_converted_tuple=True
        )
        if ppoi is not False:
            self._ppoi_value = ppoi
            self.build_filters_and_sizers(ppoi, self.create_on_demand)

    def build_filters_and_sizers(self, ppoi_value, create_on_demand):
        """Build the filters and sizers for a field."""
        name = self.name
        if not name and self.field.placeholder_image_name:
            name = self.field.placeholder_image_name
        self.filters = FilterLibrary(
            name,
            self.storage,
            versatileimagefield_registry,
            ppoi_value,
            create_on_demand
        )
        for (
            attr_name,
            sizedimage_cls
        ) in versatileimagefield_registry._sizedimage_registry.items():
            setattr(
                self,
                attr_name,
                sizedimage_cls(
                    path_to_image=name,
                    storage=self.storage,
                    create_on_demand=create_on_demand,
                    ppoi=ppoi_value
                )
            )

    def get_filtered_root_folder(self):
        """Return the location where filtered images are stored."""
        folder, filename = os.path.split(self.name)
        return os.path.join(folder, VERSATILEIMAGEFIELD_FILTERED_DIRNAME, '')

    def get_sized_root_folder(self):
        """Return the location where sized images are stored."""
        folder, filename = os.path.split(self.name)
        return os.path.join(VERSATILEIMAGEFIELD_SIZED_DIRNAME, folder, '')

    def get_filtered_sized_root_folder(self):
        """Return the location where filtered + sized images are stored."""
        sized_root_folder = self.get_sized_root_folder()
        return os.path.join(
            sized_root_folder,
            VERSATILEIMAGEFIELD_FILTERED_DIRNAME
        )

    def delete_matching_files_from_storage(self, root_folder, regex):
        """
        Delete files in `root_folder` which match `regex` before file ext.

        Example values:
            * root_folder = 'foo/'
            * self.name = 'bar.jpg'
            * regex = re.compile('-baz')

            Result:
                * foo/bar-baz.jpg <- Deleted
                * foo/bar-biz.jpg <- Not deleted
        """
        if not self.name:   # pragma: no cover
            return
        try:
            directory_list, file_list = self.storage.listdir(root_folder)
        except OSError:   # pragma: no cover
            pass
        else:
            folder, filename = os.path.split(self.name)
            basename, ext = os.path.splitext(filename)
            for f in file_list:
                if not f.startswith(basename) or not f.endswith(ext):   # pragma: no cover
                    continue
                tag = f[len(basename):-len(ext)]
                assert f == basename + tag + ext
                if regex.match(tag) is not None:
                    file_location = os.path.join(root_folder, f)
                    self.storage.delete(file_location)
                    cache.delete(
                        self.storage.url(file_location)
                    )
                    print(
                        "Deleted {file} (created from: {original})".format(
                            file=os.path.join(root_folder, f),
                            original=self.name
                        )
                    )

    def delete_filtered_images(self):
        """Delete all filtered images created from `self.name`."""
        self.delete_matching_files_from_storage(
            self.get_filtered_root_folder(),
            filter_regex
        )

    def delete_sized_images(self):
        """Delete all sized images created from `self.name`."""
        self.delete_matching_files_from_storage(
            self.get_sized_root_folder(),
            sizer_regex
        )

    def delete_filtered_sized_images(self):
        """Delete all filtered sized images created from `self.name`."""
        self.delete_matching_files_from_storage(
            self.get_filtered_sized_root_folder(),
            filter_and_sizer_regex
        )

    def delete_all_created_images(self):
        """Delete all images created from `self.name`."""
        self.delete_filtered_images()
        self.delete_sized_images()
        self.delete_filtered_sized_images()

[((29, 15, 29, 53), 're.compile', 're.compile', ({(29, 26, 29, 52): "filter_regex_snippet + '$'"}, {}), "(filter_regex_snippet + '$')", False, 'import re\n'), ((30, 14, 30, 51), 're.compile', 're.compile', ({(30, 25, 30, 50): "sizer_regex_snippet + '$'"}, {}), "(sizer_regex_snippet + '$')", False, 'import re\n'), ((31, 25, 33, 1), 're.compile', 're.compile', ({(32, 4, 32, 52): "filter_regex_snippet + sizer_regex_snippet + '$'"}, {}), "(filter_regex_snippet + sizer_regex_snippet + '$')", False, 'import re\n'), ((129, 27, 129, 51), 'os.path.split', 'os.path.split', ({(129, 41, 129, 50): 'self.name'}, {}), '(self.name)', False, 'import os\n'), ((130, 15, 130, 77), 'os.path.join', 'os.path.join', ({(130, 28, 130, 34): 'folder', (130, 36, 130, 72): 'VERSATILEIMAGEFIELD_FILTERED_DIRNAME', (130, 74, 130, 76): '""""""'}, {}), "(folder, VERSATILEIMAGEFIELD_FILTERED_DIRNAME, '')", False, 'import os\n'), ((134, 27, 134, 51), 'os.path.split', 'os.path.split', ({(134, 41, 134, 50): 'self.name'}, {}), '(self.name)', False, 'import os\n'), ((135, 15, 135, 74), 'os.path.join', 'os.path.join', ({(135, 28, 135, 61): 'VERSATILEIMAGEFIELD_SIZED_DIRNAME', (135, 63, 135, 69): 'folder', (135, 71, 135, 73): '""""""'}, {}), "(VERSATILEIMAGEFIELD_SIZED_DIRNAME, folder, '')", False, 'import os\n'), ((140, 15, 143, 9), 'os.path.join', 'os.path.join', ({(141, 12, 141, 29): 'sized_root_folder', (142, 12, 142, 48): 'VERSATILEIMAGEFIELD_FILTERED_DIRNAME'}, {}), '(sized_root_folder, VERSATILEIMAGEFIELD_FILTERED_DIRNAME)', False, 'import os\n'), ((165, 31, 165, 55), 'os.path.split', 'os.path.split', ({(165, 45, 165, 54): 'self.name'}, {}), '(self.name)', False, 'import os\n'), ((166, 28, 166, 54), 'os.path.splitext', 'os.path.splitext', ({(166, 45, 166, 53): 'filename'}, {}), '(filename)', False, 'import os\n'), ((173, 36, 173, 64), 'os.path.join', 'os.path.join', ({(173, 49, 173, 60): 'root_folder', (173, 62, 173, 63): 'f'}, {}), '(root_folder, f)', False, 'import os\n'), ((180, 33, 180, 61), 'os.path.join', 'os.path.join', ({(180, 46, 180, 57): 'root_folder', (180, 59, 180, 60): 'f'}, {}), '(root_folder, f)', False, 'import os\n')]