"""
This module defines a thread which watches for input from a stream, processes
it, and calls callbacks when the input matches registered patterns.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import select
import sys
import termios
import tty

import six

from . import common


class Interactor(common.ThreadInterface):
    def __init__(self, input_stream=sys.stdin):
        super(Interactor, self).__init__()
        self._stream = input_stream
        self._old_attrs = termios.tcgetattr(self._stream)
        self._registered_key_presses = {}

    def run(self):
        try:
            tty.setcbreak(self._stream, termios.TCSADRAIN)
            super(Interactor, self).run()
        finally:
            termios.tcsetattr(self._stream, termios.TCSADRAIN, self._old_attrs)

    def _run_impl(self):
        c = self._read_char()
        if c is None:
            return
        elif c in self._registered_key_presses:
            for callback in self._registered_key_presses[c]:
                callback()

    def register_key_press_callback(self, char, callback):
        assert isinstance(char, six.string_types)
        assert callable(callback)
        if char not in self._registered_key_presses:
            self._registered_key_presses[char] = []
        self._registered_key_presses[char].append(callback)

    def delete_key_press_callback(self, char):
        del self._registered_key_presses[char]

    def _read_char(self):
        if select.select([self._stream], [], [], 0) == ([self._stream], [], []):
            c = self._stream.read(1)
            if c == '\x1b':
                c += self._stream.read(2)
                if c == '\x1b[C':
                    return 'right_arrow'
                elif c == '\x1b[A':
                    return 'up_arrow'
                elif c == '\x1b[B':
                    return 'down_arrow'
                elif c == '\x1b[D':
                    return 'left_arrow'
            return c
