# Source code for pympress.media_overlays.gif_backend

    # -*- coding: utf-8 -*-
    #
    #       media_overlays/gif.py
    #
    #       Copyright 2018 Cimbali <me@cimba.li>
    #
    #       This program is free software; you can redistribute it and/or modify
    #       it under the terms of the GNU General Public License as published by
    #       the Free Software Foundation; either version 2 of the License, or
    #       (at your option) any later version.
    #
    #       This program is distributed in the hope that it will be useful,
    #       but WITHOUT ANY WARRANTY; without even the implied warranty of
    #       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #       GNU General Public License for more details.
    #
    #       You should have received a copy of the GNU General Public License
    #       along with this program; if not, write to the Free Software
    #       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
    #
    """
    :mod:`pympress.media_overlays.gif` -- widget to play gif images as videos
    -------------------------------------------------------------------------
    """

    import logging
    logger = logging.getLogger(__name__)

    import gi
    import cairo
    gi.require_version('Gtk', '3.0')
    from gi.repository import Gdk, GLib, GdkPixbuf

    from pympress.media_overlays import base

    class GifOverlay(base.VideoOverlay):
        """ A simple overlay mimicking the functionality of showing videos, but showing gifs instead.
        """
        #: A :class:`~GdkPixbuf.PixbufAnimation` containing all the frames and their timing for the displayed gif
        anim = None
        #: A :class:`~GdkPixbuf.PixbufAnimationIter` which will provide the timely access to the frames in `~anim`
        anim_iter = None
        #: A `tuple` of (`int`, `int`) indicating the size of the bounding box of the gif
        base_size = None
        #: The :class:`~cairo.Matrix` defining the zoom & shift to scale the gif
        transform = None

        def __init__(self, *args, **kwargs):
            super(GifOverlay, self).__init__(*args, **kwargs)

            # override: no toolbar or interactive stuff for a gif, replace the whole widget area with a GdkPixbuf
            self.autoplay = True
            self.toolbar.set_visible(False)

            # we'll manually draw on the movie zone
            self.movie_zone.connect('draw', self.draw)
            self.movie_zone.connect('configure-event', self.set_transform)

        def _set_file(self, filepath):
            """ Sets the media file to be played by the widget.

            Args:
                filepath (`pathlib.Path`): The path to the media file path
            """
            self.anim = GdkPixbuf.PixbufAnimation.new_from_file(str(filepath))
            self.base_size = (self.anim.get_width(), self.anim.get_height())
            self.anim_iter = self.anim.get_iter(None)

            self.set_transform()
            self.advance_gif()

        def set_transform(self, *args):
            """ Compute the transform to scale (not stretch nor crop) the gif.
            """
            widget_size = (self.movie_zone.get_allocated_width(), self.movie_zone.get_allocated_height())
            scale = min(widget_size[0] / self.base_size[0], widget_size[1] / self.base_size[1])
            dx = widget_size[0] - scale * self.base_size[0]
            dy = widget_size[1] - scale * self.base_size[1]

            self.transform = cairo.Matrix(xx = scale, yy = scale, x0 = dx / 2, y0 = dy / 2)

        def draw(self, widget, ctx):
            """ Simple resized drawing: get the pixbuf, set the transform, draw the image.
            """
            if self.anim_iter is None:
                return False

            try:
                ctx.transform(self.transform)
                Gdk.cairo_set_source_pixbuf(ctx, self.anim_iter.get_pixbuf(), 0, 0)
                ctx.paint()
            except cairo.Error:
                logger.error(_('Cairo can not draw gif'), exc_info = True)

        def advance_gif(self):
            """ Advance the gif, queue redrawing if the frame changed, and schedule the next frame.
            """
            if self.anim_iter.advance():
                self.movie_zone.queue_draw()

            delay = self.anim_iter.get_delay_time()
            if delay >= 0:
                GLib.timeout_add(delay, self.advance_gif)

        def do_set_time(self, t):
            """ Set the player at time t.

            Should run on the main thread to ensure we avoid reentrency problems.

            Args:
                t (`int`): the timestamp, in ms

            Returns:
                `bool`: `True` iff this function should be run again (:meth:`~GLib.idle_add` convention)
            """
            start = GLib.TimeVal()
            GLib.DateTime.new_now_local().to_timeval(start)
            start.add(-t)
            self.anim_iter = self.anim.get_iter(start)
            self.advance_gif()
            return False

        # a bunch of inherited functions that do nothing, for gifs

        def mute(self, *args): pass

        def is_playing(self): return True

        def do_stop(self): pass

        def do_play(self): return False

        def do_play_pause(self): return False

        @classmethod
        def setup_backend(cls):
            """ Returns the name of this backend.
            """
            return _('GdkPixbuf gif player')