try:
    import Xlib.X
    import Xlib.protocol.event
except ImportError:
    pass


class SelectGagAction:

    def __init__(self, factor_x, factor_y):
        self._button = Xlib.X.Button1
        self._factor_x = factor_x
        self._factor_y = factor_y

    def execute(self, extended_controls, xkeyevent):
        engine_geometry = extended_controls._engine_window.get_geometry()
        smaller_dimension = min(engine_geometry.width, engine_geometry.height)
        attr = dict(
            window=extended_controls.engine_window,
            detail=self._button,
            state=xkeyevent.state,
            event_x=int(engine_geometry.width / 2
                        + smaller_dimension * self._factor_x),
            event_y=int(engine_geometry.height / 2
                        + smaller_dimension * self._factor_y),
            # apparently root_x & root_y do not need to correspond with event_x/y.
            # attributes are still required to be set.
            root_x=0,  # xkeyevent.root_x,
            root_y=0,  # xkeyevent.root_y,
            child=xkeyevent.child,
            root=xkeyevent.root,
            time=xkeyevent.time,  # X.CurrentTime
            same_screen=xkeyevent.same_screen,
        )
        if isinstance(xkeyevent, Xlib.protocol.event.KeyPress):
            e = Xlib.protocol.event.ButtonPress(**attr)
        else:
            e = Xlib.protocol.event.ButtonRelease(**attr)
        extended_controls.engine_window.send_event(e)


class TargetEngine:
    Primary = 1 << 0
    Others = 1 << 1
    All = Primary | Others


class RewriteKeyEventAction:

    def __init__(self, keysym=None, target_engine=TargetEngine.Primary):
        self._keysym = keysym
        self._target_engine = target_engine

    @staticmethod
    def _send_event(event_template, keycode, target_window):
        target_window.send_event(type(event_template)(
            window=target_window,
            detail=keycode,
            state=event_template.state,
            root_x=event_template.root_x,
            root_y=event_template.root_y,
            event_x=event_template.event_x,
            event_y=event_template.event_y,
            child=event_template.child,
            root=event_template.root,
            time=event_template.time,  # X.CurrentTime
            same_screen=event_template.same_screen,
        ))

    def execute(self, extended_controls, xkeyevent):
        defaults = dict(
            keycode=extended_controls.xdisplay.keysym_to_keycode(self._keysym)
                if self._keysym else xkeyevent.detail,
            event_template=xkeyevent,
        )
        if self._target_engine & TargetEngine.Primary:
            self._send_event(
                target_window=extended_controls.engine_window,
                **defaults,
            )
        if self._target_engine & TargetEngine.Others:
            for win in extended_controls.find_other_engine_windows():
                self._send_event(target_window=win, **defaults)


class ForwardKeyEventAction(RewriteKeyEventAction):

    def __init__(self):
        super().__init__(keysym=None)


class ToggleExtendedControlsAction:

    def execute(self, extended_controls, xkeyevent):
        if isinstance(xkeyevent, Xlib.protocol.event.KeyPress):
            extended_controls.toggle()