from functools import partial
import subprocess

from zorro.di import has_dependencies, dependency

from .event import Event
from .xcb import Core


class Events(dict):

    def __missing__(self, key):
        res = self[key] = Event('changed.'+key)
        return res


class CommandDispatcher(dict):

    def __init__(self):
        self.events = Events()

    def __setitem__(self, name, value):
        super().__setitem__(name, value)
        ev = self.events.get(name)
        if ev is not None:
            ev.emit()

    def call(self, obj, meth, *args):
        getattr(self[obj], 'cmd_' + meth)(*args)

    def callback(self, *args):
        return partial(self.call, *args)


class EnvCommands(object):

    def cmd_exec(self, *args):
        subprocess.Popen(args)

    def cmd_shell(self, *args):
        subprocess.Popen(args, shell=True)

@has_dependencies
class EmulCommands(object):

    keyregistry = dependency(object, 'key-registry')  # circ dependency
    commander = dependency(CommandDispatcher, 'commander')
    xcore = dependency(Core, 'xcore')

    def cmd_key(self, keystr):
        mod, sym = self.keyregistry.parse_key(keystr)
        code = self.xcore.keysym_to_keycode[sym][0]
        self.xcore.xtest.FakeInput(
            type=2,
            detail=code,
            time=0,
            root=self.xcore.root_window,
            rootX=0,
            rootY=0,
            deviceid=0,
            )
        self.xcore.xtest.FakeInput(
            type=3,
            detail=code,
            time=100,
            root=self.xcore.root_window,
            rootX=0,
            rootY=0,
            deviceid=0,
            )




@@ -1648,10 +1648,508 @@
      )%0A%0A
+    def cmd_button(self, num):%0A        num = int(num)%0A        self.xcore.xtest.FakeInput(%0A            type=4,%0A            detail=num,%0A            time=0,%0A            root=self.xcore.root_window,%0A            rootX=0,%0A            rootY=0,%0A            deviceid=0,%0A            )%0A        self.xcore.xtest.FakeInput(%0A            type=5,%0A            detail=num,%0A            time=30,%0A            root=self.xcore.root_window,%0A            rootX=0,%0A            rootY=0,%0A            deviceid=0,%0A            )%0A%0A
 %0A%0A

Implement fake mouse button command (`emul button 8`)