"""Terminal capability builder patterns."""
# std imports
import re
import typing
from collections import OrderedDict

__all__ = (
    'CAPABILITY_DATABASE',
    'CAPABILITIES_RAW_MIXIN',
    'CAPABILITIES_ADDITIVES',
    'CAPABILITIES_HORIZONTAL_DISTANCE',
    'CAPABILITIES_CAUSE_MOVEMENT',
)

CAPABILITY_DATABASE: \
    typing.OrderedDict[str, typing.Tuple[str, typing.Dict[str, typing.Any]]] = OrderedDict((
        ('bell', ('bel', {})),
        ('carriage_return', ('cr', {})),
        ('change_scroll_region', ('csr', {'nparams': 2})),
        ('clear_all_tabs', ('tbc', {})),
        ('clear_screen', ('clear', {})),
        ('clr_bol', ('el1', {})),
        ('clr_eol', ('el', {})),
        ('clr_eos', ('clear_eos', {})),
        ('column_address', ('hpa', {'nparams': 1})),
        ('cursor_address', ('cup', {'nparams': 2, 'match_grouped': True})),
        ('cursor_down', ('cud1', {})),
        ('cursor_home', ('home', {})),
        ('cursor_invisible', ('civis', {})),
        ('cursor_left', ('cub1', {})),
        ('cursor_normal', ('cnorm', {})),
        ('cursor_report', ('u6', {'nparams': 2, 'match_grouped': True})),
        ('cursor_right', ('cuf1', {})),
        ('cursor_up', ('cuu1', {})),
        ('cursor_visible', ('cvvis', {})),
        ('delete_character', ('dch1', {})),
        ('delete_line', ('dl1', {})),
        ('enter_blink_mode', ('blink', {})),
        ('enter_bold_mode', ('bold', {})),
        ('enter_dim_mode', ('dim', {})),
        ('enter_fullscreen', ('smcup', {})),
        ('enter_standout_mode', ('standout', {})),
        ('enter_superscript_mode', ('superscript', {})),
        ('enter_susimpleript_mode', ('susimpleript', {})),
        ('enter_underline_mode', ('underline', {})),
        ('erase_chars', ('ech', {'nparams': 1})),
        ('exit_alt_charset_mode', ('rmacs', {})),
        ('exit_am_mode', ('rmam', {})),
        ('exit_attribute_mode', ('sgr0', {})),
        ('exit_ca_mode', ('rmcup', {})),
        ('exit_fullscreen', ('rmcup', {})),
        ('exit_insert_mode', ('rmir', {})),
        ('exit_standout_mode', ('rmso', {})),
        ('exit_underline_mode', ('rmul', {})),
        ('flash_hook', ('hook', {})),
        ('flash_screen', ('flash', {})),
        ('insert_line', ('il1', {})),
        ('keypad_local', ('rmkx', {})),
        ('keypad_xmit', ('smkx', {})),
        ('meta_off', ('rmm', {})),
        ('meta_on', ('smm', {})),
        ('orig_pair', ('op', {})),
        ('parm_down_cursor', ('cud', {'nparams': 1})),
        ('parm_left_cursor', ('cub', {'nparams': 1, 'match_grouped': True})),
        ('parm_dch', ('dch', {'nparams': 1})),
        ('parm_delete_line', ('dl', {'nparams': 1})),
        ('parm_ich', ('ich', {'nparams': 1})),
        ('parm_index', ('indn', {'nparams': 1})),
        ('parm_insert_line', ('il', {'nparams': 1})),
        ('parm_right_cursor', ('cuf', {'nparams': 1, 'match_grouped': True})),
        ('parm_rindex', ('rin', {'nparams': 1})),
        ('parm_up_cursor', ('cuu', {'nparams': 1})),
        ('print_screen', ('mc0', {})),
        ('prtr_off', ('mc4', {})),
        ('prtr_on', ('mc5', {})),
        ('reset_1string', ('r1', {})),
        ('reset_2string', ('r2', {})),
        ('reset_3string', ('r3', {})),
        ('restore_cursor', ('rc', {})),
        ('row_address', ('vpa', {'nparams': 1})),
        ('save_cursor', ('sc', {})),
        ('scroll_forward', ('ind', {})),
        ('scroll_reverse', ('rev', {})),
        ('set0_des_seq', ('s0ds', {})),
        ('set1_des_seq', ('s1ds', {})),
        ('set2_des_seq', ('s2ds', {})),
        ('set3_des_seq', ('s3ds', {})),
        # this 'color' is deceiving, but often matching, and a better match
        # than set_a_attributes1 or set_a_foreground.
        ('color', ('_foreground_color', {'nparams': 1, 'match_any': True, 'numeric': 1})),
        ('set_a_foreground', ('color', {'nparams': 1, 'match_any': True, 'numeric': 1})),
        ('set_a_background', ('on_color', {'nparams': 1, 'match_any': True, 'numeric': 1})),
        ('set_tab', ('hts', {})),
        ('tab', ('ht', {})),
        ('italic', ('sitm', {})),
        ('no_italic', ('sitm', {})),
    ))

_ESC = re.escape('\x1b')
_CSI = rf'{_ESC}\['
_ANY_NOTESC = rf'[^{_ESC}]*'

CAPABILITIES_RAW_MIXIN: typing.Dict[str, str] = {
    'bell': re.escape('\a'),
    'carriage_return': re.escape('\r'),
    'cursor_left': re.escape('\b'),
    'cursor_report': rf'{_CSI}(\d+)\;(\d+)R',
    'cursor_right': rf'{_CSI}C',
    'exit_attribute_mode': rf'{_CSI}m',
    'parm_left_cursor': rf'{_CSI}(\d+)D',
    'parm_right_cursor': rf'{_CSI}(\d+)C',
    'restore_cursor': rf'{_CSI}u',
    'save_cursor': rf'{_CSI}s',
    'scroll_forward': re.escape('\n'),
    'set0_des_seq': re.escape('\x1b(B'),
    'tab': re.escape('\t'),
}


CAPABILITIES_ADDITIVES: typing.Dict[
    str, typing.Union[typing.Tuple[str, str, int], typing.Tuple[str, str]]] = {
    'link': (rf'{_ESC}\]8;{_ANY_NOTESC};{_ANY_NOTESC}{_ESC}\\', 'link', 1),
    'color256': (rf'{_CSI}38;5;\d+m', 'color', 1),
    'on_color256': (rf'{_CSI}48;5;\d+m', 'on_color', 1),
    'color_rgb': (rf'{_CSI}38;2;\d+;\d+;\d+m', 'color_rgb', 3),
    'on_color_rgb': (rf'{_CSI}48;2;\d+;\d+;\d+m', 'on_color_rgb', 3),
    'shift_in': (re.escape('\x0f'), ''),
    'shift_out': (re.escape('\x0e'), ''),
    # sgr(...) outputs strangely, use the basic ANSI/EMCA-48 codes here.
    'set_a_attributes1': (rf'{_CSI}\d+m', 'sgr', 1),
    'set_a_attributes2': (rf'{_CSI}\d+\;\d+m', 'sgr', 2),
    'set_a_attributes3': (rf'{_CSI}\d+\;\d+\;\d+m', 'sgr', 3),
    'set_a_attributes4': (rf'{_CSI}\d+\;\d+\;\d+\;\d+m', 'sgr', 4),
    # this helps where xterm's sgr0 includes set0_des_seq, we'd
    # rather like to also match this immediate substring.
    'sgr0': (rf'{_CSI}m', 'sgr0'),
    'backspace': (re.escape('\b'), ''),
    'ascii_tab': (CAPABILITIES_RAW_MIXIN['tab'], ''),
    'clr_eol': (rf'{_CSI}K', ''),
    'clr_eol0': (rf'{_CSI}0K', ''),
    'clr_bol': (rf'{_CSI}1K', ''),
    'clr_eosK': (rf'{_CSI}2K', ''),
}

CAPABILITIES_HORIZONTAL_DISTANCE: typing.Dict[str, int] = {
    'ascii_tab': 8,
    'backspace': -1,
    'cursor_left': -1,
    'cursor_right': 1,
    'parm_left_cursor': -1,
    'parm_right_cursor': 1,
    'tab': 8,
}

CAPABILITIES_CAUSE_MOVEMENT: typing.Tuple[str, ...] = tuple(CAPABILITIES_HORIZONTAL_DISTANCE) + (
    'carriage_return',
    'clear_screen',
    'column_address',
    'cursor_address',
    'cursor_down',
    'cursor_home',
    'cursor_up',
    'enter_fullscreen',
    'exit_fullscreen',
    'parm_down_cursor',
    'parm_up_cursor',
    'restore_cursor',
    'row_address',
    'scroll_forward',
)
