import gi
gi.require_version("Gtk", "4.0")
from gi.repository import GLib, Gio, GObject, Gtk
from pydbus import SessionBus
import pydbus.generic


class StatusNotifierWatcher:
    StatusNotifierItemRegistered = pydbus.generic.signal()
    StatusNotifierHostRegistered = pydbus.generic.signal()
    StatusNotifierItemUnregistered = pydbus.generic.signal()

    def __init__(self, bus):
        super().__init__()
        self.hosts = set()
        self.items = set()
        self.bus = bus

        dbus_proxy = self.bus.get("org.freedesktop.DBus", "/org/freedesktop/DBus")
        dbus_proxy.NameOwnerChanged.connect(self._on_name_owner_changed)

    def _on_name_owner_changed(self, name, old_owner, new_owner):
        if new_owner == "":
            removed = False
            for lookup in (name, old_owner):
                if lookup in self.items:
                    self.items.discard(lookup)
                    self.StatusNotifierItemUnregistered(lookup)
                if lookup in self.hosts:
                    self.hosts.discard(lookup)

    def RegisterStatusNotifierItem(self, service_name):
        self.items.add(service_name)
        self.StatusNotifierItemRegistered(service_name)

    def RegisterStatusNotifierHost(self, service_name):
        self.hosts.add(service_name)
        self.StatusNotifierHostRegistered(service_name)

    @property
    def RegisteredStatusNotifierItems(self):
        return sorted(self.items)

    @property
    def IsStatusNotifierHostRegistered(self):
        return bool(self.hosts)

    @property
    def ProtocolVersion(self):
        return 0


class KDEStatusNotifierWatcher(StatusNotifierWatcher):
    """
    <node>
        <interface name="org.kde.StatusNotifierWatcher">
            <method name="RegisterStatusNotifierItem">
                <arg type="s" name="service_name" direction="in"/>
            </method>
            <method name="RegisterStatusNotifierHost">
                <arg type="s" name="service_name" direction="in"/>
            </method>
            <property name="RegisteredStatusNotifierItems" type="as" access="read"/>
            <property name="IsStatusNotifierHostRegistered" type="b" access="read"/>
            <property name="ProtocolVersion" type="i" access="read"/>
            <signal name="StatusNotifierItemRegistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
            <signal name="StatusNotifierItemUnregistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
            <signal name="StatusNotifierHostRegistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
        </interface>
    </node>
    """


class FDStatusNotifierWatcher(StatusNotifierWatcher):
    """
    <node>
        <interface name="org.freedesktop.StatusNotifierWatcher">
            <method name="RegisterStatusNotifierItem">
                <arg type="s" name="service_name" direction="in"/>
            </method>
            <method name="RegisterStatusNotifierHost">
                <arg type="s" name="service_name" direction="in"/>
            </method>
            <property name="RegisteredStatusNotifierItems" type="as" access="read"/>
            <property name="IsStatusNotifierHostRegistered" type="b" access="read"/>
            <property name="ProtocolVersion" type="i" access="read"/>
            <signal name="StatusNotifierItemRegistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
            <signal name="StatusNotifierItemUnregistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
            <signal name="StatusNotifierHostRegistered">
                <arg type="s" name="service" direction="out"/>
            </signal>
        </interface>
    </node>
    """


class WatcherApplication(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="com.roundabout_host.roundabout.PanoramaIndicatorService",
                         flags=Gio.ApplicationFlags.FLAGS_NONE)
        self.bus = None
        self.kde_publishing = None
        self.fd_publishing = None
        self.kde_watcher = None
        self.fd_watcher = None

    def do_startup(self):
        Gtk.Application.do_startup(self)
        self.bus = SessionBus()
        self.kde_watcher = KDEStatusNotifierWatcher(self.bus)
        self.fd_watcher = FDStatusNotifierWatcher(self.bus)
        self.kde_publishing = self.bus.publish(
            f"org.kde.StatusNotifierWatcher",
            ("/StatusNotifierWatcher", self.kde_watcher)
        )
        self.fd_publishing = self.bus.publish(
            f"org.freedesktop.StatusNotifierWatcher",
            ("/StatusNotifierWatcher", self.fd_watcher)
        )

    def do_activate(self):
        print("StatusNotifierWatcher running...")
        self.hold()

    def do_shutdown(self):
        if self.bus:
            if self.kde_publishing:
                self.bus.unpublish(self.kde_publishing)
            if self.fd_publishing:
                self.bus.unpublish(self.fd_publishing)
            print("Unregistered")
        Gtk.Application.do_shutdown(self)


if __name__ == "__main__":
    app = WatcherApplication()
    app.run(None)
