;(function ($, window) {
    var headIndex = (function () {
        function headIndex(element, options) {
            this.settings = $.extend(true, $.fn.headIndex.default, options || {});
            this.element = element;
            this.init();
        }

        headIndex.prototype = {
            init: function () {
                this.articleWrap = $(this.settings.articleWrapSelector);
                this.headerList = this.articleWrap.find(':header');
                this.indexBox = $(this.settings.indexBoxSelector);
                this.indexScrollBox = $(this.settings.indexScrollBoxSelector);
                this.scrollBody = $(this.settings.scrollSelector);
                this.scrollWrap = $(this.settings.scrollWrap);
                this.manual = false;
                this.mouseHovered = false;

                if (this.indexBox.length === 0 || this.headerList.length === 0) {
                    return null;
                }

                this.initHeader();
                this.event();
            },

            initHeader: function () {
                for (var i = 0; i < this.headerList.length; i++, this.autoId++) {
                    //文章header添加id和计算高度
                    this.headerList[i].id = this.headerList[i].id || "header-id-" + this.autoId;
                    this.headerList[i].topHeight = this.offsetTop(this.headerList[i]);
                    this.headerList[i].h = Number(this.headerList[i].tagName.charAt(1));
                }

                this.tempHtml = [];
                this.buildHtml(this.buildTree());

                var res = '<ul>' + this.tempHtml.join('') + '</ul>';
                this.indexBox.html(res);
            },

            event: function () {
                var that = this;
                var manualValTimer = null;
                this.indexBox.on('click.headindex', function (event) {
                    var target = $(event.target);
                    if (target.hasClass(that.settings.linkClass)) {
                        event.preventDefault();
                        var indexItem = target.parent('.' + that.settings.itemClass);

                        //手动点击的时候，屏蔽滑动响应
                        that.manual = true;
                        if (manualValTimer) {
                            clearTimeout(manualValTimer);
                            manualValTimer = null;
                        }
                        manualValTimer = setTimeout(function () {
                            that.manual = false;
                        }, 400);
                        that.current(indexItem);

                        //滚动到当前的标题
                        that.scrollTo(event.target.getAttribute('href'))
                    }
                });

                //鼠标 Hover 监听
                this.indexScrollBox.on('mouseover', function (event) {
                    that.mouseHovered = true;
                });
                this.indexScrollBox.on('mouseleave', function (event) {
                    that.mouseHovered = false;
                });

                //滑动监听
                $(this.scrollWrap).scroll(function () {
                    if (that.manual) return;
                    that.updateCurrent();
                });

                //默认选中当前滑动的位置
                that.updateCurrent();
            },

            updateTopHeight: function () {
                var length = this.headerList.length;
                var i;
                if (length === 0) return;

                //第一个和最后一个标题的高度都没有发生变化，默认整体高度没变
                if (this.headerList[0].topHeight === this.offsetTop(this.headerList[0])
                    && this.headerList[length - 1].topHeight === this.offsetTop(this.headerList[length - 1])) {
                    return;
                }

                //第一个和最后一个标题的高度变化的差值相同，默认整体标题的变化差值相同
                if ((this.headerList[0].topHeight - this.offsetTop(this.headerList[0]))
                    === (this.headerList[length - 1].topHeight - this.offsetTop(this.headerList[length - 1]))) {

                    var hx = this.offsetTop(this.headerList[0]) - this.headerList[0].topHeight;
                    for (i = 0; i < this.headerList.length; i++, this.autoId++) {
                        this.headerList[i].topHeight += hx;
                    }
                    return;
                }

                //其他变化，整体进行重新计算和赋值
                for (i = 0; i < this.headerList.length; i++, this.autoId++) {
                    this.headerList[i].topHeight = this.offsetTop(this.headerList[i]);
                }
            },

            current: function (indexItem) {
                var subBox,
                    currentClass = 'current';

                if (indexItem.length === 0 || indexItem.hasClass(currentClass)) {
                    return;
                }
                //移除其他位置的current类
                var otherCurrent = this.indexBox.find('li.' + currentClass);
                if (otherCurrent.length > 0) {
                    otherCurrent.removeClass(currentClass);
                }
                //先清除全部的open标记
                this.indexBox.find('ul.open').removeClass('open');

                //打开当前下级别的subItemBox
                subBox = indexItem.children('.' + this.settings.subItemBoxClass);
                if (subBox.length > 0) {
                    subBox.addClass('open').slideDown();
                }
                //为了应对非常快速滑动的时候，scroll函数略过父级的box
                var parentsBox = indexItem.parents('ul.' + this.settings.subItemBoxClass);
                if (parentsBox.length > 0) {
                    parentsBox.addClass('open').slideDown()
                }
                //关闭其他位置打开的subItemBox 排除当前父级上的subItemBox
                subBox = this.indexBox.find('ul.' + this.settings.subItemBoxClass).not('.open');
                if (subBox.length > 0) {
                    subBox.slideUp()
                }
                //为当前添加current类
                indexItem.addClass(currentClass);
                //如果超出了目录的边界，则滚动到目录中
                if (this.mouseHovered){
                    return;
                }
                var relativeOffsetTopToWrapper = indexItem.position().top;
                var indexScrollBoxScrollTop = this.indexScrollBox.scrollTop();
                var indexScrollBoxHeight = this.indexScrollBox.height();
                if (relativeOffsetTopToWrapper < 20 + indexItem.height()){
                    var target = indexScrollBoxScrollTop + relativeOffsetTopToWrapper - 20 - indexItem.height();
                    if (target < 30){
                        target = 0;
                    }
                    this.indexScrollBox.stop().animate({
                        scrollTop: target
                    }, 'normal');
                }
                if (relativeOffsetTopToWrapper > indexScrollBoxHeight - 10){
                    this.indexScrollBox.stop().animate({
                        scrollTop: indexScrollBoxScrollTop + relativeOffsetTopToWrapper - indexScrollBoxHeight + 10 + indexItem.height()
                    }, 'normal');
                }
            },

            buildHtml: function (tree) {
                if (tree === undefined || tree.length === 0) return;

                for (var i = 0; i < tree.length; i++) {
                    this.tempHtml.push("<li class='" + this.settings.itemClass + "'>"
                        + "<a no-pjax class='" + this.settings.linkClass + "' href='#" + tree[i].item.id + "'>"
                        + tree[i].item.innerText + "</a>");

                    if (tree[i].children.length !== 0) {
                        this.tempHtml.push("<ul class='" + this.settings.subItemBoxClass + "'>");
                        this.buildHtml(tree[i].children);
                        this.tempHtml.push("</ul>");
                    }
                    this.tempHtml.push("</li>")
                }
            },

            buildTree: function () {
                var current = null,
                    tempCur,
                    indexTree = [];

                for (var i = 0; i < this.headerList.length; i++) {
                    if (current == null) {
                        current = {item: this.headerList[i], parent: null, children: [],};
                        indexTree.push(current);
                        continue;
                    }
                    if (current.item.h < this.headerList[i].h) {
                        tempCur = {item: this.headerList[i], parent: current, children: [],};
                        current.children.push(tempCur);
                        current = tempCur;
                        continue;
                    }
                    if (current.item.h === this.headerList[i].h) {
                        tempCur = {item: this.headerList[i], parent: current.parent, children: [],};
                        ((current.parent && current.parent.children) || indexTree).push(tempCur);
                        current = tempCur;
                        continue;
                    }
                    while (current != null && current.item.h > this.headerList[i].h) {
                        current = current.parent;
                    }
                    if (current == null) {
                        current = {item: this.headerList[i], parent: null, children: [],};
                        indexTree.push(current);
                        continue;
                    }
                    i--;
                }

                return indexTree;
            },
            search: function (start, end, findValue) {
                if (this.headerList.length === 0) return null;

                if (end - start <= 1) {
                    if (this.headerList[end].topHeight < findValue) {
                        return this.headerList[end];
                    }
                    return this.headerList[start];
                }

                if (start < end) {
                    var middleIndex = parseInt((start + end) / 2);
                    var middleValue = this.headerList[middleIndex].topHeight;
                    if (findValue < middleValue) {
                        end = middleIndex;
                    } else if (findValue > middleValue) {
                        start = middleIndex
                    } else {
                        return this.headerList[middleIndex];
                    }
                    return this.search(start, end, findValue)
                }
            },

            /**
             * 计算每个标题距离文档顶部的垂直高度，
             * 为了应对不同需求，如果计算不准确，可以修改这个方法
             * @param elem
             * @returns {number}
             */
             /*已重写该方法*/
            offsetTop: function (elem) {
                return $(elem).offset().top - this.settings.offset;
                /*var wrapTop = this.articleWrap[0].getBoundingClientRect().top
                var eTop = elem.getBoundingClientRect().top

                return parseInt(eTop - wrapTop - this.settings.offset)*/

                // var rect, win;
                // if (!elem) {
                //     return;
                // }
                // if (!elem.getClientRects().length) {
                //     return {top: 0, left: 0};
                // }
                //
                // rect = elem.getBoundingClientRect();
                // win = elem.ownerDocument.defaultView;
                // return parseInt(rect.top + win.pageYOffset);
            },
            /**
             * 滑动到指定id选择器的标题
             * @param eid 标题的id值
             */
            scrollTo: function (eid) {
                this.scrollBody.stop().animate({
                    scrollTop: this.offsetTop(document.getElementById(eid.substr(1))) + 8
                }, 'normal', 'easeOutExpo');
            },
            /**
             * 更新当前位置
             */
            updateCurrent: function () {
                var scrollTop = this.scrollBody.scrollTop();
                this.updateTopHeight();

                var find = this.search(0, this.headerList.length - 1, scrollTop);//
                if (!find) {
                    return;
                }

                var indexItem = this.indexBox
                    .find('a[href="#' + find.id + '"]')
                    .parent('li.' + this.settings.itemClass);

                this.current(indexItem);
            },
            /**
             * 清除缓存对象
             */
            clean: function () {
                if (this.element) {
                    this.element.data("headIndex", null)
                }
            },
            /**
             * 临时忽略滚动监听
             */
            ignoreScrollEvent: function (ignore) {
                if (ignore) {
                    this.manual = true;
                } else {
                    this.manual = false;
                    this.updateCurrent();
                }
            }
        };

        headIndex.prototype.autoId = 1;

        return headIndex;
    })();

    $.fn.headIndex = function (options) {
        return this.each(function () {
            var $this = $(this),
                instance = $this.data("headIndex");
                /*此处为适配 pjax 注释了下面的 if*/
            /*if (!instance) {*/
                instance = new headIndex($this, options);
                $this.data("headIndex", instance);
            /*}*/
            if ($.type(options) === "string") return instance[options]();
        });
    };

    //-----------------------------------
    // 默认参数
    //-----------------------------------
    $.fn.headIndex.default = {
        articleWrapSelector: ".article-wrap",/*包裹文章的选择器*/
        indexBoxSelector: ".index-box",/*包裹目录索引的选择器*/
        indexScrollBoxSelector: "#leftbar_part2_inner",/*包裹目录索引的选择器 (新增)*/
        scrollSelector: 'body,html',/*滑动元素的选择器*/
        scrollWrap: window,/*能够监听到scrollSelector滑动的选择器*/
        subItemBoxClass: "index-subItem-box",
        itemClass: "index-item",
        linkClass: "index-link",
        offset: 0,/*滑动偏移量 按需求进行偏移*/
    }
})(jQuery, window);
