import time
from random import randint
from Xlib import display, X, XK, ext
from PIL import Image


WINDOW_WIDTH = 1600
WINDOW_HEIGHT = 900
BOARD_X = 367
BOARD_Y = 129
BOARD_WIDTH = 420
BOARD_HEIGHT = 638
KEY_DELAY = 14  # milliseconds


disp = display.Display()


def find_window(name):
    def traverse(window):
        if window.get_wm_name() == name:
            return window

        for child in window.query_tree().children:
            win = traverse(child)
            if win:
                return win

    return traverse(disp.screen().root)


def get_exapunks_window():
    win = find_window('EXAPUNKS')
    assert win, 'EXAPUNKS window not found'
    geo = win.get_geometry()
    assert geo.width == WINDOW_WIDTH
    assert geo.height == WINDOW_HEIGHT
    return win


def focus_window(window):
    window.set_input_focus(X.RevertToNone, X.CurrentTime)
    window.raise_window()
    disp.sync()


def screenshot_board(window):
    raw = window.get_image(BOARD_X, BOARD_Y, BOARD_WIDTH, BOARD_HEIGHT,
                           X.ZPixmap, 0xffffffff)
    dim = BOARD_WIDTH, BOARD_HEIGHT
    im = Image.frombytes('RGB', dim, raw.data, 'raw', 'BGRX')
    return im.convert('HSV')


def press_keys(window, keys):
    assert disp.has_extension('XTEST')
    for key in keys:
        keysym = XK.string_to_keysym(key)
        keycode = disp.keysym_to_keycode(keysym)

        ext.xtest.fake_input(disp, X.KeyPress, keycode)
        disp.sync()
        time.sleep(KEY_DELAY / 1000)

        ext.xtest.fake_input(disp, X.KeyRelease, keycode)
        disp.sync()
        time.sleep(KEY_DELAY / 1000)


def listen_keys(handlers):
    from pynput import keyboard

    def handler(keycode):
        key = str(keycode).replace('\'', '')
        if key in handlers:
            handlers[key]()

    keyboard.Listener(on_release=handler).start()


if __name__ == '__main__':
    win = get_exapunks_window()
    win.raise_window()

    old_focus = disp.get_input_focus()
    disp.set_input_focus(win, X.RevertToParent, X.CurrentTime)

    #press_keys(win, 'aaaj')
    #while True:
    #    press_keys(win, 'djkj' * 7)
    #    press_keys(win, 'ajkj' * 7)

    while True:
        press_keys(win, 'adjk'[randint(0, 3)])

    disp.set_input_focus(old_focus.focus, X.RevertToParent, X.CurrentTime)
    disp.sync()
