'''
PIL: PIL image loader
'''

__all__ = ('ImageLoaderPIL', )

try:
    import Image as PILImage
except ImportError:
    # for python3
    from PIL import Image as PILImage

from kivy.logger import Logger
from kivy.core.image import ImageLoaderBase, ImageData, ImageLoader

try:
    # Pillow
    PILImage.frombytes
    PILImage.Image.tobytes
except AttributeError:
    # PIL
    # monkey patch frombytes and tobytes methods, refs:
    # https://github.com/kivy/kivy/issues/5460
    PILImage.frombytes = PILImage.frombuffer
    PILImage.Image.tobytes = PILImage.Image.tostring


class ImageLoaderPIL(ImageLoaderBase):
    '''Image loader based on the PIL library.

    .. versionadded:: 1.0.8

    Support for GIF animation added.

    Gif animation has a lot of issues(transparency/color depths... etc).
    In order to keep it simple, what is implemented here is what is
    natively supported by the PIL library.

    As a general rule, try to use gifs that have no transparency.
    Gif's with transparency will work but be prepared for some
    artifacts until transparency support is improved.

    '''

    @staticmethod
    def can_save():
        return True

    @staticmethod
    def can_load_memory():
        return True

    @staticmethod
    def extensions():
        '''Return accepted extensions for this loader'''
        PILImage.init()
        return tuple((ext_with_dot[1:] for ext_with_dot in PILImage.EXTENSION))

    def _img_correct(self, _img_tmp):
        '''Convert image to the correct format and orientation.
        '''
        # image loader work only with rgb/rgba image
        if _img_tmp.mode.lower() not in ('rgb', 'rgba'):
            try:
                imc = _img_tmp.convert('RGBA')
            except:
                Logger.warning(
                    'Image: Unable to convert image to rgba (was %s)' %
                    (_img_tmp.mode.lower()))
                raise
            _img_tmp = imc

        return _img_tmp

    def _img_read(self, im):
        '''Read images from an animated file.
        '''
        im.seek(0)

        # Read all images inside
        try:
            img_ol = None
            while True:
                img_tmp = im
                img_tmp = self._img_correct(img_tmp)
                if img_ol and (hasattr(im, 'dispose') and not im.dispose):
                    # paste new frame over old so as to handle
                    # transparency properly
                    img_ol.paste(img_tmp, (0, 0), img_tmp)
                    img_tmp = img_ol
                img_ol = img_tmp
                yield ImageData(img_tmp.size[0], img_tmp.size[1],
                                img_tmp.mode.lower(), img_tmp.tobytes())
                im.seek(im.tell() + 1)
        except EOFError:
            pass

    def load(self, filename):
        try:
            im = PILImage.open(filename)
        except:
            Logger.warning('Image: Unable to load image <%s>' % filename)
            raise
        # update internals
        if not self._inline:
            self.filename = filename
        # returns an array of type ImageData len 1 if not a sequence image
        return list(self._img_read(im))

    @staticmethod
    def save(filename, width, height, fmt, pixels, flipped=False):
        image = PILImage.frombytes(fmt.upper(), (width, height), pixels)

        if flipped:
            image = image.transpose(PILImage.FLIP_TOP_BOTTOM)
        image.save(filename)
        return True


# register
ImageLoader.register(ImageLoaderPIL)
