# A utility for saving a large number of images quickly without
# blocking a single thread to wait for each individual image to save.

import os
import PIL
from .workerpool import WorkerBase, WorkerPool
from . import pbar


def all_items_and_filenames(img_array, filename_pattern, index=()):
    for i, data in enumerate(img_array):
        inner_index = index + (i,)
        if PIL.Image.isImageType(data):
            yield data, (filename_pattern % inner_index)
        else:
            for img, name in all_items_and_filenames(data, filename_pattern,
                    inner_index):
                yield img, name

def expand_last_filename(img_array, filename_pattern):
    index, data = (), img_array
    while not PIL.Image.isImageType(data):
        index += (len(data) - 1,)
        data = data[len(data) - 1]
    return filename_pattern % index

def num_items(img_array):
    num = 1
    while not PIL.Image.isImageType(img_array):
       num *= len(img_array)
       img_array = img_array[-1]
    return num

def save_image_set(img_array, filename_pattern, sourcefile=None):
    '''
    Saves all the (PIL) images in the given array, using the
    given filename pattern (which should contain a `%d` to get
    the index number of the image).
    '''
    if sourcefile is not None:
        last_filename = expand_last_filename(img_array, filename_pattern)
        # Do nothing if the last file exists and is newer than the sourcefile
        if os.path.isfile(last_filename) and (os.path.getmtime(last_filename)
                >= os.path.getmtime(sourcefile)):
            pbar.descnext(None)
            return
    # Use multiple threads to write all the image files faster.
    pool = WorkerPool(worker=SaveImageWorker)
    for img, filename in pbar(
            all_items_and_filenames(img_array, filename_pattern),
            total=num_items(img_array)):
        pool.add(img, filename)
    pool.join()

class SaveImageWorker(WorkerBase):
    def work(self, img, filename, quality=99):
        os.makedirs(os.path.dirname(filename), exist_ok=True)
        img.save(filename, optimize=True, quality=quality)

class SaveImagePool(WorkerPool):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, worker=SaveImageWorker, **kwargs)
