
//立即执行函数 把jquery和window作为参数传进来  分隔出作用域
(function ($, window) {
    var gallery = {
        //主要入口函数
        init: function (options, el) {
            //为了统一和方便阅读  每个函数都会将this赋值为base  防止一些函数执行上下文改变了this指向
            var base = this;
            base.options = $.extend({}, $.fn.gallery.options, options); //将默认参数和传入的参数合并 
            base.$el = el; // 最外层容器
            base.initDom();
        },
        //初始化DOM结构
        initDom: function () {
            var base = this;
            if (base.$el.children().length === 0) { return false }  //如果传入的对象的items为0  return false
            base.$UserItem = base.$el.find('.item').wrapAll('<div class=\'gallery-wrapper-outer\'></div>');   //创建gallery-wrapper-out包裹gallery-item
            base.$el.find('.item').wrapAll('<div class=\'gallery-wrapper\'></div>').wrap('<div class=\'gallery-item\'></div>'); //创建gallery-item包裹item
            base.$wrapperOut = base.$el.find('.gallery-wrapper-outer');
            //所有gallery-item的jquery对象
            base.$galleryItem = base.$el.find('.gallery-item');
            //初始化的item数量
            base.$itemNum = base.$galleryItem.length;
            //将初始的item数量保存出来 避免在屏幕从小放大的时候无法更新回初始的items数量
            base.initItem = base.options.items;
            //当前的index
            base.$curIndex = base.options.initIndex;
            //wrapper的tranlate的值
            base.translateX = 0;
            //当前是否在切换中
            base.isTranstion = false;
            //遍历为每个item依次添加下标
            for (var i = 0; i < base.$galleryItem.length; i++) {
                base.$galleryItem.eq(i).attr('data-item-index', i);
            }
            //wrap元素
            base.$wrap = base.$el.find('.gallery-wrapper');
            //最大的值 
            base.$maxIndex = base.$galleryItem.length - 1;
            //最外层元素的宽度
            base.$elWidth = base.$el.width();
            base.checkBrowser();
            base.setCss();                       // 初始化css样式
            if (base.options.needPlay) {
                base.buildNav();
                base.buildPaignation();              //创建分页器
                base.bindClick();                    //绑定点击事件
                base.drag();                         //开启拖拽事件
                base.goTo(base.$curIndex);
                base.touch();
                base.autoPlayFn();               //创建左右切换按钮
            }
        },
        //循环函数
        loop: function () {
            var base = this;
            if (base.options.loop && base.options.needPlay) {
                if (base.options.items === 1) {
                    base.$wrap.prepend(base.getCurEl(base.$maxIndex).clone(false).addClass('gallery-item-duplicate'));
                    base.$wrap.append(base.getCurEl(0).clone(true).addClass('gallery-item-duplicate'));
                }
                else {
                    for (var i = 0; i < base.options.items - 1; i++) {
                        base.$wrap.prepend(base.getCurEl(base.$maxIndex - i).clone(true).addClass('gallery-item-duplicate'));
                        base.$wrap.append(base.getCurEl(i + 0).clone(true).addClass('gallery-item-duplicate'));
                    }
                }
                //更新gallery-item
                base.$galleryItem = base.$el.find('.gallery-item');
            }
        },
        //获取data-item-index值为target并且不是复制的元素
        getCurEl: function (target) {
            var base = this;
            return base.$el.find(".gallery-item[data-item-index=" + target + "]:not(.gallery-item-duplicate)");
        },
        //初始化样式
        setCss: function () {
            var base = this;
            //设置切换速度
            base.$wrap.css(base.changeTransition(base.options.speed));
            if (base.options.items == 1 && base.options.effect == 'fade') {
                //创建一个虚拟元素  为整个div撑起高度 
                base.$virtual = base.$wrap.prepend(base.getCurEl(0).clone(true).addClass('gallery-item-virtual gallery-item-duplicate')).find('.gallery-item-virtual');
                base.$virtual.css({
                    'visibility': 'hidden',
                    'display': 'block',
                    'z-index': '-1',
                })
                if(base.options.responsive){
                    base.responsiveWidthFn();
                }
                else{
                    base.upDateItem();
                }
                base.$galleryItem = base.$el.find('.gallery-item:not(.gallery-item-duplicate)');
                base.$galleryItem.css({
                    'position': 'absolute',
                    'top': '0px',
                    'left': '0px',
                    'right': '0px',
                    'bottom': '0px',
                    'opacity': '0',
                })
                base.getCurEl(0).css({ 'opacity': '1' })
            }
            else {
                base.loop();
                base.$el.find('.gallery-item').addClass('gallery-item-slide');
                if(base.options.responsive){
                    base.responsiveWidthFn();
                }
                else{
                    base.upDateItem();
                }
                base.maxWidth = base.$wrapWidth - base.$elWidth;
            }
            //监听窗口变化  当窗口变化  调用responsiveWidthFn函数； 
            if(base.options.responsive){
                $(window).resize(function () {
                    base.responsiveWidthFn();
                });
            }
        },
        //判断浏览器是否支持css3 translate3D的属性
        checkBrowser:function(){
            var base = this,
            translate3D = "translate3d(0px, 0px, 0px)",
            tempElem = document.createElement("div"),
            regex,
            asSupport,
            support3d,
            isTouch;
    
            tempElem.style.cssText = "  -moz-transform:" + translate3D +
                                "; -ms-transform:"     + translate3D +
                                "; -o-transform:"      + translate3D +
                                "; -webkit-transform:" + translate3D +
                                "; transform:"         + translate3D;
            regex = /translate3d\(0px, 0px, 0px\)/g;
            asSupport = tempElem.style.cssText.match(regex);
            support3d = (asSupport !== null && asSupport.length === 1);
        
            isTouch = "ontouchstart" in window || window.navigator.msMaxTouchPoints;
        
            base.browser = {
                "support3d" :support3d,
                "isTouch" : isTouch
            };
        },
        //更新item的宽度
        upDateItem: function () {
            var base = this;
            var width = base.$el.width();
            base.$galleryItem = base.$el.find('.gallery-item');
            //item的宽度
            if (base.options.items === 1 && base.options.effect === 'fade') {
                base.$wrapWidth = width;
            }
            else {
                base.itemWidth = Math.floor((width - base.options.spaceBetween * (base.options.items - 1)) / base.options.items);
                base.$galleryItem.css({ 'width': base.itemWidth, })
                //wrap的宽度
                if (base.options.wrap) {
                    base.$wrapWidth = base.$el.width();
                    base.$galleryItem.css({ 'marginBottom': base.options.bottom, 'marginRight': base.options.spaceBetween });
                    var i = base.options.items;
                    while (i <= base.$galleryItem.length) {
                        $(base.$galleryItem[i - 1]).css({ 'marginRight': '0px' });
                        i += base.options.items;
                    }
                }
                else {
                    base.$galleryItem.css({ 'marginRight': base.options.spaceBetween + 'px' });
                    base.$galleryItem.last().css({ 'marginRight': '0px', })
                    base.$wrapWidth = (base.itemWidth * base.$galleryItem.length) + (base.options.spaceBetween * (base.$galleryItem.length - 1));
                }
            }
            base.$wrap.css({ 'width': base.$wrapWidth + 'px' })
        },
        //响应式函数  动态更新宽度
        responsiveWidthFn: function () {
            var base = this;
            if (base.options.responsive) {
                var lastWidth, curWidth;//上一次宽度  当前宽度
                //做一个判断  只有当最外层元素的宽度改变的时候  才触发下面函数  避免每次窗口变化都触发下面函数
                lastWidth = curWidth;
                curWidth = base.$el.width();
                if (curWidth != lastWidth) {
                    var obj = base.options.responsiveWidth;
                    var wid = $(window).width();
                    base.options.items = base.initItem;
                    //如果不为空 遍历对象  
                    if (!($.isEmptyObject(obj))) {
                        //先排序 再遍历对象 解决某些浏览器对遍历对象不按照顺序的问题
                        var sortKeys = Object.keys(obj).sort(function (a, b) {
                            return b - a;
                        });
                        for (var i = 0; i < sortKeys.length; i++) {
                            if (wid <= sortKeys[i]) {
                                //更新全局的items  spaceBetween bottom 的值
                                //需要做出判断  因为有可能传过来的值是空的
                                obj[sortKeys[i]].items ?  base.options.items = obj[sortKeys[i]].items : '';
                                obj[sortKeys[i]].spaceBetween ?base.options.spaceBetween = obj[sortKeys[i]].spaceBetween : '';
                                obj[sortKeys[i]].bottom ? base.options.bottom = obj[sortKeys[i]].bottom : '';
                            }
                        }
                    }
                    //更新对应宽度
                    base.upDateItem();
                }
            }
        },
        //下一个
        next: function () {
            var base = this;
            if(base.isTranstion){
                return false;
            }
            //判断是滑动效果 还是fade效果
            if (base.options.effect === 'fade' && base.options.items === 1) {
                //fade切换实现逻辑
                var last = base.$curIndex;
                if (base.$curIndex >= base.$maxIndex) {
                    base.$curIndex = 0
                }
                else {
                    base.$curIndex += 1;
                }
                base.fadeMove(last,base.$curIndex);
            }
            else {
                //滑动切换实现逻辑
                //如果是最后一个 
                if ((base.$elWidth + base.translateX) >= base.$wrapWidth) {
                    //如果是loop 
                    if (base.options.loop) {
                        if (base.options.items == 1) {
                            base.translateX = base.options.spaceBetween + base.itemWidth;
                        }
                        else {
                            base.translateX = (base.itemWidth + base.options.spaceBetween) * (base.options.items - 2);
                        }
                        base.$wrap.css(base.changeTransition(0));
                        base.browser.support3d ? base.$wrap.css(base.doTranslate(-base.translateX)) : base.$wrap.stop(true,true).animate({'left':-base.translateX},0);
                        // BUG!!   ≧ ﹏ ≦   如果删除下面这行代码循环轮播的最后一个跳转到第一个就会有问题  
                        base.getCurTranslate();
                        base.$wrap.css(base.changeTransition(base.options.speed));
                    }
                    //不是loop
                    else {
                        base.translateX = -(base.itemWidth + base.options.spaceBetween);
                        base.$curIndex = -1;
                    }
                }
                var value = base.itemWidth + base.options.spaceBetween;
                base.translateX += value;
                if (base.$curIndex >= base.$maxIndex) {
                    base.$curIndex = 0;
                }
                else {
                    base.$curIndex += 1;
                }
                base.move(-base.translateX);
            }
            base.addActive();
        },
        //跳转到第几个
        goTo: function (target) {
            var base = this;
            if(base.isTranstion){
                return false;
            }
            if (base.options.effect === 'fade' && base.options.items === 1) {
                var last = base.$curIndex;
                base.$curIndex = target;
                base.fadeMove(last,base.$curIndex);
                
            }
            else {
                var index = base.getCurEl(target).index();
                base.translateX = (base.itemWidth * index + (index * base.options.spaceBetween));
                if ((base.translateX + base.$elWidth) > base.$wrapWidth) {
                    base.translateX = base.$wrapWidth - base.$elWidth;
                }
                base.$curIndex = target;
                base.move(-base.translateX);
            }
            base.addActive();
        },
        //fade切换实现函数
        fadeMove: function (cur, target) {
            var base = this;
            base.getCurEl(cur).css({ 'opacity': '0', 'z-index': '1' });
            base.getCurEl(target).css({ 'opacity': '1', 'z-index': '2' });
            base.upDatePagination();
        },
        //上一个
        prev: function () {
            var base = this;
            if(base.isTranstion){
                return false;
            }
            if (base.options.effect === 'fade' && base.options.items === 1) {
                var last = base.$curIndex;
                if (base.$curIndex <= 0) {
                    base.$curIndex = base.$maxIndex;
                }
                else {
                    base.$curIndex -= 1;
                }
                base.fadeMove(last, base.$curIndex);
            }
            else {
                var value = base.itemWidth + base.options.spaceBetween;
                var curValue = base.translateX;
                if (curValue <= 5) {
                    if (base.options.loop) {
                        var nums = base.$el.find('.gallery-item:not(.gallery-item-duplicate)').length;
                        base.translateX = nums * (base.options.spaceBetween + base.itemWidth);
                        base.$wrap.css(base.changeTransition(0));
                        base.browser.support3d ? base.$wrap.css(base.doTranslate(-base.translateX)) : base.$wrap.stop(true,true).animate({'left':-base.translateX},0);
                        // BUG!!   ≧ ﹏ ≦   如果删除下面这行代码循环轮播的最后一个跳转到第一个就会有问题  我不知道为什么!!!
                        base.getCurTranslate();
                        base.$curIndex = base.$maxIndex;
                        base.$wrap.css(base.changeTransition(base.options.speed));
                    }
                    else {
                        base.translateX = (base.$galleryItem.length - base.options.items + 1) * value;
                        base.$curIndex = base.$maxIndex + 1;
                    }
                }
                base.translateX = base.translateX - value;
                if (base.$curIndex <= 0) {
                    base.$curIndex = base.$maxIndex;
                }
                else {
                    base.$curIndex -= 1;
                }
                base.move(-base.translateX);
            }
            base.addActive();
        },
        //获取当前translateX的值
        getCurTranslate: function () {
            var base = this;
            //通过css方法获取translate的值 然后通过正则表达式过滤掉字母   然后通过split方法分割成一个数组  数组的第四个就是translateX的值
            var cur = base.$wrap.css('transform').replace(/[^0-9\,]/g, '').split(',')[4];
            return cur;
        },
        //切换函数  所有切换最终都是通过这个函数来实现的
        move: function (value) {
            var base = this;
            base.isTranstion = true;
           
            //如果支持css3
            if(base.browser.support3d === true){
                base.$wrap.css(base.doTranslate(value));
            }
            //否则使用css2实现
            else{
                base.moveCss2(value);
            }
            base.upDatePagination();
            if(base.options.autoPlay){
                base.stop();
                base.play();
            }
            base.isTranstion = false;
           
        
            //回调函数
            if (typeof base.options.afterMove === 'function') {
                //用apply 将当前对象作为afterMove函数的调用对象；这样可以在外部调用所有当前对象的方法
                base.options.afterMove.apply(this);
            }
        },
        //使用css2切换 用于不兼容css3的浏览器
        moveCss2:function(value){
            var base = this;
            base.$wrap.stop(true,true).animate({
                "left":value,
            })
        },
        //自动轮播函数
        autoPlayFn: function () {
            var base = this;
            if (base.options.autoPlay) {
                base.moveTimer = setInterval(function () {
                    base.next();
                }, base.options.autoPlayTime);

                //是否鼠标悬停暂停轮播
                if (base.options.stopOnHover) {
                    base.$el.hover(function () {
                        clearInterval(base.moveTimer);
                    },
                    function () {
                        base.moveTimer = setInterval(function () {
                            base.next();
                        }, base.options.autoPlayTime);
                    })
                }
            }
        },
        play:function(){
            var base = this;
            base.moveTimer = setInterval(function(){
                base.next();
            },base.options.autoPlayTime);
        },
        stop:function(){
            var base = this;
            clearInterval(base.moveTimer);
        },
        //为当前元素添加active
        addActive: function () {
            var base = this;
            var el = base.getCurEl(base.$curIndex);
            base.$el.find('.gallery-item').removeClass('active gallery-item-prev gallery-item-next');
            el.addClass('active');
            el.next().addClass('gallery-item-next');
            el.prev().addClass('gallery-item-prev');
            base.onChange();
        },
        //动画效果
        doTranslate: function (pixels) {
            return {
                "-webkit-transform": "translate3d(" + pixels + "px, 0px, 0px)",
                "-moz-transform": "translate3d(" + pixels + "px, 0px, 0px)",
                "-o-transform": "translate3d(" + pixels + "px, 0px, 0px)",
                "-ms-transform": "translate3d(" + pixels + "px, 0px, 0px)",
                "transform": "translate3d(" + pixels + "px, 0px,0px)"
            }
        },
        //改变transition-duration时间
        changeTransition: function (time) {
            return {
                "transition-duration": time + "s",
                "-moz-transition-duration": time + "s",
                "-webkit-transition-duration": time + "s",
                "-o-transition-duration": time + "s",
            }
        },
        //添加左右切换按钮
        buildNav: function () {
            var base = this;
            if (base.options.navigation == false || base.$galleryItem.length <= 1) {
                return false;
            }
            base.prevEl = $('<div class=\'gallery-prev\'></div>').appendTo(base.$wrapperOut);
            base.nextEl = $('<div class=\'gallery-next\'></div>').appendTo(base.$wrapperOut);
            base.nextEl.on('click touchend', function (e) {
                e.preventDefault();
                base.next();
            })
            base.prevEl.on('click touchend', function (e) {
                e.preventDefault();
                base.prev();
            })
        },
        //添加分页器函数
        buildPaignation: function () {
            var base = this;
            if (base.options.pagination === false || base.$galleryItem.length<=1) {
                return false;
            }
            base.pagination = [];
            base.paginationBox = $('<div class=\'gallery-pagination-box\'></div>').appendTo(base.$el);
            // var num = Math.ceil(base.$itemNum / base.options.items);
            var num = base.$itemNum - base.options.items + 1;
            base.paginationNum = num;
            for (var i = 0; i < num; i++) {
                base.pagination[i] = $('<div class=\'gallery-page\'></div>').appendTo(base.paginationBox);
                //绑定点击事件 
                base.pagination[i].on('click touchend', (function (j) {
                    // ie9不兼容let语法  所以使用闭包的方式
                        return function () {
                            base.goTo(j);
                        }
                    })(i)
                )
            }
        },
        //更新分页器
        upDatePagination: function () {
            var base = this;
            if (base.$curIndex < base.paginationNum) {
                base.pagination[base.$curIndex].addClass('active').siblings().removeClass('active');
            }
        },
        //切换之后调用的函数 
        onChange: function () {
            var base = this;
            if (base.options.bindControl.length > 0) {
                base.bindControlFn(base.options.bindControl)
                for (var i = 0; i < base.options.bindControl.length; i++) {
                    if (base.$curIndex != base.options.bindControl[i].$curIndex) {
                        base.options.bindControl[i].goTo(base.$curIndex);
                    }
                }
            }
        },
        //绑定控制  通过其他元素控制切换
        bindControlFn: function (args) {
            var base = this;
            for (var i = 0; i < args.length; i++) {
                args[i].onChange = function () {
                    base.$curIndex = this.$curIndex;
                    base.goTo(base.$curIndex);
                }
            }
        },
        //绑定点击
        bindClick: function () {
            var base = this;
            if (base.options.clickBind) {
                base.$galleryItem.click(function () {
                    base.$curIndex = $(this).index();
                    base.addActive();
                })
            }
        },
        //实现拖拽切换
        drag: function () {
            var base = this;
            var x = 0;
            var y = 0;
            var cur = 0;
            var isDown = false;
            if (base.options.drag === false) {
                return false;
            }
            //当鼠标按下  
            base.$el.on('mousedown', function (event) {
                var e = event || window.event;
                e.preventDefault()
                x = e.clientX;
                y = e.clientY;
                cur = base.translateX;
                isDown = true;
                base.$wrap.css(base.changeTransition(0));
            })
            //当鼠标移动
            $(window).on('mousemove', function (event) {
                var e = event || window.event;
                if (isDown === true) {
                  
                    base.isTranstion = true;
                    var newx = e.clientX;
                    var value = 0;
                    var num = 0;
                    if (newx > x) {
                        value = newx - x;
                        num = cur - value;
                        base.$wrap.css(base.doTranslate(-num));
                    }
                    else {
                        value = x - newx;
                        num = cur + value;
                        base.$wrap.css(base.doTranslate(-num));
                    }
                }
            })
            //当松开鼠标
            $(window).on('mouseup', function (event) {
                var e = event || window.event;
                if (isDown === true) {
                    base.$wrap.css(base.changeTransition(base.options.speed));
                    isDown = false;
                    base.isTranstion = false;
                    var val = base.getCurTranslate();
                    if (val > cur) {
                        base.next();
                    }
                    if (val < cur) {
                        base.prev();
                    }
                    
                }
            })
        },
        //移动端触摸滑动函数
        touch: function () {
            var base = this;
            var x = 0;
            var y = 0;
            var cur = 0;
            var isDown = false;
            if (base.options.drag === false) {
                return false;
            }
            base.$el.on('touchstart', function (event) {
                var e = event || window.event;
                e.preventDefault()
                x = e.originalEvent.touches[0].clientX;
                y = e.originalEvent.touches[0].clientY;
                cur = base.translateX;
                isDown = true;
                base.$wrap.css(base.changeTransition(0));
            })
            $(window).on('touchmove', function (event) {
                var e = event || window.event;
                if (isDown === true) {
                    base.isTranstion = true;
                    var newx = e.originalEvent.touches[0].clientX;
                    var value = 0;
                    var num = 0;
                    if (newx > x) {
                        value = newx - x;
                        num = cur - value;
                        base.$wrap.css(base.doTranslate(-num));
                    }
                    else {
                        value = x - newx;
                        num = cur + value;
                        base.$wrap.css(base.doTranslate(-num));
                    }
                }
            })
            $(window).on('touchend', function (event) {
                var e = event || window.event;
                if (isDown === true) {
                    base.$wrap.css(base.changeTransition(base.options.speed));
                    isDown = false;
                    base.isTranstion = false;
                    var val = base.getCurTranslate();
                    if (val > cur) {
                        base.next();
                    }
                    if (val < cur) {
                        base.prev();
                    }
                }
            })
        }
    }

    //把调用方法挂载到jquery上
    $.fn.gallery = function (options) {
        return this.each(function(){
            var gall = Object.create(gallery);
            gall.init(options, $(this));
            return gall;
        })
    }

    //内容导航切换公用函数
    //相当于superslide的点击切换 三个参数  第一个是导航元素  第二个是切换的元素内容  第三个是出触发条件 一般为 mouseover  click
    // 调用方法示例 $.tabChange('div .tab li','div .cont .item','click');
    $.tabChange=function(el,cont,triger){
        $(el).eq(0).addClass('on');
        $(cont).hide().eq(0).show();
        $(el).on(triger,function(){
            if(!($(this).hasClass('on'))){
                $(this).addClass('on').siblings().removeClass('on');
                var index = $(this).index();
                $(cont).hide().eq(index).fadeIn();
            }
        })
    }

    // 二级菜单切换函数
    $.menuChange=function(el,item,triger,parent){
        $(el).on(triger,function(){
            var _this = $(this);
            if(!parent){
                parent = 0;
            }
            for(var i =0;i<parent;i++){
                _this = _this.parent();
            }
            if(!(_this.hasClass('on'))){
                _this.addClass('on').siblings().removeClass('on');
                _this.find(item).slideDown();
                _this.siblings().find(item).slideUp();
            }
            else{
                _this.find(item).slideUp();
                _this.removeClass('on');
            }
        })
    }


    //默认参数
    $.fn.gallery.options = {
        //是否需要分页按钮
        pagination:false,

        //是否需要左右切换箭头按钮
        navigation:false,

        //是否需要轮播
        needPlay: true,

        //是否换行
        wrap: false,

        //切换效果 如果items>1 则其他效果不生效 只能是滑动效果
        effect: 'slide',

        //每个item之间的间距
        spaceBetween: 0,

        //是否循环轮播
        loop: false,

        //每行展示的数量
        items: 1,

        //是否监听窗口变化动态改变item的宽度
        responsive: true,

        //可以设置指定窗口宽度的items的数量、间距
        responsiveWidth: {},

        //回调函数 每次切换会触发 并且此函数的执行上下文中的this指向当前轮播对象，也就是可以调用此对象中的所有方法
        afterMove: null,

        //绑定控制 可以监听其他的轮播变化然后让此对对象也跟随变化 接受一个数组，要求数组里面传入的都是gallery.js所构造的对象
        bindControl: [],

        //是否可以点击切换当前的元素  一般用于缩略图
        clickBind: false,

        //是否开启鼠标拖拽切换轮播
        drag: true,

        //是否自动轮播
        autoPlay: false,

        //自动轮播时间
        autoPlayTime: 5000,

        //切换速度
        speed: 0.5,

        //鼠标悬停是否暂停轮播
        stopOnHover: false,

        //行间距 
        bottom: 30,

        //初始化时的index
        initIndex:0,
    }
})(jQuery, window)


