import hid, keycodes, time

default_delay = 0

modifier_keys = {
    'CTRL': keycodes.MOD_LEFT_CONTROL,
    'CONTROL': keycodes.MOD_LEFT_CONTROL,
    'ALT': keycodes.MOD_LEFT_ALT,
    'SHIFT': keycodes.MOD_LEFT_SHIFT,
    'GUI': keycodes.MOD_LEFT_WIN,
    'WINDOWS': keycodes.MOD_LEFT_WIN,
}

special_keys = {
    'ESC': keycodes.ESCAPE,
    'ENTER': keycodes.ENTER,
    'ESCAPE': keycodes.ESCAPE,
    'BREAK': keycodes.PAUSE,
    'PAUSE': keycodes.PAUSE,
    'CAPS': keycodes.CAPS_LOCK,
    'CAPSLOCK': keycodes.CAPS_LOCK,
    'DELETE': keycodes.DELETE,
    'HOME': keycodes.HOME,
    'END': keycodes.END,
    'INSERT': keycodes.INSERT,
    'NUMLOCK': keycodes.KEYPAD_NUMLOCK,
    'PAGEUP': keycodes.PAGE_UP,
    'PAGEDOWN': keycodes.PAGE_DOWN,
    'PRINTSCREEN': keycodes.PRINT_SCREEN,
    'SCROLLOCK': keycodes.SCROLL_LOCK,
    'SPACE': keycodes.SPACE,
    'TAB': keycodes.TAB,
    'LEFT': keycodes.LEFT_ARROW,
    'RIGHT': keycodes.RIGHT_ARROW,
    'UP': keycodes.UP_ARROW,
    'DOWN': keycodes.DOWN_ARROW,
    'POWER': keycodes.POWER,
}

def cmd_unknown(cmd_words):
    print('I don\'t  know what command this is: %s' % ' '.join(cmd_words))


def cmd_comment(cmd_words):
    if cmd_words[0] not in ['REM']:
        print('Wrong function called for command: %s' % ' '.join(cmd_words))


def cmd_default_delay(cmd_words):
    if len(cmd_words) != 2:
        print('Wrong number of arguments for command: %s' % ' '.join(cmd_words))
    if cmd_words[0] not in ['DEFAULT_DELAY']:
        print('Wrong function called for command: %s' % ' '.join(cmd_words))
    delay = int(cmd_words[1])
    global default_delay
    default_delay = delay


def cmd_delay(cmd_words):
    if len(cmd_words) != 2:
        print('Wrong number of arguments for command: %s' % ' '.join(cmd_words))
    if cmd_words[0] not in ['DELAY']:
        print('Wrong function called for command: %s' % ' '.join(cmd_words))
    delay = int(cmd_words[1])
    if delay > 0:
        time.sleep(float(delay) / 1000)


def cmd_string(cmd_words):
    if len(cmd_words) < 2:
        print('Wrong number of arguments for command: %s' % ' '.join(cmd_words))
    if cmd_words[0] not in ['STRING']:
        print('Wrong function called for command: %s' % ' '.join(cmd_words))
    text = ' '.join(cmd_words[1:])
    if len(text) > 0:
        hid.keyboard_type(text)


def cmd_keys(cmd_words):
    codes = []
    modifiers = 0

    for word in cmd_words:
        if word in special_keys:
            codes.append(special_keys[word])
        elif word in modifier_keys:
            modifiers |= modifier_keys[word]
        elif len(word) == 1:
            codes.append(keycodes.char_to_keycode(word.lower())[0])
        else:
            print('Unknown command or letter "%s"' % word)

    if len(codes) > 6:
        print('Warning: maximally 6 keys may be sent at the same time. \
        Truncating to first 6.')
        codes = codes[:6]

    print('mods: %d codes:' % modifiers, codes)
    hid.keyboard_press_keys(bytes(codes), bytes([modifiers]))


command_dict = {
    'REM': cmd_comment,
    'DEFAULTDELAY': cmd_default_delay,
    'DEFAULT_DELAY': cmd_default_delay,
    'DELAY': cmd_delay,
    'STRING': cmd_string,
}


def run_commands(commands):
    prev_command = None
    for command in commands:
        words = command.split(' ')
        name = words[0]
        if name in command_dict:
            # Command is a known command
            print('Running %s' % name)
            command_dict[name](words)
        elif name is 'REPEAT' and prev_command is not None:
            # Command is a REPEAT command, that repeats the previous command N times
            if len(words) != 2:
                print('Invalid number of arguments for REPEAT command. \
                Usage: REPEAT <number of times to repeat last command>')
                continue
            number_repeats = int(words[1])
            run_commands([prev_command] * number_repeats)
        else:
            # Command might be separate keys, i.e. CTRL, or ALT, or DELETE, etc.,
            # followed by zero or more other keys
            print('Sending keys:', command)
            cmd_keys(words)

        hid.keyboard_release()

        if default_delay > 0:
            time.sleep(float(default_delay) / 1000)

        prev_command = command


def run_script(filename):
    with open(filename) as f:
        script_contents = f.read()
        
    commands = script_contents.replace('\r', '').split('\n')
    
    # If script ended in a newline, skip the empty last line
    if len(commands[-1]) == 0:
        commands = commands[:-1]
        
    return run_commands(commands)