from typing import Optional

from gi.repository import Gdk, GdkPixbuf, Gtk


class SpinnerPicture(Gtk.Overlay):
    def __init__(
        self,
        loading: bool = True,
        spinner_name: str = None,
        **kwargs,
    ):
        """An picture with a loading overlay."""
        super().__init__()
        self.filename: Optional[str] = None
        self.pixbuf = None

        self.drawing_area = Gtk.DrawingArea()
        self.drawing_area.connect("draw", self.expose)
        self.add_overlay(self.drawing_area)

        self.spinner = Gtk.Spinner(
            name=spinner_name,
            active=loading,
            halign=Gtk.Align.CENTER,
            valign=Gtk.Align.CENTER,
        )
        self.add_overlay(self.spinner)

    def set_from_file(self, filename: Optional[str]):
        """Set the picture to the given filename."""
        filename = filename or None
        if self.filename == filename:
            return

        self.filename = filename

        if self.filename:
            self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(self.filename)
        else:
            self.pixbuf = None

    def set_loading(self, loading_status: bool):
        if loading_status:
            self.spinner.start()
            self.spinner.show()
        else:
            self.spinner.stop()
            self.spinner.hide()

    def expose(self, area, cr):
        if self.pixbuf:
            pix_width = self.pixbuf.get_width()
            pix_height = self.pixbuf.get_height()
            alloc_width = self.get_allocated_width()
            alloc_height = self.get_allocated_height()

            cr.translate(alloc_width / 2, alloc_height / 2);
            scale = max(alloc_width / pix_width, alloc_height / pix_height)
            cr.scale(scale, scale)
            cr.translate(-pix_width / 2, -pix_height / 2);
            Gdk.cairo_set_source_pixbuf(cr, self.pixbuf, 0, 0)
            cr.paint()
