#!/usr/bin/env python3

from gi.repository import Gtk, Gdk

from nwg_panel.tools import check_key, update_image_fallback_desktop, hyprctl


class HyprlandWorkspaces(Gtk.Box):
    def __init__(self, settings, monitors, workspaces, clients, activewindow, icons_path):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        self.settings = settings
        self.num_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        self.num_box.set_property("name", "hyprland-workspaces")
        self.ws_id2name = None
        self.name_label = Gtk.Label()
        self.name_label.set_property("name", "hyprland-workspaces-name")
        self.icon = Gtk.Image()
        self.icon.set_property("name", "hyprland-workspaces-icon")
        self.floating_icon = Gtk.Image()
        self.icons_path = icons_path

        self.ws_nums = []

        self.build_box()
        self.refresh(monitors, workspaces, clients, activewindow)

    def build_box(self):
        check_key(self.settings, "num-ws", 10)
        check_key(self.settings, "show-icon", True)
        check_key(self.settings, "image-size", 16)
        check_key(self.settings, "show-name", True)
        check_key(self.settings, "name-length", 40)
        check_key(self.settings, "show-empty", True)
        check_key(self.settings, "mark-content", True)
        check_key(self.settings, "show-names", True)
        check_key(self.settings, "mark-floating", True)
        check_key(self.settings, "mark-xwayland", True)
        check_key(self.settings, "angle", 0.0)

        if self.settings["angle"] != 0.0:
            self.set_orientation(Gtk.Orientation.VERTICAL)
            self.num_box.set_orientation(Gtk.Orientation.VERTICAL)

        self.pack_start(self.num_box, False, False, 0)

        for i in range(1, self.settings["num-ws"] + 1):
            self.ws_nums.append(i)

        if self.settings["show-icon"]:
            self.pack_start(self.icon, False, False, 6)

        if self.settings["show-name"]:
            self.pack_start(self.name_label, False, False, 0)

        if self.settings["mark-floating"]:
            self.pack_start(self.floating_icon, False, False, 6)

    def build_number(self, num, add_dot=False, active_win_ws=0):
        eb = Gtk.EventBox()
        eb.connect("enter_notify_event", self.on_enter_notify_event)
        eb.connect("leave_notify_event", self.on_leave_notify_event)
        eb.connect("button-release-event", self.on_click, num)
        eb.add_events(Gdk.EventMask.SCROLL_MASK)
        eb.connect('scroll-event', self.on_scroll)

        if active_win_ws == num:
            eb.set_property("name", "task-box-focused")
        else:
            eb.set_property("name", "")

        box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
        box.set_property("name", "hyprland-workspaces-item")
        if self.settings["angle"] != 0.0:
            box.set_orientation(Gtk.Orientation.VERTICAL)
        eb.add(box)

        name = str(num)
        if self.settings["show-names"] and num in self.ws_id2name and self.ws_id2name[num] != str(num):
            name = "{} {}".format(num, self.ws_id2name[num])

        lbl = Gtk.Label.new("{}".format(name)) if not add_dot else Gtk.Label.new("{}.".format(name))
        lbl.set_use_markup(True)
        if self.settings["angle"] != 0.0:
            lbl.set_angle(self.settings["angle"])
            self.name_label.set_angle(self.settings["angle"])

        box.pack_start(lbl, False, False, 6)

        return eb, lbl

    def refresh(self, monitors, workspaces, clients, activewindow):
        occupied_workspaces = []
        self.ws_id2name = {}

        for ws in workspaces:
            for client in clients:
                if client["workspace"]["id"] == ws["id"] and ws["id"] not in occupied_workspaces:
                    occupied_workspaces.append(ws["id"])
                    break

            self.ws_id2name[ws["id"]] = ws["name"]
        occupied_workspaces.sort()

        for c in self.num_box.get_children():
            c.destroy()

        if activewindow:
            client_class = activewindow["class"]
            client_title = activewindow["title"][:self.settings["name-length"]]
            if self.settings["mark-xwayland"] and activewindow["xwayland"]:
                client_title = "X|{}".format(client_title)
            floating = activewindow["floating"]
            pinned = activewindow["pinned"]
            active_ws = activewindow["workspace"]["id"]
        else:
            client_class = ""
            client_title = ""
            floating = False
            pinned = False
            for m in monitors:
                if m["focused"]:
                    active_ws = m["activeWorkspace"]["id"]
                    break

        for num in self.ws_nums:
            if num in occupied_workspaces or self.settings["show-empty"]:
                dot = num in occupied_workspaces and self.settings["show-empty"] and self.settings["mark-content"]
                eb, lbl = self.build_number(num, add_dot=dot, active_win_ws=active_ws)
                self.num_box.pack_start(eb, False, False, 0)
                self.num_box.show_all()

        if self.settings["show-icon"]:
            self.update_icon(client_class, client_title)
        if self.settings["show-name"]:
            self.name_label.set_text(client_title)
        if self.settings["mark-floating"]:
            if pinned:
                update_image_fallback_desktop(self.floating_icon, "pin", self.settings["image-size"],
                                              self.icons_path)
                self.floating_icon.show()
            elif floating:
                update_image_fallback_desktop(self.floating_icon, "focus-windows", self.settings["image-size"],
                                              self.icons_path)
                self.floating_icon.show()
            else:
                self.floating_icon.hide()

    def update_icon(self, client_class, client_title):
        loaded_icon = False
        if client_class and client_title:
            try:
                update_image_fallback_desktop(self.icon,
                                              client_class,
                                              self.settings["image-size"],
                                              self.icons_path,
                                              fallback=False)
                loaded_icon = True
                if not self.icon.get_visible():
                    self.icon.show()
            except:
                pass
        else:
            self.icon.hide()

        if not loaded_icon and self.icon.get_visible():
            self.icon.hide()

    def on_click(self, event_box, event_button, num):
        hyprctl("dispatch workspace {}".format(num))

    def on_scroll(self, event_box, event):
        if event.direction == Gdk.ScrollDirection.UP:
            hyprctl("dispatch workspace e-1")
        elif event.direction == Gdk.ScrollDirection.DOWN:
            hyprctl("dispatch workspace e+1")

    def on_enter_notify_event(self, widget, event):
        widget.set_state_flags(Gtk.StateFlags.DROP_ACTIVE, clear=False)
        widget.set_state_flags(Gtk.StateFlags.SELECTED, clear=False)

    def on_leave_notify_event(self, widget, event):
        widget.unset_state_flags(Gtk.StateFlags.DROP_ACTIVE)
        widget.unset_state_flags(Gtk.StateFlags.SELECTED)
