# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from dom import clear
from elementmaker import E
from book_list.theme import get_color
from gettext import gettext as _

from read_book.shortcuts import shortcut_for_key_event


class Hints:

    def __init__(self, view):
        self.view = view
        container = self.container
        container.setAttribute('tabindex', '0')
        container.style.overflow = 'hidden'
        container.addEventListener('keydown', self.on_keydown, {'passive': False})
        container.addEventListener('click', self.container_clicked, {'passive': False})
        self.reset()

    def reset(self):
        self.hints_map = {}
        self.current_prefix = ''

    @property
    def container(self):
        return document.getElementById('book-hints-overlay')

    @property
    def is_visible(self):
        return self.container.style.display is not 'none'

    def focus(self):
        self.container.focus()

    def hide(self):
        if self.is_visible:
            self.container.style.display = 'none'
            self.send_message('hide')
            self.reset()
            self.view.focus_iframe()

    def show(self):
        if not self.is_visible:
            self.reset()
            c = self.container
            c.style.display = 'block'
            clear(c)
            self.focus()
            self.send_message('show')

    def on_keydown(self, ev):
        ev.preventDefault(), ev.stopPropagation()
        if ev.key is 'Escape':
            self.hide()
            return
        if ev.key is 'Enter':
            if self.current_prefix:
                self.apply_prefix(True)
            return
        if ev.key is 'Backspace':
            if self.current_prefix:
                self.current_prefix = self.current_prefix[:-1]
                self.apply_prefix()
            return
        hint_keys = list('1234567890abcdefghijklmnopqrstuvwxyz')
        q = ev.key.toLowerCase()
        if hint_keys.indexOf(q) > -1:
            self.current_prefix += q
            self.apply_prefix()

        sc_name = shortcut_for_key_event(ev, self.view.keyboard_shortcut_map)
        if not sc_name:
            return

    def container_clicked(self, ev):
        ev.stopPropagation(), ev.preventDefault()
        self.hide()

    def apply_prefix(self, accept_full_match):
        matches = v'[]'
        if self.current_prefix:
            for k in Object.keys(self.hints_map):
                if k is '_length':
                    continue
                q = encode(int(k))
                if accept_full_match:
                    if q is self.current_prefix:
                        matches.push(k)
                        break
                elif q.startswith(self.current_prefix):
                    matches.push(k)
        if matches.length is 1:
            self.send_message('activate', hint=self.hints_map[matches[0]])
            self.hide()
        else:
            self.send_message('apply_prefix', prefix=self.current_prefix)

    def send_message(self, type, **kw):
        self.view.iframe_wrapper.send_message('hints', type=type, **kw)

    def handle_message(self, msg):
        if msg.type is 'shown':
            self.reset()
            self.hints_map = msg.hints_map
            if not self.hints_map._length:
                self.no_hints_found()

    def no_hints_found(self):
        c = self.container
        c.appendChild(E.div(
            _('No links found. Press Esc to close'),
            style=f'position: absolute; margin: auto; top: 50%; left: 50%; background: {get_color("window-background")};' +
                  ' padding: 1rem; border: solid 1px currentColor; border-radius: 4px; transform: translate(-50%, -50%);'
        ))


def is_visible(a):
    if not a.offsetParent:
        return False
    rect = a.getBoundingClientRect()
    return rect.left >= 0 and rect.top >= 0 and rect.left < window.innerWidth and rect.top < window.innerHeight


def encode(i):
    return i.toString(36).toLowerCase()


def hint_visible_links():
    i = 0
    hint_map = {}
    for a in document.body.querySelectorAll('a[href]'):
        if is_visible(a):
            i += 1
            h = i + ''
            a.dataset.calibreHintRender = encode(i)
            a.dataset.calibreHintValue = h
            a.classList.add('calibre-hint-visible')
            hint_map[h] = {'type': 'link', 'value': i}
    hint_map._length = i
    return hint_map


def unhint_links():
    for a in document.body.querySelectorAll('a[href]'):
        a.classList.remove('calibre-hint-visible', 'calibre-hint-enter')
        v'delete a.dataset.calibreHintRender'
        v'delete a.dataset.calibreHintValue'


def apply_prefix_to_hints(prefix):
    for a in document.body.querySelectorAll('[data-calibre-hint-value]'):
        val = int(a.dataset.calibreHintValue)
        r = encode(val)
        a.classList.remove('calibre-hint-enter')
        if not prefix or r.startsWith(prefix):
            a.classList.add('calibre-hint-visible')
            a.dataset.calibreHintRender = leftover = r[prefix.length:] or '\xa0'
            if leftover is '\xa0':
                a.classList.add('calibre-hint-enter')
        else:
            a.classList.remove('calibre-hint-visible')
