# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2015, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import hash_literals

from dom import build_rule, clear, svgicon, create_keyframes, set_css, change_icon_image, add_extra_css, ensure_id
from elementmaker import E

from book_list.theme import get_color

# Button {{{

def create_button(text, icon=None, action=None, tooltip=None, highlight=False, download_filename=None, class_=''):
    ic = ''
    if icon:
        ic = svgicon(icon)
        text = '\xa0' + text
    ans = E.a(ic, E.span(text), class_='calibre-push-button ' + class_, href='javascript: void(0)', role='button', title=tooltip or '')
    if download_filename and v'"download" in ans':
        ans.setAttribute('download', download_filename)
    if action is not None:
        if jstype(action) is 'string':
            ans.setAttribute('href', action)
        else:
            ans.addEventListener('click', def(event): event.preventDefault(), action(event);)
    if highlight:
        set_css(ans, font_size='larger', font_weight='bold')
    return ans

create_button.style = build_rule('a.calibre-push-button',
    border_radius='1em', background_clip='padding-box', background_color=get_color('button-start'),
    background_image='linear-gradient(to bottom, {}, {})'.format(get_color('button-start'), get_color('button-end')),
    padding='0.5ex 1em', color=get_color('button-text'), cursor='pointer', font_size='inherit', display='inline-flex',
    align_items='center', user_select='none',
    box_shadow='0px 2px 1px rgba(50, 50, 50, 0.75)', white_space='nowrap'
)
create_button.style += build_rule('a.calibre-push-button:hover', transform='scale(1.05)')
create_button.style += build_rule('a.calibre-push-button:active', transform='scale(1.1)')
# This is needed because of a bug in Firefox: https://bugs.launchpad.net/bugs/1881385
create_button.style += build_rule('a.calibre-push-button:visited', color=get_color('button-text'))
# }}}

# Spinner {{{
def create_spinner(height, width):
    ans = svgicon('cog', height, width)
    ans.classList.add('spin')
    return ans

create_spinner.style  = build_rule('.spin', animation='spin 2s infinite linear')
create_spinner.style += create_keyframes('spin', 'from { transform: rotate(0deg); } to { transform: rotate(359deg);}')

# }}}

# Breadcrumbs {{{

class Breadcrumbs:

    STYLE_RULES =  build_rule(
        '.calibre-breadcrumbs',
        user_select='none', white_space='nowrap', background_color=get_color('window-background2'),
        z_index='-1', border_radius='10px', margin='1ex 1em', margin_bottom='0'
    )

    STYLE_RULES += build_rule(
        '.calibre-breadcrumbs > li',
        cursor='pointer', display='inline-block', line_height='26px', margin='0 9px 0 -10px',
        padding='0.5ex 1rem', position='relative'
    )

    STYLE_RULES += build_rule('.calibre-breadcrumbs > li:hover', color=get_color('window-hover-foreground'))

    STYLE_RULES += build_rule('.calibre-breadcrumbs > li:active', color=get_color('window-hover-foreground'), transform='scale(1.5)')

    STYLE_RULES += build_rule(
        '.calibre-breadcrumbs > li:before, .calibre-breadcrumbs > li:after',
        border_right='2px solid currentColor', content='""', display='block', height='50%',
        position='absolute', left='0', top='0', right='0', transform='skewX(45deg)'
    )

    STYLE_RULES += build_rule(
        '.calibre-breadcrumbs > li:after',
        bottom='0', top='auto', transform='skewX(-45deg)'
    )

    STYLE_RULES += build_rule(
        '.calibre-breadcrumbs > li:last-of-type:before, .calibre-breadcrumbs > li:last-of-type:after',
        display='none')


    def __init__(self, container):
        self.container_id = ensure_id(container, 'calibre-breadcrumbs-')
        container.classList.add('calibre-breadcrumbs')
        clear(container)

    @property
    def container(self):
        return document.getElementById(self.container_id)

    def reset(self):
        clear(self.container)

    def add_crumb(self, callback):
        li = E.li()
        if callback:
            li.addEventListener('click', callback)
        self.container.appendChild(li)
        return li
# }}}

# Simple Tree {{{

def create_tree(root, populate_data, onclick):
    container = E.div(class_='simple-tree')
    set_css(container, overflow='auto')

    def toggle_node(li):
        if li.dataset.treeState is 'closed':
            li.dataset.treeState = 'open'
            li.lastChild.style.display = 'block'
            change_icon_image(li.firstChild.firstChild, 'caret-down')
        else:
            li.dataset.treeState = 'closed'
            li.lastChild.style.display = 'none'
            change_icon_image(li.firstChild.firstChild, 'caret-right')

    def bullet(icon):
        ans = svgicon(icon, '2ex', '2ex')
        ans.style.minWidth = '2ex'
        ans.style.minHeight = '2ex'
        return ans

    def process_node(node, parent_container, level):
        if node.children?.length:
            ul = E.div()
            parent_container.appendChild(ul)
            for child in node.children:
                icon = 'caret-right' if child.children?.length else None
                li = E.div(style='display:flex; flex-direction:column; margin: 1ex 1em; margin-left: {}em'.format(level+1),
                    E.div(style='display:flex; align-items: center',
                        bullet(icon),
                        E.span('\xa0'),
                        E.a(
                            href='javascript: void(0)',
                            class_='simple-link tree-item-title',
                            onclick=def (event):
                                if onclick:
                                    if event.button is 0:
                                        event.preventDefault(), event.stopPropagation()
                                    onclick(event, event.currentTarget.parentNode.parentNode)
                        ),
                    ),
                    E.div(style='display:none', data_tree_subtree_container='1'),
                    data_tree_state='closed',
                )
                ul.appendChild(li)
                populate_data(child, li, li.firstChild.lastChild)
                if icon:
                    set_css(li.firstChild.firstChild, cursor='pointer')
                    li.firstChild.firstChild.addEventListener('click', def(event):
                        toggle_node(event.currentTarget.parentNode.parentNode)
                    )
                    process_node(child, li.lastChild, level + 1)

    if root:
        process_node(root, container, 0)
    return container

def find_text_in_tree(container, q):
    q = q.lower()
    last_match = container.querySelector('a[data-tree-last-match]')
    if last_match:
        last_match.parentNode.style.backgroundColor = 'transparent'
        last_match.parentNode.style.borderRadius = '0'
        lm = last_match.getAttribute('data-tree-last-match')
        last_match.removeAttribute('data-tree-last-match')
        if lm is not q:
            last_match = None
    if not q:
        return
    before = []
    seen = False
    ans = None

    for a in container.querySelectorAll('a.tree-item-title'):
        if a is last_match:
            seen = True
        else:
            if a.textContent.lower().indexOf(q) != -1:
                if seen:
                    ans = a
                    break
                if last_match is None:
                    ans = a
                    break
                before.push(a)
    if not ans and before.length:
        ans = before[0]
    ans = ans or last_match
    if ans:
        ans.dataset.treeLastMatch = q
    if ans:
        ans.parentNode.style.backgroundColor = get_color('tree-highlight-item')
        ans.parentNode.style.borderRadius = '5px'
        ans = ans.parentNode.parentNode
    return ans

def scroll_tree_item_into_view(item):
    p = item.parentNode?.parentNode
    while p and p.getAttribute('data-tree-subtree-container'):
        p.style.display = 'block'
        p = p.parentNode?.parentNode?.parentNode
    item.scrollIntoView()

# }}}

add_extra_css(def():
    ans = 'a, button:focus { outline: none }; a, button::-moz-focus-inner { border: 0 }\n'
    ans += '.simple-link { cursor: pointer } .simple-link:hover { color: HC } .simple-link:active { transform: scale(1.5) }\n'.replace('HC', get_color('window-hover-foreground'))
    ans += '.blue-link { cursor: pointer; color: COL } .blue-link:visited { color: COL} .blue-link:hover { color: HC } .blue-link:active { transform: scale(1.5) }\n'.replace('HC', get_color('window-hover-foreground')).replace(/COL/g, get_color('link-foreground'))
    ans += create_button.style + '\n'
    ans += create_button.style + '\n'
    ans += create_spinner.style + '\n'
    ans += Breadcrumbs.STYLE_RULES + '\n'
    # Chrome hardcodes the size of these to 13.3px. In safari on some devices
    # the font size is smaller than the body font size and small enough to
    # trigger page zooms. So set it to 1em so they scale with body font size.
    ans += '''
        select, textarea, input[type="text"], input[type="password"],
        input[type="datetime"], input[type="datetime-local"],
        input[type="date"], input[type="month"], input[type="time"],
        input[type="week"], input[type="number"], input[type="email"],
        input[type="url"], input[type="search"] { font-size: 1em }
    '''
    return ans
)


def enable_escape_key(container, action):
    container.setAttribute('tabindex', '0')
    container.addEventListener('keydown', def(ev):
        if ev.key is 'Escape':
            ev.stopPropagation(), ev.preventDefault()
            action()
    , {'passive': False})
    container.focus()
