from kmk.keys import FIRST_KMK_INTERNAL_KEY, KC, ModifierKey, make_key
from kmk.modules import Module


class CapsWord(Module):
    # default timeout is 8000
    # alphabets, numbers and few more keys will not disable capsword
    def __init__(self, timeout=8000):
        self._alphabets = range(KC.A.code, KC.Z.code)
        self._numbers = range(KC.N1.code, KC.N0.code)
        self.keys_ignored = [
            KC.MINS,
            KC.BSPC,
            KC.UNDS,
        ]
        self._timeout_key = False
        self._cw_active = False
        self.timeout = timeout
        make_key(
            names=(
                'CAPSWORD',
                'CW',
            ),
            on_press=self.cw_pressed,
        )

    def during_bootup(self, keyboard):
        return

    def before_matrix_scan(self, keyboard):
        return

    def process_key(self, keyboard, key, is_pressed, int_coord):
        if self._cw_active and key != KC.CW:
            continue_cw = False
            # capitalize alphabets
            if key.code in self._alphabets:
                continue_cw = True
                keyboard.process_key(KC.LSFT, is_pressed)
            elif (
                key.code in self._numbers
                or isinstance(key, ModifierKey)
                or key in self.keys_ignored
                or key.code
                >= FIRST_KMK_INTERNAL_KEY  # user defined keys are also ignored
            ):
                continue_cw = True
            # requests and cancels existing timeouts
            if is_pressed:
                if continue_cw:
                    self.discard_timeout(keyboard)
                    self.request_timeout(keyboard)
                else:
                    self.process_timeout()

        return key

    def before_hid_send(self, keyboard):
        return

    def after_hid_send(self, keyboard):
        return

    def on_powersave_enable(self, keyboard):
        return

    def on_powersave_disable(self, keyboard):
        return

    def after_matrix_scan(self, keyboard):
        return

    def process_timeout(self):
        self._cw_active = False
        self._timeout_key = False

    def request_timeout(self, keyboard):
        if self._cw_active:
            if self.timeout:
                self._timeout_key = keyboard.set_timeout(
                    self.timeout, lambda: self.process_timeout()
                )

    def discard_timeout(self, keyboard):
        if self._timeout_key:
            if self.timeout:
                keyboard.cancel_timeout(self._timeout_key)
            self._timeout_key = False

    def cw_pressed(self, key, keyboard, *args, **kwargs):
        # enables/disables capsword
        if key == KC.CW:
            if not self._cw_active:
                self._cw_active = True
                self.discard_timeout(keyboard)
                self.request_timeout(keyboard)
            else:
                self.discard_timeout(keyboard)
                self.process_timeout()