/**
 *  We handle several device classes based on browser width.
 *
 *  - desktop:   > __tablet_width__ (as set in style.ini)
 *  - mobile:
 *    - tablet   <= __tablet_width__
 *    - phone    <= __phone_width__
 */
var device_class = ''; // not yet known
var device_classes = 'desktop mobile tablet phone';

function tpl_dokuwiki_mobile(){

    // the z-index in mobile.css is (mis-)used purely for detecting the screen mode here
    var screen_mode = jQuery('#screen__mode').css('z-index') + '';

    // determine our device pattern
    // TODO: consider moving into dokuwiki core
    switch (screen_mode) {
        case '1':
            if (device_class.match(/tablet/)) return;
            device_class = 'mobile tablet';
            break;
        case '2':
            if (device_class.match(/phone/)) return;
            device_class = 'mobile phone';
            break;
        default:
            if (device_class == 'desktop') return;
            device_class = 'desktop';
    }

    jQuery('html').removeClass(device_classes).addClass(device_class);

    // handle some layout changes based on change in device
    var $handle = jQuery('#dokuwiki__aside h3.toggle');
    var $toc = jQuery('#dw__toc h3');

    if (device_class == 'desktop') {
        // reset for desktop mode
        if($handle.length) {
            $handle[0].setState(1);
            $handle.hide();
        }
        if($toc.length) {
            $toc[0].setState(1);
        }
    }
    if (device_class.match(/mobile/)){
        // toc and sidebar hiding
        if($handle.length) {
            $handle.show();
            $handle[0].setState(-1);
        }
        if($toc.length) {
            $toc[0].setState(-1);
        }
    }
}

jQuery(function(){
    var resizeTimer;
    dw_page.makeToggle('#dokuwiki__aside h3.toggle','#dokuwiki__aside div.content');

    tpl_dokuwiki_mobile();
    jQuery(window).on('resize',
        function(){
            if (resizeTimer) clearTimeout(resizeTimer);
            resizeTimer = setTimeout(tpl_dokuwiki_mobile,200);
        }
    );

    // increase sidebar length to match content (desktop mode only)
    var sidebar_height = jQuery('.desktop #dokuwiki__aside').height();
    var pagetool_height = jQuery('.desktop #dokuwiki__pagetools ul:first').height();
    // pagetools div has no height; ul has a height
    var content_min = Math.max(sidebar_height || 0, pagetool_height || 0);

    var content_height = jQuery('#dokuwiki__content div.page').height();
    if(content_min && content_min > content_height) {
        var $content = jQuery('#dokuwiki__content div.page');
        $content.css('min-height', content_min);
    }

    // blur when clicked
    jQuery('#dokuwiki__pagetools div.tools>ul>li>a').on('click', function(){
        this.blur();
    });

    (function enhanceHeaderMenu(){
        var $menu = jQuery('#dokuwiki__header .header__menu');

        if ($menu.length === 0) {
            return;
        }

        function closeMenu() {
            $menu.removeAttr('open');
        }

        jQuery(document).on('click', function (event) {
            if (!jQuery(event.target).closest($menu).length) {
                closeMenu();
            }
        });

        jQuery(document).on('keydown', function (event) {
            if (event.key === 'Escape') {
                closeMenu();
            }
        });
    })();

    // make edit toolbar icons themeable by converting img icons to CSS masks
    (function enhanceEditToolbarIcons() {
        function toMaskIcons() {
            jQuery('.dokuwiki #tool__bar button.toolbutton img').each(function () {
                var $img = jQuery(this);
                var src = $img.attr('src');

                if (!src) {
                    return;
                }

                var $icon = jQuery('<span/>', {
                    'class': 'toolicon',
                    'aria-hidden': 'true'
                });
                $icon[0].style.setProperty('--icon-url', 'url("' + src.replace(/"/g, '\\"') + '")');
                $img.replaceWith($icon);
            });
        }

        toMaskIcons();

        var toolbar = document.getElementById('tool__bar');
        if (toolbar && window.MutationObserver) {
            new MutationObserver(toMaskIcons).observe(toolbar, {childList: true, subtree: true});
        }
    }());

    // Relocate section edit buttons next to their headings.
    // DokuWiki renders the edit marker after the section content div,
    // so we match by secid: .editbutton_N belongs to h*.sectioneditN.
    (function enhanceSectionEditButtons() {
        jQuery('#dokuwiki__content .secedit[class*="editbutton_"]').each(function () {
            var $btn = jQuery(this);
            var match = $btn.attr('class').match(/editbutton_(\d+)/);
            if (!match) return;

            var $heading = jQuery('#dokuwiki__content .sectionedit' + match[1]);
            if (!$heading.length || !$heading.is('h1,h2,h3,h4,h5,h6')) return;

            // Skip if already relocated
            if ($heading.parent().hasClass('section-heading-row')) return;

            var $wrapper = jQuery('<div/>', {'class': 'section-heading-row'});
            $heading.before($wrapper);
            $wrapper.append($heading, $btn);
        });
    }());

    // enhance header search with suggestions and keyboard navigation
    (function enhanceSearch(){
        var $input = jQuery('#qsearch__in');
        var $output = jQuery('#qsearch__out');

        if ($input.length === 0 || $output.length === 0) {
            return;
        }

        var $form = $input.closest('form');
        var debounceMs = 150;
        var minChars = 2;
        var maxSuggestions = 10;
        var requestTimer = null;
        var curRequest = null;
        var items = [];
        var activeIndex = -1;
        var lastNavigation = null;
        var listId = 'qsearch__listbox';

        $form
            .addClass('search-enhanced')
            .attr('autocomplete', 'off');

        $input
            .attr('autocomplete', 'off')
            .attr('spellcheck', 'false')
            .attr('aria-autocomplete', 'list')
            .attr('aria-expanded', 'false')
            .attr('aria-controls', listId)
            .attr('aria-haspopup', 'listbox');

        $output
            .attr('aria-hidden', 'true');

        // remove default quicksearch handlers
        $input.off('keyup');
        $output.off('click');

        function clearActive() {
            activeIndex = -1;
            lastNavigation = null;
            $input.removeAttr('aria-activedescendant');
        }

        function closeList() {
            if (curRequest) {
                curRequest.abort();
                curRequest = null;
            }
            if (requestTimer) {
                window.clearTimeout(requestTimer);
                requestTimer = null;
            }

            items = [];
            clearActive();
            $output
                .removeClass('is-open is-loading')
                .attr('aria-hidden', 'true')
                .hide()
                .empty();
            $form.removeClass('is-searching');
            $input.attr('aria-expanded', 'false');
        }

        function openList() {
            $output
                .addClass('is-open')
                .attr('aria-hidden', 'false')
                .show();
            $input.attr('aria-expanded', 'true');
        }

        function renderList(content) {
            $output.empty().append(content);
            openList();
        }

        function renderLoading() {
            var $list = jQuery('<ul />', {
                'class': 'search-suggestions',
                'id': listId,
                'role': 'listbox',
                'aria-busy': 'true'
            });
            $list.append(jQuery('<li />', {
                'class': 'is-loading',
                'role': 'option',
                'aria-disabled': 'true',
                'text': 'Loading…'
            }));
            $output.addClass('is-loading');
            renderList($list);
        }

        function renderNoMatches() {
            var $list = jQuery('<ul />', {
                'class': 'search-suggestions',
                'id': listId,
                'role': 'listbox',
                'aria-busy': 'false'
            });
            $list.append(jQuery('<li />', {
                'class': 'is-empty',
                'role': 'option',
                'aria-disabled': 'true',
                'text': 'No Matches'
            }));
            $output.removeClass('is-loading');
            renderList($list);
        }

        function updateActive() {
            var $options = $output.find('li[data-index]');
            $options.removeClass('is-active is-tabbed').attr('aria-selected', 'false');

            if (activeIndex < 0 || activeIndex >= items.length) {
                clearActive();
                return;
            }

            var $active = $options.filter('[data-index="' + activeIndex + '"]');
            $active.addClass('is-active').attr('aria-selected', 'true');
            if (lastNavigation === 'tab') {
                $active.addClass('is-tabbed');
            }
            $input.attr('aria-activedescendant', $active.attr('id'));
        }

        function moveActive(delta, source) {
            if (!items.length) {
                return;
            }
            lastNavigation = source || null;
            if (activeIndex < 0) {
                activeIndex = delta > 0 ? 0 : items.length - 1;
            } else {
                activeIndex = (activeIndex + delta + items.length) % items.length;
            }
            updateActive();
        }

        function selectActive() {
            if (activeIndex < 0 || activeIndex >= items.length) {
                return false;
            }
            window.location.assign(items[activeIndex].href);
            return true;
        }

        function renderResults(results) {
            var $list = jQuery('<ul />', {
                'class': 'search-suggestions',
                'id': listId,
                'role': 'listbox',
                'aria-busy': 'false'
            });

            results.forEach(function (item, index) {
                var optionId = 'qsearch__option_' + index;
                var $link = jQuery('<a />', {
                    'href': item.href,
                    'text': item.text
                });
                var $option = jQuery('<li />', {
                    'id': optionId,
                    'role': 'option',
                    'data-index': index,
                    'aria-selected': 'false'
                });
                $option.append($link);
                $list.append($option);
            });

            $output.removeClass('is-loading');
            renderList($list);
            clearActive();
        }

        function handleResults(data) {
            $form.removeClass('is-searching');
            curRequest = null;

            var $wrapper = jQuery('<div />').html(data || '');
            var $links = $wrapper.find('a');
            items = [];

            $links.each(function () {
                if (items.length >= maxSuggestions) {
                    return false;
                }
                items.push({
                    href: this.href,
                    text: jQuery(this).text()
                });
                return true;
            });

            if (!items.length) {
                renderNoMatches();
                return;
            }

            renderResults(items);
        }

        function scheduleSearch() {
            if (requestTimer) {
                window.clearTimeout(requestTimer);
                requestTimer = null;
            }
            requestTimer = window.setTimeout(runSearch, debounceMs);
        }

        function runSearch() {
            var term = jQuery.trim($input.val());

            if (term.length < minChars) {
                closeList();
                return;
            }

            if (curRequest) {
                curRequest.abort();
            }

            $form.addClass('is-searching');
            renderLoading();

            var base = (typeof DOKU_BASE !== 'undefined') ? DOKU_BASE : '/';
            curRequest = jQuery.post(
                base + 'lib/exe/ajax.php',
                {
                    call: 'qsearch',
                    q: encodeURI(term)
                },
                handleResults,
                'html'
            ).fail(function () {
                $form.removeClass('is-searching');
                curRequest = null;
                renderNoMatches();
            });
        }

        $input.on('input', scheduleSearch);

        $input.on('keydown', function (event) {
            var key = event.key;
            var isOpen = $output.hasClass('is-open');

            if (!isOpen) {
                return;
            }

            if (key === 'Escape') {
                event.preventDefault();
                closeList();
                return;
            }

            if (!items.length) {
                return;
            }

            if (key === 'ArrowDown') {
                event.preventDefault();
                moveActive(1, 'arrow');
                return;
            }

            if (key === 'ArrowUp') {
                event.preventDefault();
                moveActive(-1, 'arrow');
                return;
            }

            if (key === 'Tab') {
                event.preventDefault();
                moveActive(event.shiftKey ? -1 : 1, 'tab');
                return;
            }

            if (key === 'Enter') {
                if (selectActive()) {
                    event.preventDefault();
                }
            }
        });

        $output.on('mouseenter', 'li[data-index]', function () {
            activeIndex = parseInt(jQuery(this).attr('data-index'), 10);
            lastNavigation = 'mouse';
            updateActive();
        });

        $output.on('mouseleave', 'li[data-index]', function () {
            clearActive();
        });

        $output.on('mousedown', 'li[data-index] > a', function (event) {
            event.preventDefault();
            window.location.assign(this.href);
        });

        jQuery(document).on('click', function (event) {
            if (!jQuery(event.target).closest($form).length) {
                closeList();
            }
        });
    })();
});
