#!/usr/bin/env python3
# ============================================================
#     The rekonq project
# ============================================================
# SPDX-License-Identifier: GPL-3.0-only
# Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
# ============================================================
""" Generate SettingsWidgets from KDE kcfg files """


import argparse
import sys
from xml.etree import ElementTree


def write_int_entry(obj, name):
    """Add a QSpinBox connected to an Int"""
    print(f'  auto* { obj } = new QSpinBox(this);')
    print(f'  { obj }->setValue(s->value("{ obj }").toInt());')
    print(f'  connect({ obj }, &QSpinBox::valueChanged, this, [this]() {{ emit changed(); }});')
    print(f'  formLayout->addRow(tr("{ name }"), { obj });')


def write_bool_entry(obj, name):
    """Add a QCheckBox connected to a Bool"""
    print(f'  auto* { obj } = new QCheckBox(tr("{ name }"), this);')
    print(f'  { obj }->setChecked(s->value("{ obj }").toBool());')
    print(f'  connect({ obj }, &QCheckBox::stateChanged, this, [this]() {{ emit changed(); }});')
    print(f'  formLayout->addRow(QString(), { obj });')


def write_string_entry(obj, name):
    """Add a QLineEdit connected to a String"""
    print(f'  auto* {obj} = new QLineEdit(this);')
    print(f'  { obj }->setText(s->value("{ obj }").toString());')
    print(f'  connect({ obj }, &QLineEdit::textChanged, this, [this]() {{ emit changed(); }});')
    print(f'  formLayout->addRow(tr("{ name }"), { obj });')


def write_font_entry(obj, name):
    """Add a QFontComboBox connected to a Font"""
    print(f'  auto* { obj } = new QFontComboBox(this);')
    print(f'  { obj }->setCurrentFont(s->value("{ obj }").toString());')
    print(f'  connect({ obj }, &QFontComboBox::currentFontChanged, this, [this]() {{ emit changed(); }});')
    print(f'  formLayout->addRow(tr("{ name }"), { obj });')


def write_shortcut_entry(obj, name):
    """Add a QKeySequenceEdit connected to a Shortcut"""
    print(f'  auto* { obj } = new QKeySequenceEdit(this);')
    print(f'  { obj }->setKeySequence(s->value("{ obj }").toString());')
    print(f'  connect({ obj }, &QKeySequenceEdit::keySequenceChanged, this, [this]() {{ emit changed(); }});')
    print(f'  formLayout->addRow(tr("{ name }"), { obj });')


def generate_group_widget(root, group):
    """Generate a class based on the group name"""
    class_group = group.attrib["name"].replace(' ', '')
    class_name = group.attrib["name"].replace(' ', '') + 'SettingsWidget'

    write_entry_fn = {
        'Int': write_int_entry,
        'Bool': write_bool_entry,
        'String': write_string_entry,
        'Font': write_font_entry,
        'Shortcut': write_shortcut_entry
    }

    # includes
    print('// Includes')
    print('#include "settingswidgets.hpp"')
    print('#include <QFormLayout>')
    print('#include <QLineEdit>')
    print('#include <QSpinBox>')
    print('#include <QFontComboBox>')
    print('#include <QKeySequenceEdit>')
    print('#include <QCheckBox>')
    print('// kcfg Includes')
    for include in root.findall('{http://www.kde.org/standards/kcfg/1.0}include'):
        print(f'#include <{ include.text }>')
    print('')

    # ctor
    print(f'{ class_name }::{ class_name }(RekonqSettings *s, QWidget *parent) : SettingsWidget(s, parent) {{')
    print(f'  setObjectName("{ class_group }");')
    if class_group != 'General':
        print(f'  s->beginGroup("{ class_group }");')
    print('  auto *formLayout = new QFormLayout;')
    print('  setLayout(formLayout);')
    print('')

    print('  // Entries')
    for entry in group.findall('{http://www.kde.org/standards/kcfg/1.0}entry'):
        if entry.attrib.get("hidden") == "true":
            print(f'  // hidden entry { entry.attrib.get("name") }')
        else:
            obj = entry.attrib['key']
            name = entry.attrib["name"]
            write_entry_fn.get(entry.attrib['type'])(obj, name)
            print(f'  { obj }->setObjectName("{ obj }");')
        print('')

    if class_group != 'General':
        print('  m_settings->endGroup();')
    print('}\n')

    # reset
    print(f'void { class_name }::reset() {{')
    if class_group != 'General':
        print(f'  m_settings->beginGroup("{ class_group }");')

    for entry in group.findall('{http://www.kde.org/standards/kcfg/1.0}entry'):
        if entry.attrib.get("hidden") == "true":
            print(f'  // hidden entry { entry.attrib.get("name") }')
        else:
            key = entry.attrib['key']
            print(f'  m_settings->resetValue("{ key }");')

    if class_group != 'General':
        print('  m_settings->endGroup();')
    print('}\n')

def generate_group_ini(group):
    """Generate settings in ini format for group"""
    group_name = group.attrib["name"].replace(' ', '')
    print(f'[{ group_name }]')
    for entry in group.findall('{http://www.kde.org/standards/kcfg/1.0}entry'):
        if entry.find('{*}default').get('code') == 'true':
            continue
        entry_key = entry.attrib['key']
        entry_val = entry.find('{*}default').text
        print(f'{ entry_key }={ entry_val }')
    print('')


def main():
    """main function"""
    parser = argparse.ArgumentParser(description='Generate SettingsWidgets')
    parser.add_argument('file', type=str, help='kcfg file')
    parser.add_argument('--group', type=str, required=True, help='Group')
    parser.add_argument('--output', type=str, default=None, help='Redirect output to file')
    args = parser.parse_args()

    with open(args.output, 'w', encoding="utf-8") if args.output else sys.stdout as sys.stdout:
        tree = ElementTree.parse(args.file)
        root = tree.getroot()

        if args.group == 'all':
            for group in root.findall('{http://www.kde.org/standards/kcfg/1.0}group'):
                generate_group_ini(group)
        else:
            for group in root.findall('{http://www.kde.org/standards/kcfg/1.0}group'):
                if group.attrib["name"] == args.group:
                    print('// This is an automatically generated file')
                    generate_group_widget(root, group)
                    break


if __name__ == '__main__':
    main()