// Doghole content. Require Doghole.
// Just make sure your post has right tree structure, otherwise some title may not be shown.
// 2024/06/04
// TODO: Replace scroll event listener with Intersection Observer
(function DogholeMenu($) {
    if (!$) {console.error('Require Doghole!!');return}
    console.log('DogholeMenu loaded.')
    let
    Q = x => document.querySelector(x),
    A = x => document.querySelectorAll(x),
    C = x => document.createElement(x);
    $.locate = function (target) {
        if (!target) return !1;
        let
        name = target.indexOf('#') == 0 ? target.substr(1) : target,
        menu = 
            Q(`[name="${name}"]`) || Q(`[id="${name}"]`) ||
            Q(`[name="${encodeURI(name)}"]`) || Q(`[id="${encodeURI(name)}"]`) ||
            Q(`[name="${decodeURI(name)}"]`) || Q(`[id="${decodeURI(name)}"]`) ||
            Q(`[name="${encodeURI(decodeURI(name))}"]`) || Q(`[id="${encodeURI(decodeURI(name))}"]`);
        if (!menu) return !1;
        
        // locate 暂时 off refreshMenu 事件
        if ($.refreshMenuHandler)
            window.removeEventListener('scroll', $.refreshMenuHandler)
        
        let
        needImmediateRefresing = !0,
        prev = menu.previousSibling,
        targetTop = !prev || !(prev instanceof Element) || prev.style.display == 'none' ? menu.offset().top : prev.offset().top;
        
        if (targetTop + scrollOffset + 1 != window.scrollY) {
            needImmediateRefresing = !1
            A('.widget-contents li .active').forEach(activeLi => activeLi.classList.remove('active'))
            menu.classList.add('active')
            $.Animate.scrollTo(targetTop + scrollOffset + 1, 400, () => {
                // 定位完毕后重新注册 scroll 的 refreshMenu 并立即刷新一次
                if ($.refreshMenuHandler)
                    window.addEventListener('scroll', $.refreshMenuHandler)
                if ($.refreshMenu) $.refreshMenu()
            })
        }
        window.history.pushState({status:0}, '', '#' + name);
        if (needImmediateRefresing && $.refreshMenu) $.refreshMenu()
        return !1;
    }
    var titleTags = ['h1', 'h2', 'h3']
    ,titleList = C('ul')
    ,postDom = Q('.post-content')
    ,postDomChildren = postDom.children
    ,beginLevel = 0
    ,scrollOffset = -90;
    
    
    // This part is for menu creation.
    // 存储待添加的 anchor 用的，防止遍历过程中破坏 index 结构
    var anchorsWaitForAdding = [];
    titleTags.forEach((tag, level) => {
        var founds = postDom.querySelectorAll(tag);
        if (!founds.length) {
            beginLevel += 1;
            return !0
        }
        founds.forEach((found, i) => {
            if (found.classList.contains('no-toc')) return !0
            var index = Array.from(postDomChildren).indexOf(found), index = index == -1 ? Math.random() : index
            , menu = (function (m) {
                var om = m, i = 1;
                while (anchorsWaitForAdding.find(o => o.main.innerText == m)) {
                    m = `${om}-${i++}`;
                }
                return m;
            })(found.innerText)
            , li = C('li'),
            menuElem = C('a'), titleAnchor = C('a');
            
            li.setAttribute('level', level)
            li.setAttribute('index', index)
            
            menuElem.setAttribute('href', '#' + menu)
            menuElem.setAttribute('title', found.textContent)
            menuElem.classList.add('dog-menu')
            menuElem.textContent = found.textContent
            menuElem.style.textIndent = 2.5 * (level - beginLevel) + 'em'
            menuElem.on('click', () => $.locate(menu))
            
            li.appendChild(menuElem)
            
            titleAnchor.setAttribute('name', menu)
            titleAnchor.classList.add('dog-anchor')
            
            anchorsWaitForAdding.push({
                main: found,
                add: titleAnchor
            })
            
            if (level == beginLevel) {
                titleList.append(li);
            } else {
                // Recursive it
                var recursion = function(prevLevel) {
                    var prevLevelLi = titleList.querySelectorAll(`li[level="${prevLevel}"]`)
                    , appended
                    , next;
                    
                    for (let prevLi of prevLevelLi) {
                        let prevIndex = prevLi.getAttribute('index')
                        if (prevIndex < index
                            && (!prevLi.nextSibling || prevLi.nextSibling.getAttribute('index') > index)) {
                            let firstUl = prevLi.querySelector(':scope > ul')
                            if (!firstUl) {
                                firstUl = C('ul')
                                firstUl.style.display = 'none'
                                prevLi.appendChild(firstUl)
                            }
                            firstUl.appendChild(li)
                            appended = !0
                            break
                        }
                        else if (!next || prevIndex < next.getAttribute('index')) next = prevLi
                    }
                    if (!appended) {
                        // Tree structure may be wrong
                        if (prevLevel - 1 < beginLevel) {
                            console.warn('Tree structure may be wrong')
                            let wrongLi = C('li'), wrongUl = C('ul');
                            wrongUl.appendChild(li);
                            wrongLi.appendChild(wrongUl)
                            wrongLi.setAttribute('level', prevLevel)
                            wrongLi.setAttribute('index', index - 1)
                            wrongLi.style.display = 'block'
                        }
                        else recursion(prevLevel - 1)
                    }
                }
                recursion(level - 1);
            }
        });
        if (location.href.indexOf('#') > 0) {
            $.locate(location.href.split('#')[1]);
        }
    });
    anchorsWaitForAdding.forEach(e => {
        e.main.after(e.add)
    })
    // Add to sidebar
    if (titleList.querySelector('li')) {
        titleList.classList.add('widget-list')
        titleList.classList.add('widget-contents')
        
        let
        widgetTitleSpan = C('span'),
        sidebarHeaderDiv = C('div'),
        section = C('section');
        
        widgetTitleSpan.classList.add('widget-title')
        widgetTitleSpan.textContent = 'Content'
        sidebarHeaderDiv.classList.add('sidebar-header')
        sidebarHeaderDiv.append(widgetTitleSpan)
        section.append(sidebarHeaderDiv)
        section.append(titleList)
        
        Q('.sidebar-container section').before(section)
        
        var showAndActive = (menua) => {
            var
            others = A('.widget-contents li');
            others.forEach(li => {
                li.querySelectorAll('.active').forEach(li2 =>
                    li2.classList.remove('active')
                )
            })
            
            if (menua) {
                let closestParentUl = $.Elem.parents(menua, 'ul')
                while (closestParentUl.length && !closestParentUl[0].classList.contains('widget-contents')) {
                    $.Animate.slideDown(closestParentUl[0], 200)
                    closestParentUl = $.Elem.parents(closestParentUl[0], 'ul')
                }
                menua.classList.add('active');
                let closestLi = $.Elem.closest(menua, 'li');
                if (closestLi) {
                    closestLi.querySelectorAll(':scope > ul').forEach(ul => {
                        $.Animate.slideDown(ul, 200)
                    })
                }
            }
            
            others.forEach((li, i) => {
                if (!li.querySelectorAll('.active').length) {
                    li.querySelectorAll('ul').forEach(ul => {
                        $.Animate.slideUp(ul, 200)
                    })
                }
            })
        }
        
        var _refreshMenu = () => {
            var scrollTop = window.scrollY
            , windowHeight = window.innerHeight
            , docHeight = document.documentElement.scrollHeight;
            if (scrollTop + windowHeight - docHeight == 0) {
                let
                aDogMenus = A('a.dog-menu'),
                aDogMenuLast = aDogMenus.length && aDogMenus[aDogMenus.length - 1] || null
                showAndActive(aDogMenuLast);
            }
            else {
                
                let
                dogAnchors = A('.dog-anchor'),
                dogAnchorFirst = dogAnchors.length && dogAnchors[0] || null
                
                if (dogAnchorFirst && 
                    (dogAnchorFirst.offset().top > windowHeight  - scrollOffset + scrollTop || scrollTop == 0)) {
                        showAndActive();
                    }
                
                else {
                    let max;
                    dogAnchors.forEach(menu => {
                        let
                        prev = menu.previousSibling,
                        targetTop = prev && prev.style.display == 'none' ? menu.offset().top : prev.offset().top;
                        if (targetTop + scrollOffset <= scrollTop) {
                            max = menu;
                        }
                    })
                    if (!!max) {
                        let name = max.getAttribute('name');
                        showAndActive(Q(`[href="#${name}"].dog-menu`))
                    }
                }
            }
        }
        
        function throttle(func, delay) {
          let timer = null;
          return function(...args) {
            if (!timer) {
              timer = setTimeout(() => {
                func.apply(this, args);
                timer = null;
              }, delay);
            }
          };
        }
        
        $.refreshMenuHandler = throttle(_refreshMenu, 500)
        $.refreshMenu = _refreshMenu
        window.addEventListener('resize', $.refreshMenuHandler)
        window.addEventListener('scroll', $.refreshMenuHandler)
        $.refreshMenu();
    }
    // Take over content anchor
    // 2024/02/24
    document.body.on('click', 'a[href^="#"]', function (e) {
        var href = this.getAttribute('href');
        var name = href.substr(1);
        if (!$.locate(name)) return !1;
    });
})(Doghole)