/**
 * Cherrypy-foundation
 * Copyright (C) 2026 IKUS Software
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

/**
 * Escapes special characters in a field name for safe use in a jQuery/CSS attribute selector
 */
function cfFieldEscape(v) {
    return v.replace(/(:|\.|\[|\]|,|=)/g, String.raw`\$1`);
}

function cfFieldValue(elem) {
    const type = elem.attr('type')?.toLowerCase();
    if (type === 'checkbox' || type === 'radio') {
        return elem.is(':checked') ? elem.val() : '';
    }
    return elem.val();
}

function cfFieldPasswordIconZone(input) {
    const rect = input.getBoundingClientRect();
    const fontSize = Number.parseFloat(getComputedStyle(input).fontSize);
    const iconWidth = fontSize * 0.75 + 6;       // calc(.75em + .375rem)
    const rightPadding = fontSize * 0.375 + 3;   // calc(.375em + .1875rem)
    return {
        start: rect.right - rightPadding - iconWidth,
        end:   rect.right - rightPadding
    };
}

jQuery(function() {
    /**
     * Control showif
     */
    $('[data-showif-field]').each(function() {
        const elem = $(this);
        const field = $(this).data('showif-field');
        const operator = $(this).data('showif-operator');
        const value = $(this).data('showif-value');
        // Lookup field
        if (!field) {
            return;
        }
        const fieldElem = $(`[name='${cfFieldEscape(field)}']`);
        if (fieldElem.length > 0) {
            function updateShowIf() {
                const curValue = cfFieldValue(fieldElem);
                let visible = false;
                if (operator == 'eq') {
                    visible = curValue == value;
                } else if (operator == 'ne') {
                    visible = curValue != value;
                } else if (operator == 'in' && Array.isArray(value)) {
                    visible = $.inArray(curValue, value) >= 0;
                }
                // To handle the initial state, manually add the collapse class before creating the collapsable class.
                const parent = elem.closest('.form-field');
                if (!parent.hasClass('collapse')) {
                    parent.addClass('collapse');
                    if (visible) {
                        parent.addClass('show');
                    }
                }
                // Update widget visibility accordingly.
                let collapsible = bootstrap.Collapse.getOrCreateInstance(parent, {
                    toggle: false
                });
                if (visible) {
                    collapsible.show();
                    elem.removeAttr('disabled');
                } else {
                    collapsible.hide();
                    elem.attr('disabled', '1');
                }
            }
            // Attach event to field.
            fieldElem.change(function() {
                updateShowIf();
            })
            updateShowIf();
        }
    });

    /*
     * Toggle password visibility.
     */
    document.querySelectorAll('input.cf-field-password').forEach(input => {
        input.addEventListener('click', function(e) {
            const { start, end } = cfFieldPasswordIconZone(this);
            if (e.clientX >= start && e.clientX <= end) {
                this.type = this.type === 'password' ? 'text' : 'password';
            }
        });

        input.addEventListener('mousemove', function(e) {
            const { start, end } = cfFieldPasswordIconZone(this);
            this.style.cursor = (e.clientX >= start && e.clientX <= end) ? 'pointer' : 'text';
        });
    });
});