/*
 * Copyright 2019 Abakkk
 * Copyright 2024 Dave Prowse
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-FileCopyrightText: 2019 Abakkk
 * SPDX-License-Identifier: GPL-3.0-or-later
 * SPDX-FileContributor: Modified by Dave Prowse
 */

/* jslint esversion: 6 (2019) */
/* eslint version: 9.16 (2024) */
/* exported DrawingHelper */

import Clutter from 'gi://Clutter';

import St from 'gi://St';
import GObject from 'gi://GObject';
import * as Shortcuts from './shortcuts.js';
import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';

import { CURATED_UUID as UUID } from './utils.js';
import { SHELL_MAJOR_VERSION } from './utils.js';

import GLib from 'gi://GLib';


const HELPER_ANIMATION_TIME = 0.25;

// DrawingHelper provides the "help osd" (Ctrl + F1)
// It uses the same texts as in prefs
//TODO: Review this class later
export const DrawingHelper = GObject.registerClass({
    GTypeName: `${UUID}-DrawingHelper`,
}, class DrawingHelper  extends St.ScrollView {

    _init(extension, params, monitor) {
        params.style_class = 'osd-window draw-on-gnome-helper';
        super._init(params);
        this._extension = extension;
        this.monitor = monitor;
        this.hide();

        this.settingsHandler = this._extension.settings.connect('changed', this._onSettingsChanged.bind(this));
        this.internalShortcutsettingsHandler = this._extension.internalShortcutSettings.connect('changed', this._onSettingsChanged.bind(this));
        this.connect('destroy', () => {
            this._extension.settings.disconnect(this.settingsHandler);
            this._extension.internalShortcutSettings.disconnect(this.internalShortcutsettingsHandler);
        });
    }

    _onSettingsChanged(settings, key) {
        if (key == 'toggle-help')
            this._updateHelpKeyLabel();

        if (this.vbox) {
            this.vbox.destroy();
            delete this.vbox;
        }
    }

    _updateHelpKeyLabel() {
        try {
            this._helpKeyLabel = this._extension.internalShortcutSettings.get_strv('toggle-help')[0];
        } catch(e) {
            logError(e);
            this._helpKeyLabel = " ";
        }
    }

    get helpKeyLabel() {
        if (!this._helpKeyLabel)
            this._updateHelpKeyLabel();

        return GLib.markup_escape_text(this._helpKeyLabel, -1);
    }

    _populate() {
        this.vbox = new St.BoxLayout({ vertical: true });
        this.add_child(this.vbox);
        this.vbox.add_child(new St.Label({ text: _("Global") }));

        Shortcuts.GLOBAL_KEYBINDINGS.forEach((settingKeys) => {
            this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' }));

            if (!this._extension.settings.get_strv(settingKeys)[0])
                return;

            let hbox = new St.BoxLayout({ vertical: false });
            let shortcut = this._extension.settings.get_strv(settingKeys)[0];
            // Convert modifier keys
            shortcut = shortcut.replace(/<Primary>/g, 'Ctrl+')
                               .replace(/<Shift>/g, 'Shift+')
                               .replace(/<Alt>/g, 'Alt+')
                               .replace(/<Super>/g, 'Super+')
                               // Remove KP_ prefix (numpad keys)
                               .replace(/KP_/g, '')
                               // Convert symbol names to actual symbols
                               .replace(/equal/g, '=')
                               .replace(/Multiply/g, '*')
                               .replace(/Divide/g, '/')
                               .replace(/Add/g, '+')
                               .replace(/Subtract/g, '-')
                               .replace(/period/g, '.')
                               .replace(/comma/g, ',')
                               .replace(/slash/g, '/')
                               .replace(/minus/g, '-')
                               .replace(/plus/g, '+')
                               .replace(/asterisk/g, '*')
                               // Uppercase single letters after + or at start
                               .replace(/\+([a-z])$/g, (match, letter) => '+' + letter.toUpperCase())
                               .replace(/^([a-z])$/g, (match, letter) => letter.toUpperCase());
            shortcut = GLib.markup_escape_text(shortcut, -1);
            hbox.add_child(new St.Label({ text: this._extension.settings.settings_schema.get_key(settingKeys).get_summary() }));
            let label = new St.Label({ text: "<b><i>" + shortcut + "</i></b>", x_expand: true })
            label.get_clutter_text().set_use_markup(true);
            hbox.add_child(label);
            this.vbox.add_child(hbox);
        });

        this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' }));
        this.vbox.add_child(new St.Label({ text: _("Internal") }));

        // Shortcuts.OTHERS.forEach((pairs, index) => {
        //     if (index)
        //         this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' }));

        //     pairs.forEach(pair => {
        //         let [action, shortcut] = pair;
        //         let hbox = new St.BoxLayout({ vertical: false });
        //         hbox.add_child(new St.Label({ text: action }));
        //         hbox.add_child(new St.Label({ text: shortcut, x_expand: true }).get_clutter_text().set_use_markup(true));

        //         hbox.get_children()[0]);
        //         this.vbox.add_child(hbox);
        //     });
        // });

        // this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' }));

        Shortcuts.INTERNAL_KEYBINDINGS.forEach((settingKeys) => {
            this.vbox.add_child(new St.BoxLayout({ vertical: false, style_class: 'draw-on-gnome-helper-separator' }));

            if (!this._extension.internalShortcutSettings.get_strv(settingKeys)[0])
                return;

            let hbox = new St.BoxLayout({ vertical: false });
            let shortcut = this._extension.internalShortcutSettings.get_strv(settingKeys)[0];
            // Convert modifier keys
            shortcut = shortcut.replace(/<Primary>/g, 'Ctrl+')
                               .replace(/<Shift>/g, 'Shift+')
                               .replace(/<Alt>/g, 'Alt+')
                               .replace(/<Super>/g, 'Super+')
                               // Remove KP_ prefix (numpad keys)
                               .replace(/KP_/g, '')
                               // Convert symbol names to actual symbols
                               .replace(/equal/g, '=')
                               .replace(/Multiply/g, '*')
                               .replace(/Divide/g, '/')
                               .replace(/Add/g, '+')
                               .replace(/Subtract/g, '-')
                               .replace(/period/g, '.')
                               .replace(/comma/g, ',')
                               .replace(/slash/g, '/')
                               .replace(/minus/g, '-')
                               .replace(/plus/g, '+')
                               .replace(/asterisk/g, '*')
                               // Uppercase single letters after + or at start
                               .replace(/\+([a-z])$/g, (match, letter) => '+' + letter.toUpperCase())
                               .replace(/^([a-z])$/g, (match, letter) => letter.toUpperCase());
            shortcut = GLib.markup_escape_text(shortcut, -1);
            hbox.add_child(new St.Label({ text: this._extension.internalShortcutSettings.settings_schema.get_key(settingKeys).get_summary() }));
            let label = new St.Label({ text: "<b><i>" + shortcut + "</i></b>", x_expand: true })
            label.get_clutter_text().set_use_markup(true);
            hbox.add_child(label);
            this.vbox.add_child(hbox);
        });        
    }

    showHelp() {
        if (!this.vbox)
            this._populate();

        this.opacity = 0;
        this.show();

        let maxHeight = this.monitor.height * 3 / 4;
        this.set_height(Math.min(this.height, maxHeight));
        this.set_position(Math.floor(this.monitor.width / 2 - this.width / 2),
                          Math.floor(this.monitor.height / 2 - this.height / 2));

        // St.PolicyType: GS 3.32+
        if (this.height == maxHeight)
            this.vscrollbar_policy = St.PolicyType ? St.PolicyType.ALWAYS : 1;
        else
            this.vscrollbar_policy = St.PolicyType ? St.PolicyType.NEVER : 0;

        this.remove_all_transitions();
        this.ease({
            opacity: 255,
            duration: HELPER_ANIMATION_TIME * 1000,
            mode: Clutter.AnimationMode.EASE_OUT_QUAD
        });
    }

    hideHelp() {
        this.remove_all_transitions();
        this.ease({
            opacity: 0,
            duration: HELPER_ANIMATION_TIME * 1000,
            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
        onComplete: () => this.hide()
        });
    }
});

