export default class AccessibilityHelper
{
    static focusableSelectors = [
        'a[href]:not([tabindex="-1"])',
        'area[href]:not([tabindex="-1"])',
        'input:not([disabled]):not([tabindex="-1"])',
        'select:not([disabled]):not([tabindex="-1"])',
        'textarea:not([disabled]):not([tabindex="-1"])',
        'button:not([disabled]):not([tabindex="-1"])',
        'iframe:not([tabindex="-1"])',
        'object:not([tabindex="-1"])',
        'embed:not([tabindex="-1"])',
        '[tabindex]:not([tabindex="-1"])',
        '[contenteditable]:not([tabindex="-1"])',
    ];

    constructor(wrapper, timeout = 0)
    {
        this.wrapper = wrapper;
        this.timeout = timeout;
        this.handleKeydown = this.handleTrappedKeydown.bind(this);
    }

    trap()
    {
        const elements = this.wrapper.querySelectorAll(AccessibilityHelper.focusableSelectors.join(','));
        if (elements.length === 0) return;

        this.focusedElement = document.activeElement;
        this.focusedElement.blur();
        this.wrapper.setAttribute('tabindex', '-1');
        this.wrapper.style.outline = 'none';
        setTimeout(() => {
            this.wrapper.focus();
            this.wrapper.addEventListener('keydown', this.handleKeydown);
        }, this.timeout);
    }

    handleTrappedKeydown(event)
    {
        if (event.key !== 'Tab') {
            return;
        }
        const elements = this.wrapper.querySelectorAll(AccessibilityHelper.focusableSelectors.join(','));
        if (elements.length === 0) return;

        const first = elements[0];
        const last = elements[elements.length - 1];
        if (event.shiftKey && document.activeElement === first) {
            event.preventDefault();
            last.focus();
        } else if (!event.shiftKey && document.activeElement === last) {
            event.preventDefault();
            first.focus();
        }
    }

    release()
    {
        this.wrapper.removeEventListener('keydown', this.handleKeydown);
        this.wrapper.removeAttribute('tabindex');
        this.wrapper.style.outline = '';
        clearTimeout(this.delay);
        this.delay = setTimeout(() => {
            this.focusedElement.focus();
        }, 300);
    }

    static trapFocus(wrapper, timeout = 0)
    {
        if (!wrapper.accessibility) {
            wrapper.accessibility = new this(wrapper, timeout);
        }
        wrapper.accessibility.trap();
    }

    static releaseTrap(wrapper)
    {
        if (!wrapper.accessibility) return;
        setTimeout(() => {
            wrapper.accessibility.release()
        }, 100);
    }

    static isClick(event)
    {
        return event.type == "click" || event.type == "touchend"
    }

    static processAction(event, callback, eventsList)
    {
        if (eventsList && eventsList.indexOf(event.type) == -1) return;
        if (this.isClick(event) || (event.type == "keyup" && event.key == 'Enter')) {
            callback.call();
        }
    }
}