#------------------------------------------------------------------------------
# Copyright (c) 2013-2025, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
import re

from enaml.styling import StyleCache


_grad_re = re.compile(r'(lineargradient|radialgradient)')

_alert_re = re.compile(r'alert\((-?[_a-zA-Z][_a-zA-Z0-9-]*)\)')


def _translate_gradient(v):
    return _grad_re.sub(r'q\1', v)


_KNOWN_FIELDS = set([
    'alternate-background-color',
    'background',
    'background-clip',
    'background-color',
    'border',
    'border-top',
    'border-right',
    'border-bottom',
    'border-left',
    'border-color',
    'border-top-color',
    'border-right-color',
    'border-bottom-color',
    'border-left-color',
    'border-radius',
    'border-top-left-radius',
    'border-top-right-radius',
    'border-bottom-right-radius',
    'border-bottom-left-radius',
    'border-style',
    'border-top-style',
    'border-right-style',
    'border-bottom-style',
    'border-left-style',
    'border-width',
    'border-top-width',
    'border-right-width',
    'border-bottom-width',
    'border-left-width',
    'bottom',
    'color',
    'font',
    'font-family',
    'font-size',
    'font-style',
    'font-weight',
    'height',
    'icon-size',
    'left',
    'line-edit-password-character',
    'margin',
    'margin-top',
    'margin-right',
    'margin-bottom',
    'margin-left',
    'max-height',
    'max-width',
    'min-height',
    'min-width',
    'padding',
    'padding-top',
    'padding-right',
    'padding-bottom',
    'padding-left',
    'position',
    'right',
    'selection-background-color',
    'selection-color',
    'spacing',
    'subcontrol-origin',
    'subcontrol-position',
    'text-align',
    'text-decoration',
    'top',
    'width',
])


_MAY_HAVE_GRADIENT = set([
    'background',
    'background-color',
    'border',
    'border-top',
    'border-right',
    'border-bottom',
    'border-left',
    'border-color',
    'border-top-color',
    'border-right-color',
    'border-bottom-color',
    'border-left-color',
    'color',
    'selection-background-color',
    'selection-color',
])


def _translate_setter(setter):
    field = setter.field
    if field in _KNOWN_FIELDS:
        value = setter.value
        if value:
            if field in _MAY_HAVE_GRADIENT:
                value = _translate_gradient(value)
            value = '    %s: %s;' % (field, value)
            return value


def _translate_style_body(style):
    translated = []
    for setter in style.setters():
        tks = StyleCache.toolkit_setter(setter, _translate_setter)
        if tks is not None:
            translated.append(tks)
    return '\n'.join(translated)


def translate_style(name, style):
    parts = ['#%s' % name]
    if style.pseudo_element:
        root = parts.pop()
        for pe in style.pseudo_element.split(','):
            parts.append(root + '::%s' % pe.strip())
    if style.pseudo_class:
        these = parts[:]
        parts = []
        for pc in style.pseudo_class.split(','):
            pc = pc.strip()
            for this in these:
                parts.append(this + ':%s' % pc)
    selector = ','.join(parts)
    body = '{\n%s\n}' % _translate_style_body(style)
    return '%s %s' % (selector, body)


#------------------------------------------------------------------------------
# Dock Area Styling
#------------------------------------------------------------------------------
def _basic_pc(root, pc):
    if pc:
        root += ':%s' % pc
    return root


def _base_dock_area(name, pc):
    rest = []
    floating = False
    for part in pc.split(':'):
        if part == 'floating':
            floating = True
        else:
            rest.append(part)
    if floating:
        root = 'QDockWindow > QDockArea'
    else:
        root = 'QDockArea'
    return _basic_pc(root, ':'.join(rest))


def _dock_bar(name, pc):
    return _basic_pc('QDockBar', pc)


def _dock_bar_button(name, pc):
    return _maybe_alert('QDockBarButton', name, pc)


_position_map = {'top': '0', 'right': '1', 'bottom': '2', 'left': '3'}
def _dock_bar_handle(name, pc):
    rest = []
    position = None
    for part in pc.split(':'):
        if part in _position_map:
            position = _position_map[part]
        else:
            rest.append(part)
    if position is not None:
        root = 'QDockBarItem[position="%s"] QDockBarItemHandle' % position
    else:
        root = 'QDockBarItem QDockBarItemHandle'
    return _basic_pc(root, ':'.join(rest))


def _dock_container(name, pc):
    rest = []
    tabbed = False
    floating = False
    for part in pc.split(':'):
        if part == 'tabbed':
            tabbed = True
        elif part == 'floating':
            floating = True
        else:
            rest.append(part)
    if tabbed:
        root = 'QDockTabWidget QDockContainer'
    elif floating:
        root = 'QDockContainer[floating="true"]'
    else:
        root = 'QDockContainer'
    return _maybe_alert(root, name, ':'.join(rest))


def _dock_window(name, pc):
    return _basic_pc('QDockWindow', pc)


def _dock_window_button(name, pc):
    return _basic_pc('QDockWindowButtons QBitmapButton', pc)


def _dock_window_close_button(name, pc):
    return _basic_pc('QBitmapButton#dockwindow-close-button', pc)


def _dock_window_link_button(name, pc):
    return _basic_pc('QBitmapButton#dockwindow-link-button', pc)


def _dock_window_maximize_button(name, pc):
    return _basic_pc('QBitmapButton#dockwindow-maximize-button', pc)


def _dock_window_restore_button(name, pc):
    return _basic_pc('QBitmapButton#dockwindow-restore-button', pc)


def _rubber_band(name, pc):
    return _basic_pc('QDockRubberBand', pc)


def _splitter_handle(name, pc):
    return _basic_pc('QDockSplitter::handle', pc)


def _tab_bar(name, pc):
    return _basic_pc('QDockTabBar', pc)


def _tab_bar_tab(name, pc):
    rest = []
    alert = ''
    for part in pc.split(':'):
        match = _alert_re.match(part)
        if match is not None:
            alert = match.group(1)
        else:
            rest.append(part)
    if alert:
        root = 'QDockTabBar[alert="%s"]::tab' % alert
    else:
        root = 'QDockTabBar::tab'
    return _basic_pc(root, ':'.join(rest))


def _tab_bar_close_button(name, pc):
    return _basic_pc('QBitmapButton#docktab-close-button', pc)


def _tab_bar_corner(name, pc):
    return _basic_pc('QDockTabWidget::right-corner', pc)


def _tab_bar_corner_bar(name, pc):
    return _basic_pc('QDockTitleBar#docktab-corner-widget', pc)


def _tab_bar_corner_button(name, pc):
    return _basic_pc('QDockTitleBar#docktab-corner-widget > QBitmapButton', pc)


def _maybe_alert(root, name, pc):
    rest = []
    alert = ''
    for part in pc.split(':'):
        match = _alert_re.match(part)
        if match is not None:
            alert = match.group(1)
        else:
            rest.append(part)
    if alert:
        root = '%s[alert="%s"]' % (root, alert)
    return _basic_pc(root, ':'.join(rest))


def _base_dock_item(name, pc):
    rest = []
    tabbed = False
    floating = False
    for part in pc.split(':'):
        if part == 'tabbed':
            tabbed = True
        elif part == 'floating':
            floating = True
        else:
            rest.append(part)
    if tabbed:
        root = 'QDockTabWidget QDockItem'
    elif floating:
        root = 'QDockContainer[floating="true"] QDockItem'
    else:
        root = 'QDockItem'
    return _maybe_alert(root, name, ':'.join(rest))


def _title_bar(name, pc):
    return _maybe_alert('QDockTitleBar', name, pc)


def _title_bar_label(name, pc):
    return _maybe_alert('QDockTitleBar > QTextLabel', name, pc)


def _title_bar_button(name, pc):
    return _basic_pc('QDockTitleBar > QBitmapButton', pc)


def _title_bar_close_button(name, pc):
    return _basic_pc('QBitmapButton#docktitlebar-close-button', pc)


def _title_bar_link_button(name, pc):
    return _basic_pc('QBitmapButton#docktitlebar-link-button', pc)


def _title_bar_maximize_button(name, pc):
    return _basic_pc('QBitmapButton#docktitlebar-maximize-button', pc)


def _title_bar_pin_button(name, pc):
    return _basic_pc('QBitmapButton#docktitlebar-pin-button', pc)


def _title_bar_restore_button(name, pc):
    return _basic_pc('QBitmapButton#docktitlebar-restore-button', pc)


_DOCK_AREA_PSEUDO_ELEMENTS = {
    '': _base_dock_area,
    'dock-bar': _dock_bar,
    'dock-bar-button': _dock_bar_button,
    'dock-bar-handle': _dock_bar_handle,
    'dock-container': _dock_container,
    'dock-window': _dock_window,
    'dock-window-button': _dock_window_button,
    'dock-window-close-button': _dock_window_close_button,
    'dock-window-link-button': _dock_window_link_button,
    'dock-window-maximize-button': _dock_window_maximize_button,
    'dock-window-restore-button': _dock_window_restore_button,
    'rubber-band': _rubber_band,
    'splitter-handle': _splitter_handle,
    'tab-bar': _tab_bar,
    'tab-bar-tab': _tab_bar_tab,
    'tab-bar-corner': _tab_bar_corner,
    'tab-bar-corner-bar': _tab_bar_corner_bar,
    'tab-bar-corner-button': _tab_bar_corner_button,
    'tab-bar-close-button': _tab_bar_close_button,
}


_DOCK_ITEM_PSEUDO_ELEMENTS = {
    '': _base_dock_item,
    'title-bar': _title_bar,
    'title-bar-label': _title_bar_label,
    'title-bar-button': _title_bar_button,
    'title-bar-close-button': _title_bar_close_button,
    'title-bar-link-button': _title_bar_link_button,
    'title-bar-maximize-button': _title_bar_maximize_button,
    'title-bar-pin-button': _title_bar_pin_button,
    'title-bar-restore-button': _title_bar_restore_button,
}


def _dock_style_selector(name, style, elements):
    handlers = []
    for pe in style.pseudo_element.split(','):
        handler = elements.get(pe.strip())
        if handler:
            handlers.append(handler)
    if not handlers:
        return
    parts = []
    for pc in style.pseudo_class.split(','):
        pc = pc.strip()
        for handler in handlers:
            parts.append(handler(name, pc))
    return ', '.join(parts)


def translate_dock_area_style(name, style):
    selector = _dock_style_selector(name, style, _DOCK_AREA_PSEUDO_ELEMENTS)
    if not selector:
        return
    body = '{\n%s\n}' % _translate_style_body(style)
    return '%s %s' % (selector, body)


def translate_dock_item_style(name, style):
    selector = _dock_style_selector(name, style, _DOCK_ITEM_PSEUDO_ELEMENTS)
    if not selector:
        return
    body = '{\n%s\n}' % _translate_style_body(style)
    return '%s %s' % (selector, body)


#------------------------------------------------------------------------------
# Notebook Styling
#------------------------------------------------------------------------------
_NOTEBOOK_PSEUDO_ELEMENTS = {
    'tab': lambda name, pc: _basic_pc('QTabBar::tab', pc),
    'tear': lambda name, pc: _basic_pc('QTabBar::tear', pc),
    'scroller': lambda name, pc: _basic_pc('QTabBar::scroller', pc),
    'tool-button': lambda name, pc: _basic_pc('QTabBar QToolButton', pc),
}


def translate_notebook_style(name, style):
    selector = _dock_style_selector(name, style, _NOTEBOOK_PSEUDO_ELEMENTS)
    if not selector:
        return
    body = '{\n%s\n}' % _translate_style_body(style)
    return '%s %s' % (selector, body)
