# shellconf.py - User interface for the TortoiseHg shell extension settings
#
# Copyright 2009 Steve Borho <steve@borho.org>
# Copyright 2010 Adrian Buehlmann <adrian@cadifra.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import annotations

from mercurial.windows import winreg

CreateKey = winreg.CreateKey
HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
OpenKey = winreg.OpenKey
QueryValueEx = winreg.QueryValueEx
REG_DWORD = winreg.REG_DWORD
REG_SZ = winreg.REG_SZ
SetValueEx = winreg.SetValueEx

from .qtgui import (
    QApplication,
    QCheckBox,
    QDialog,
    QDialogButtonBox,
    QGridLayout,
    QGroupBox,
    QHBoxLayout,
    QLabel,
    QListWidget,
    QListWidgetItem,
    QPushButton,
    QStyle,
    QTabWidget,
    QVBoxLayout,
    QWidget,
)

from ..util import menuthg
from ..util.i18n import _
from . import qtlib

THGKEY = 'TortoiseHg'
OVLKEY = 'TortoiseOverlays'
PROMOTEDITEMS = 'PromotedItems'

# reading functions
def is_true(x): return x in ('1', 'True')
def nonzero(x): return x != 0

# writing functions
def one_str(x):
    if x: return '1'
    return '0'
def one_int(x):
    if x: return 1
    return 0

def noop(x): return x

vars = {
    # name:
    #   default, regkey, regtype, evalfunc, wrfunc, checkbuttonattribute
    'EnableOverlays':
        [True,     THGKEY, REG_SZ, is_true, one_str, 'ovenable'],
    'LocalDisksOnly':
        [False,    THGKEY, REG_SZ, is_true, one_str, 'localonly'],
    'ShowTaskbarIcon':
        [True,     THGKEY, REG_SZ, is_true, one_str, 'show_taskbaricon'],
    'HighlightTaskbarIcon':
        [True,     THGKEY, REG_SZ, is_true, one_str, 'highlight_taskbaricon'],
    'HideMenuOutsideRepo':
        [False,    THGKEY, REG_SZ, is_true, one_str, 'hidecmenu'],
    PROMOTEDITEMS:
        ['commit,workbench', THGKEY, REG_SZ, noop, noop, None],
    'ShowUnversionedOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableUnversionedHandler'],
    'ShowIgnoredOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableIgnoredHandler'],
    'ShowLockedOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableLockedHandler'],
    'ShowReadonlyOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableReadonlyHandler'],
    'ShowDeletedOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableDeletedHandler'],
    'ShowAddedOverlay':
        [True, OVLKEY, REG_DWORD, nonzero, one_int, 'enableAddedHandler']
}


class ShellConfigWindow(QDialog):

    def __init__(self, parent=None):
        super().__init__(parent)

        self.menu_cmds = {}
        self.dirty = False

        layout = QVBoxLayout()

        tw = QTabWidget()
        layout.addWidget(tw)

        # cmenu tab
        cmenuwidget = QWidget()
        grid = QGridLayout()
        cmenuwidget.setLayout(grid)
        tw.addTab(cmenuwidget, _("Context Menu"))

        w = QLabel(_("Top menu items:"))
        grid.addWidget(w, 0, 0)
        self.topmenulist = w = QListWidget()
        grid.addWidget(w, 1, 0, 4, 1)
        w.itemClicked.connect(self.listItemClicked)

        w = QLabel(_("Sub menu items:"))
        grid.addWidget(w, 0, 2)
        self.submenulist = w = QListWidget()
        grid.addWidget(w, 1, 2, 4, 1)
        w.itemClicked.connect(self.listItemClicked)

        style = QApplication.style()
        icon = style.standardIcon(QStyle.StandardPixmap.SP_ArrowLeft)
        self.top_button = w = QPushButton(icon, '')
        grid.addWidget(w, 2, 1)
        w.clicked.connect(self.top_clicked)
        icon = style.standardIcon(QStyle.StandardPixmap.SP_ArrowRight)
        self.sub_button = w = QPushButton(icon, '')
        grid.addWidget(w, 3, 1)
        w.clicked.connect(self.sub_clicked)

        grid.setRowStretch(1, 10)
        grid.setRowStretch(4, 10)

        def checkbox(label):
            cb = QCheckBox(label)
            cb.stateChanged.connect(self.stateChanged)
            return cb

        hidebox = QGroupBox(_('Menu Behavior'))
        grid.addWidget(hidebox, 5, 0, 5, 3)
        self.hidecmenu = checkbox(_('Hide context menu outside repositories'))
        self.hidecmenu.setToolTip(_('Do not show menu items on unversioned '
                                    'folders (use shift + click to override)'))
        hidebox.setLayout(QVBoxLayout())
        hidebox.layout().addWidget(self.hidecmenu)

        # Icons tab
        iconswidget = QWidget()
        iconslayout = QVBoxLayout()
        iconswidget.setLayout(iconslayout)
        tw.addTab(iconswidget, _("Icons"))

        # Overlays group
        gbox = QGroupBox(_("Overlays"))
        iconslayout.addWidget(gbox)
        hb = QHBoxLayout()
        gbox.setLayout(hb)
        self.ovenable = cb = checkbox(_("Enabled overlays"))
        hb.addWidget(cb)
        self.localonly = checkbox(_("Local disks only"))
        hb.addWidget(self.localonly)
        hb.addStretch()

        # Enabled Overlay Handlers group
        gbox = QGroupBox(_("Enabled Overlay Handlers"))
        iconslayout.addWidget(gbox)
        grid = QGridLayout()
        gbox.setLayout(grid)
        grid.setColumnStretch(3, 10)
        w = QLabel(_("Warning: affects all Tortoises, logoff required after "
                     "change"))
        grid.addWidget(w, 0, 0, 1, 3)
        self.enableAddedHandler = w = checkbox(_("Added"))
        grid.addWidget(w, 1, 0)
        self.enableLockedHandler = w = checkbox(_("Locked*"))
        grid.addWidget(w, 1, 1)
        self.enableIgnoredHandler = w = checkbox(_("Ignored*"))
        grid.addWidget(w, 1, 2)
        self.enableUnversionedHandler = w = checkbox(_("Unversioned"))
        grid.addWidget(w, 2, 0)
        self.enableReadonlyHandler = w = checkbox(_("Readonly*"))
        grid.addWidget(w, 2, 1)
        self.enableDeletedHandler = w = checkbox(_("Deleted*"))
        grid.addWidget(w, 2, 2)
        w = QLabel(_("*: not used by TortoiseHg"))
        grid.addWidget(w, 3, 0, 1, 3)

        # Taskbar group
        gbox = QGroupBox(_("Taskbar"))
        iconslayout.addWidget(gbox)
        hb = QHBoxLayout()
        gbox.setLayout(hb)
        self.show_taskbaricon = cb = checkbox(_("Show Icon"))
        hb.addWidget(cb)
        self.highlight_taskbaricon = cb = checkbox(_("Highlight Icon"))
        hb.addWidget(cb)
        hb.addStretch()

        iconslayout.addStretch()

        # i18n: URL of TortoiseSVN documentation
        url = _('https://tortoisesvn.net/docs/release/TortoiseSVN_en/'
                'tsvn-dug-settings.html#tsvn-dug-settings-icon-set')
        w = QLabel(_('You can change the icon set from <a href="%s">'
                     "TortoiseSVN's Settings</a>") % url)
        w.setOpenExternalLinks(True)
        iconslayout.addWidget(w)

        # dialog buttons
        bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Apply)
        self.apply_button = bb.button(QDialogButtonBox.StandardButton.Apply)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        bb.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self.apply)
        bb.button(QDialogButtonBox.StandardButton.Ok).setDefault(True)
        layout.addWidget(bb)

        self.setLayout(layout)
        self.setWindowTitle(_("Explorer Extension Settings - TortoiseHg"))
        self.setWindowIcon(qtlib.geticon('thg-repoconfig'))

        self.load_shell_configs()

    def load_shell_configs(self):
        for name, info in vars.items():
            default, regkey, regtype, evalfunc, wrfunc, cbattr = info
            try:
                with OpenKey(HKEY_CURRENT_USER, 'Software\\' + regkey) as hkey:
                    v = QueryValueEx(hkey, name)[0]
                    vars[name][0] = evalfunc(v)
            except OSError:
                pass
            if cbattr is not None:
                checkbutton = getattr(self, cbattr)
                checkbutton.setChecked(vars[name][0])

        promoteditems = vars[PROMOTEDITEMS][0]
        self.set_menulists(promoteditems)

        self.dirty = False
        self.update_states()

    def set_menulists(self, promoteditems):
        for list in (self.topmenulist, self.submenulist):
            list.clear()
            list.setSortingEnabled(True)
        promoted = [pi.strip() for pi in promoteditems.split(',')]
        for cmd, info in menuthg.thgcmenu.items():
            label = info['label']
            item = QListWidgetItem(label['str'])
            item._id = label['id']
            if cmd in promoted:
                self.topmenulist.addItem(item)
            else:
                self.submenulist.addItem(item)
            self.menu_cmds[item._id] = cmd

    def store_shell_configs(self):
        if not  self.dirty:
            return

        promoted = []
        list = self.topmenulist
        for row in range(list.count()):
            cmd = self.menu_cmds[list.item(row)._id]
            promoted.append(cmd)

        hkey = CreateKey(HKEY_CURRENT_USER, "Software\\" + THGKEY)
        SetValueEx(hkey, PROMOTEDITEMS, 0, REG_SZ, ','.join(promoted))

        for name, info in vars.items():
            default, regkey, regtype, evalfunc, wrfunc, cbattr = info
            if cbattr is None:
                continue
            checkbutton = getattr(self, cbattr)
            v = wrfunc(checkbutton.isChecked())
            hkey = CreateKey(HKEY_CURRENT_USER, 'Software\\' + regkey)
            SetValueEx(hkey, name, 0, regtype, v)

        self.dirty = False
        self.update_states()

    def accept(self):
        self.store_shell_configs()
        QDialog.accept(self)

    def reject(self):
        QDialog.reject(self)

    def apply(self):
        self.store_shell_configs()

    def top_clicked(self):
        self.move_selected(self.submenulist, self.topmenulist)

    def sub_clicked(self):
        self.move_selected(self.topmenulist, self.submenulist)

    def move_selected(self, fromlist, tolist):
        row = fromlist.currentRow()
        if row < 0:
            return
        item = fromlist.takeItem(row)
        tolist.addItem(item)
        tolist.setCurrentItem(item)
        fromlist.setCurrentItem(None)
        self.dirty = True
        self.update_states()

    def update_states(self):
        self.top_button.setEnabled(len(self.submenulist.selectedItems()) > 0)
        self.sub_button.setEnabled(len(self.topmenulist.selectedItems()) > 0)
        self.apply_button.setEnabled(self.dirty)

    def stateChanged(self, state):
        self.dirty = True
        self.update_states()

    def listItemClicked(self, item):
        itemlist = item.listWidget()
        for list in (self.topmenulist, self.submenulist):
            if list != itemlist:
                list.setCurrentItem(None)
        self.update_states()
