import gedit

import dbus
import dbus.service
import dbus.glib
from dbus.mainloop.glib import DBusGMainLoop

class DBusDocument(dbus.service.Object):
    def __init__(self, bus, object_path, parent):
        dbus.service.Object.__init__(self, bus, object_path)
        self._parent = parent
        self._doc = parent._doc

    @dbus.service.method(dbus_interface='org.gnome.gedit.plugin.remotecontrol',
                         in_signature='s', out_signature='s')
    def SayHello(self, txt):
        return 'Hello, %s!' % txt

    @dbus.service.signal(dbus_interface='org.gnome.gedit.plugin.remotecontrol',
                         signature='usu')
    def TextInserted(self, loc, text, len):
        print "emit TextInserted(%d, '%s', %d)" % (loc, text, len)

    @dbus.service.signal(dbus_interface='org.gnome.gedit.plugin.remotecontrol',
                         signature='uu')
    def RangeDeleted(self, start, end):
        print "emit RangeDeleted(%d, %d)" % (start, end)

    @dbus.service.method(dbus_interface='org.gnome.gedit.plugin.remotecontrol',
                         in_signature='usu', out_signature='b')
    def InsertText(self, loc, text, len):
        print 'inserting text %s!' % text
        iter = self._doc.get_iter_at_offset(loc)
        self._parent.dbus_change_in_progress = 1
        self._doc.insert(iter, text, len)
        self._parent.dbus_change_in_progress = 0
        return True

    @dbus.service.method(dbus_interface='org.gnome.gedit.plugin.remotecontrol',
                         in_signature='uu', out_signature='b')
    def DeleteRange(self, start, end):
        print 'deleting text %d %d!' % (start, end)
        self._parent.dbus_change_in_progress = 1
        self._parent.dbus_change_in_progress = 0
        return True


class RemoteControlViewHelper(object):
    def __init__(self, view):
        self._view = view
        self._doc = view.get_buffer()
        self._version = 0
        self.dbus_change_in_progress = 0

        # FIXME: We use a private D-Bus connection, meaning this plugin has
        # its own connection and this connection is not shared with other
        # plugins. I had issues otherwise with the mainloop.
        self._bus = dbus.Bus(private=True, mainloop=DBusGMainLoop())
        self._dbus_doc = DBusDocument(self._bus, "/path/to", self)

        self._handlers = [
            self._doc.connect('insert-text', self.on_insert_text),
            self._doc.connect('delete-range', self.on_delete_range)
        ]

    def deactivate(self):
        self._view.disconnect(self._handlers[0])
        self._view.disconnect(self._handlers[1])

    def on_insert_text(self, doc, loc, text, len):
        if not self.dbus_change_in_progress:
            self._dbus_doc.TextInserted(loc.get_offset(), text, len)

    def on_delete_range(self, doc, start, end):
        if not self.dbus_change_in_progress:
            self._dbus_doc.RangeDeleted(0, 0)

class RemoteControlPlugin(gedit.Plugin):
    WINDOW_DATA_KEY = "RemoteControlPluginWindowData"
    VIEW_DATA_KEY = "RemoteControlPluginViewData"

    def __init__(self):
        super(RemoteControlPlugin, self).__init__()

    def add_helper(self, view):
        helper = RemoteControlViewHelper(view)
        view.set_data(self.VIEW_DATA_KEY, helper)

    def remove_helper(self, view):
        view.get_data(self.VIEW_DATA_KEY).deactivate()
        view.set_data(self.VIEW_DATA_KEY, None)

    def activate(self, window):
        for view in window.get_views():
            self.add_helper(view)
            
        handler_id = window.connect("tab-added",
                                    lambda w, t: self.add_helper(t.get_view()))
        window.set_data(self.WINDOW_DATA_KEY, handler_id)

    def deactivate(self, window):
        handler_id = window.get_data(self.WINDOW_DATA_KEY)
        window.disconnect(handler_id)
        window.set_data(self.WINDOW_DATA_KEY, None)
        
        for view in window.get_views():
            self.remove_helper(view)

    def update_ui(self, window):
        pass

