/*
 * This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
 *
 *  Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

'use strict';

import {Dropdown} from "bootstrap";
import ClipboardJS from "clipboard";
import {Modal} from "bootstrap";

class RegisterEventHelper {
    constructor() {
        this.registerTooltips();
        this.configureDropdowns();
        
        // Only register special character input if enabled in configuration
        const keybindingsEnabled = document.body.dataset.keybindingsSpecialCharacters !== 'false';
        if (keybindingsEnabled) {
            this.registerSpecialCharInput();
        }

        //Initialize ClipboardJS
        this.registerLoadHandler(() => {
            new ClipboardJS('.btn');
        });

        this.registerModalDropRemovalOnFormSubmit();


    }

    registerModalDropRemovalOnFormSubmit() {
        //Remove all modal backdrops, before rendering the new page.
        document.addEventListener('turbo:before-render', event => {
            const back_drop = document.querySelector('.modal-backdrop');
            if (back_drop) {
                back_drop.remove();
            }

            //Remove scroll-lock if it is still active
            if (document.body.classList.contains('modal-open')) {
                document.body.classList.remove('modal-open');

                //Remove the padding-right and overflow:hidden from the body
                document.body.style.paddingRight = '';
                document.body.style.overflow = '';
            }
        });
    }

    registerLoadHandler(fn) {
        document.addEventListener('turbo:render', fn);
        document.addEventListener('turbo:load', fn);
    }

    configureDropdowns() {
        this.registerLoadHandler(() => {
            //Set the dropdown strategy to fixed, so that the dropdowns are not cut off by the overflow: hidden of the body.
            //Solution from: https://github.com/twbs/bootstrap/issues/36560
            const dropdowns = document.querySelectorAll('[data-bs-toggle="dropdown"]');
            const dropdown = [...dropdowns].map((dropdownToggleEl) => new Dropdown(dropdownToggleEl, {
                popperConfig(defaultBsPopperConfig) {
                    return { ...defaultBsPopperConfig, strategy: 'fixed' };
                }
            }));
        });
    }

    registerTooltips() {
        const handler = () => {
            $(".tooltip").remove();
            //Exclude dropdown buttons from tooltips, otherwise we run into endless errors from bootstrap (bootstrap.esm.js:614 Bootstrap doesn't allow more than one instance per element. Bound instance: bs.dropdown.)
            $('a[title], label[title], button[title]:not([data-bs-toggle="dropdown"]), p[title], span[title], h6[title], h3[title], i[title], small[title]')
                //@ts-ignore
                .tooltip("hide").tooltip({container: "body", placement: "auto", boundary: 'window'});
        };

        this.registerLoadHandler(handler);
        document.addEventListener('dt:loaded', handler);
    }

    registerSpecialCharInput() {
        this.registerLoadHandler(() => {
            //@ts-ignore
            $("input[type=text], input[type=search]").unbind("keydown").keydown(function (event) {
                let use_special_char = event.altKey;

                let greek_char = "";
                if (use_special_char){
                    //Use the key property to determine the greek letter (as it is independent of the keyboard layout)
                    switch(event.key) {
                        //Greek letters
                        case "a": //Alpha (lowercase)
                            greek_char = "\u03B1";
                            break;
                        case "A": //Alpha (uppercase)
                            greek_char = "\u0391";
                            break;
                        case "b": //Beta (lowercase)
                            greek_char = "\u03B2";
                            break;
                        case "B": //Beta (uppercase)
                            greek_char = "\u0392";
                            break;
                        case "g": //Gamma (lowercase)
                            greek_char = "\u03B3";
                            break;
                        case "G": //Gamma (uppercase)
                            greek_char = "\u0393";
                            break;
                        case "d": //Delta (lowercase)
                            greek_char = "\u03B4";
                            break;
                        case "D": //Delta (uppercase)
                            greek_char = "\u0394";
                            break;
                        case "e": //Epsilon (lowercase)
                            greek_char = "\u03B5";
                            break;
                        case "E": //Epsilon (uppercase)
                            greek_char = "\u0395";
                            break;
                        case "z": //Zeta (lowercase)
                            greek_char = "\u03B6";
                            break;
                        case "Z": //Zeta (uppercase)
                            greek_char = "\u0396";
                            break;
                        case "h": //Eta (lowercase)
                            greek_char = "\u03B7";
                            break;
                        case "H": //Eta (uppercase)
                            greek_char = "\u0397";
                            break;
                        case "q": //Theta (lowercase)
                            greek_char = "\u03B8";
                            break;
                        case "Q": //Theta (uppercase)
                            greek_char = "\u0398";
                            break;
                        case "i": //Iota (lowercase)
                            greek_char = "\u03B9";
                            break;
                        case "I": //Iota (uppercase)
                            greek_char = "\u0399";
                            break;
                        case "k": //Kappa (lowercase)
                            greek_char = "\u03BA";
                            break;
                        case "K": //Kappa (uppercase)
                            greek_char = "\u039A";
                            break;
                        case "l": //Lambda (lowercase)
                            greek_char = "\u03BB";
                            break;
                        case "L": //Lambda (uppercase)
                            greek_char = "\u039B";
                            break;
                        case "m": //Mu (lowercase)
                            greek_char = "\u03BC";
                            break;
                        case "M": //Mu (uppercase)
                            greek_char = "\u039C";
                            break;
                        case "n": //Nu (lowercase)
                            greek_char = "\u03BD";
                            break;
                        case "N": //Nu (uppercase)
                            greek_char = "\u039D";
                            break;
                        case "x": //Xi (lowercase)
                            greek_char = "\u03BE";
                            break;
                        case "X": //Xi (uppercase)
                            greek_char = "\u039E";
                            break;
                        case "o": //Omicron (lowercase)
                            greek_char = "\u03BF";
                            break;
                        case "O": //Omicron (uppercase)
                            greek_char = "\u039F";
                            break;
                        case "p": //Pi (lowercase)
                            greek_char = "\u03C0";
                            break;
                        case "P": //Pi (uppercase)
                            greek_char = "\u03A0";
                            break;
                        case "r": //Rho (lowercase)
                            greek_char = "\u03C1";
                            break;
                        case "R": //Rho (uppercase)
                            greek_char = "\u03A1";
                            break;
                        case "s": //Sigma (lowercase)
                            greek_char = "\u03C3";
                            break;
                        case "S": //Sigma (uppercase)
                            greek_char = "\u03A3";
                            break;
                        case "t": //Tau (lowercase)
                            greek_char = "\u03C4";
                            break;
                        case "T": //Tau (uppercase)
                            greek_char = "\u03A4";
                            break;
                        case "u": //Upsilon (lowercase)
                            greek_char = "\u03C5";
                            break;
                        case "U": //Upsilon (uppercase)
                            greek_char = "\u03A5";
                            break;
                        case "f": //Phi (lowercase)
                            greek_char = "\u03C6";
                            break;
                        case "F": //Phi (uppercase)
                            greek_char = "\u03A6";
                            break;
                        case "c": //Chi (lowercase)
                            greek_char = "\u03C7";
                            break;
                        case "C": //Chi (uppercase)
                            greek_char = "\u03A7";
                            break;
                        case "y": //Psi (lowercase)
                            greek_char = "\u03C8";
                            break;
                        case "Y": //Psi (uppercase)
                            greek_char = "\u03A8";
                            break;
                        case "w": //Omega (lowercase)
                            greek_char = "\u03C9";
                            break;
                        case "W": //Omega (uppercase)
                            greek_char = "\u03A9";
                            break;
                    }

                    //Use keycodes for special characters as the shift char on the number keys are layout dependent
                    switch (event.keyCode) {
                        case 49: //1 key
                            //Product symbol on shift, sum on no shift
                            greek_char = event.shiftKey ? "\u220F" : "\u2211";
                            break;
                        case 50: //2 key
                            //Integral on no shift, partial derivative on shift
                            greek_char = event.shiftKey ?  "\u2202" : "\u222B";
                            break;
                        case 51: //3 key
                            //Less than or equal on no shift, greater than or equal on shift
                            greek_char = event.shiftKey ? "\u2265" : "\u2264";
                            break;
                        case 52: //4 key
                            //Empty set on shift, infinity on no shift
                            greek_char = event.shiftKey ? "\u2205" : "\u221E";
                            break;
                        case 53: //5 key
                            //Not equal on shift, approx equal on no shift
                            greek_char = event.shiftKey ? "\u2260" : "\u2248";
                            break;
                        case 54: //6 key
                            //Element of on no shift, not element of on shift
                            greek_char = event.shiftKey ? "\u2209" : "\u2208";
                            break;
                        case 55: //7 key
                            //And on shift, or on no shift
                            greek_char = event.shiftKey ? "\u2227" : "\u2228";
                            break;
                        case 56: //8 key
                            //Proportional to on shift, angle on no shift
                            greek_char = event.shiftKey ? "\u221D" : "\u2220";
                            break;
                        case 57: //9 key
                            //Cube root on shift, square root on no shift
                            greek_char = event.shiftKey ? "\u221B" : "\u221A";
                            break;
                        case 48: //0 key
                            //Minus-Plus on shift, plus-minus on no shift
                            greek_char = event.shiftKey ? "\u2213" : "\u00B1";
                            break;

                        //Special characters
                        case 219: //hyphen (or ß on german layout)
                            //Copyright on no shift, TM on shift
                            greek_char = event.shiftKey ? "\u2122" : "\u00A9";
                            break;
                        case 191: //forward slash (or # on german layout)
                            //Generic currency on no shift, paragraph on shift
                            greek_char = event.shiftKey ? "\u00B6" : "\u00A4";
                            break;

                        //Currency symbols
                        case 192: //: or (ö on german layout)
                            //Euro on no shift, pound on shift
                            greek_char = event.shiftKey ? "\u00A3" : "\u20AC";
                            break;
                        case 221: //; or (ä on german layout)
                            //Yen on no shift,  dollar on shift
                            greek_char = event.shiftKey ? "\u0024" : "\u00A5";
                            break;


                    }

                    if(greek_char=="") return;

                    let $txt = $(this);
                    //@ts-ignore
                    let caretPos = $txt[0].selectionStart;
                    let textAreaTxt = $txt.val().toString();
                    $txt.val(textAreaTxt.substring(0, caretPos) + greek_char + textAreaTxt.substring(caretPos) );

                }
            });
            //@ts-ignore
            this.greek_once = true;
        })
    }
}

export default new RegisterEventHelper();