# Copyright (code) 2020-2022 Jan-Michael Brummer <jan.brummer@tabos.org>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.

"""
Implementation of flicker code widget
Based on TerminalFlicker code in python-fints for CLI
"""

from fints.hhd.flicker import parse, swap_bytes
from gi.repository import Gtk, GLib


class FlickerCodeArea(Gtk.DrawingArea):
    """
    Flicker Code Area
    """

    def __init__(self, code, border=6):
        """
        Initialize FlickerWidget - create stream data based on code and start
        timeout function.
        :param code: Flicker Code
        :param border: border size between flicker code elements
        """
        super().__init__()

        code = parse(code).render()
        data = swap_bytes(code)
        self.stream = ["10000", "00000", "11111", "01111", "11111", "01111", "11111"]
        self.index = 0
        self.scale = 1.0
        self.border = border
        for char in data:
            val = int(char, 16)
            self.stream.append(
                "1"
                + str(val & 1)
                + str((val & 2) >> 1)
                + str((val & 4) >> 2)
                + str((val & 8) >> 3)
            )
            self.stream.append(
                "0"
                + str(val & 1)
                + str((val & 2) >> 1)
                + str((val & 4) >> 2)
                + str((val & 8) >> 3)
            )

        self.set_size_request(250, 75)
        self.set_draw_func(self.on_draw)

        GLib.timeout_add(50, self._update)

    def _update(self):
        """
        Queue a redraw of widget
        """
        self.queue_draw()
        return True

    def on_draw(self, _, cairo, width, height):
        """
        Draw Flicker Code to widget
        :param cairo: cairo renderer
        :param width: width of drawing area
        :param height: height of drawing area
        """
        bar_width = width * self.scale / 5 - 4 * self.border

        frame = self.stream[self.index]
        idx = 0
        pos_x = (width - 4 * self.border - 5 * bar_width) / 2
        for code in frame:
            col = 255 if code == "1" else 0

            cairo.set_source_rgb(col, col, col)
            cairo.rectangle(pos_x, 0, bar_width, height)
            pos_x = pos_x + bar_width + self.border
            idx = idx + 1
            cairo.fill()

        self.index = (self.index + 1) % len(self.stream)

    def decrease(self):
        """
        Decrease widget size by 0.05, cannot be below 0.3
        """
        self.scale = self.scale - 0.05
        self.scale = max(self.scale, 0.3)

    def increase(self):
        """
        Increase widget size by 0.05, cannot exceed 1.0
        """
        self.scale = self.scale + 0.05
        self.scale = min(self.scale, 2.0)


class FlickerCode(Gtk.Box):
    """
    Flicker Code
    """

    def __init__(self, code, border=6):
        super().__init__()

        self.set_spacing(6)
        self.set_orientation(Gtk.Orientation.VERTICAL)

        box = Gtk.Box()
        box.set_halign(Gtk.Align.START)
        box.get_style_context().add_class("linked")
        self.append(box)

        dec = Gtk.Button.new_from_icon_name("list-remove-symbolic")
        dec.connect("clicked", self._on_decrease)
        box.append(dec)

        inc = Gtk.Button.new_from_icon_name("list-add-symbolic")
        inc.connect("clicked", self._on_increase)
        box.append(inc)

        self.area = FlickerCodeArea(code, border)
        self.append(self.area)

    def _on_decrease(self, _):
        self.area.decrease()

    def _on_increase(self, _):
        self.area.increase()


class Window(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self)
        self.set_title("FlickerCode Test")
        self.connect("destroy", Gtk.main_quit)

        widget = FlickerCode("2908881344731012345678900515,00")
        self.set_child(widget)


if __name__ == "__main__":
    win = Window()
    win.show()
    Gtk.main()
