var cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame;
var requestFrame = window.requestAnimationFrame;
var time = !window.performance || !window.performance.now ?
    function () {return +new Date()}:
    function () {return performance.now()};

/**
 * 计算两点距离
 * @param points
 * @returns {number}
 * distance([{x:0,y:0},{x:1,y:1}]);
 */
var distance = function(points) {
    var p1=points[0];
    var p2=points[1];
    var a = p2.x-p1.x;
    var b = p2.y-p1.y;
    return Math.sqrt(a*a+b*b);
};

/**
 * 圆公式
 * @param rotation 弧度
 * 计算公式：
 * Math.PI;     //圆周率
 * Math.sin();  //正弦 x      -左 +右
 * Math.cos;    //余弦 y      -下 +上
 */
var circleMath = {
    /**
     * 根据弧度计算角度
     * @param rotation 弧度
     * rotation, farScale, xs, xr, ys, yr, itemWidth
     */
    // parseRotate: function (rotation) {
    //     return (180 / Math.PI * rotation) - 180;
    // },
    parseRotate: function (rotation, self) {
        var sin = Math.sin(rotation), cos = Math.cos(rotation);
        var sin_cos = sin*cos;  //得出偏移正负值，从0°向左依次 +-+-
        var angle = (180 / Math.PI * rotation) - 180;
        var lastAngle = angle;

        // console.log('rotation',rotation)
        // console.log('sin',sin)
        // console.log('cos',cos)
        // console.log('sin*cos',sin*cos);
        // console.log('统一偏移角度',self.yr * (sin_cos/Math.PI))

        lastAngle = angle + (self.yr * (sin_cos/(Math.PI+1)));

        return lastAngle;
    },
    /**
     * 计算scale,x,y
     * scale    最小尺寸 + ((1 - 最小尺寸) * (sin正弦 + 1) * 0.5)
     * x        x起点 + (尺寸 * cos余弦 * x半径) - 元素宽度一半
     * y        y起点 + (尺寸 * sin正弦 * x半径) - 元素宽度一半
     * farScale, xs, xr, ys, yr, itemWidth
     */
    parseSXY: function (rotation, self) {
        var farScale=self.farScale;
        var itemWidth=self.itemWidth;
        var xs=self.xs; var xr=self.xr; var ys=self.ys; var yr=self.yr;
        var sin = Math.sin(rotation), cos = Math.cos(rotation);
        var scale = farScale + ((1 - farScale) * (sin + 1) * 0.5);  //单个尺寸

        // 按设置尺寸
        // var x = xs + (scale * cos * xr) - (itemWidth * 0.5);
        // var y = ys + (scale * sin * yr) - (itemWidth * 0.5);
        // 不使用压缩
        // var x = xs + (cos * xs) - (itemWidth * 0.5);
        // var y = ys + (sin * ys) - (itemWidth * 0.5);
        // 使用压缩
        var x = xs + (cos * xr) - (itemWidth * 0.5);
        var y = ys + (sin * yr) - (itemWidth * 0.5);
        var distanceNumber = distance([
            {x:self.$rotation.width()/2 - self.$item.width()/2, y:self.$rotation.height()/2 - self.$item.height()/2},
            {x:x,y:y}]
        );

        // console.log({x:self.$rotation.width()/2, y:self.$rotation.height()/2})
        // console.log('x,y',x,y)
        // console.log('两点距离',distanceNumber)

        return {
            x: x,
            y: y,
            scale: scale,
            distanceNumber: distanceNumber,
        }
    },
}
/**
 * 3D旋转
 * @param id
 */
var Rotation3D = window.Rotation3D = function (_opts) {
    var self=this;
    this.$rotation = $(_opts.id)
    this.$lineList = this.$rotation.find('.lineList')
    this.$item = this.$rotation.find('.rotation3D__item')
    this.$line = this.$rotation.find('.rotation3D__line')
    this.itemWidth = this.$item.width();
    this.itemHeight = this.$item.height();
    this.length = this.$item.length;
    // 圆计算
    this.rotation = Math.PI / 2;    //圆周率/2
    this.destRotation = this.rotation;

    var xr = this.$rotation.width() * 0.5;
    var yr = this.$rotation.height() * 0.5;
    var xRadius = _opts.xRadius || 0;
    var yRadius = _opts.yRadius || 0;

    var opts = Object.assign({
        farScale: 1,        // 最小尺寸
        xs: xr,             // x起点
        ys: yr,             // y起点
        xr: xr - xRadius,   // x半径-压缩
        yr: yr - yRadius,	// y半径-压缩
        // 播放
        autoPlay:false,
        autoPlayDelay:3000,
        currenIndex:-1,
        fps:30,
        speed:4,
    },_opts)
    Object.assign(this, opts)

    // 遍历子元素
    this.$item.each(function (index) {
        $(this).click(function () {
            $(this).addClass('active').siblings().removeClass('active')
            self.goTo(index)
        })
    })
    // 当前控件进入离开
    this.$rotation.mouseenter(function () {
        clearInterval(self.autoPlayTimer)
    })
    this.$rotation.mouseleave(function () {
        self.onAutoPlay()
    })

    this.onAutoPlay()
    this.onDrag()
    this.render()

}
/**
 * item样式
 * x    x起点 + (尺寸 * 余弦 * x压缩) - 元素宽度一半
 * y    y起点 + (尺寸 * 正弦 * y压缩) - 元素宽度一半
 */
Rotation3D.prototype.itemStyle = function($item, index, rotation) {
    //console.log("itemStyle=" + rotation + " index=" + index);
    var parseSXY = circleMath.parseSXY(rotation, this);
    var scale = parseSXY.scale;
    var x = parseSXY.x;
    var y = parseSXY.y;
    var $line = this.$lineList.find('.rotation3D__line').eq(index);

    //设置当前子菜单的位置（left,top） = (x,y)
    $item.find('.scale').css({
        'transform': `scale(${scale})`,
        // 'top': `${this.itemWidth * (1-scale) }`,
    })
    $item.css({
        position: 'absolute',
        display: 'inline-block',
        // opacity: scale,
        'z-index': parseInt(scale * 100),
        'transform-origin': '0px 0px',
        // 'transform': `translate(${x}px, ${y}px) scale(${scale})`,
        'transform': `translate(${x}px, ${y}px)`,
    });

    /**
     * 线样式
     */
    $line.css({
        height:parseSXY.distanceNumber,
    })
    $line.find('svg').css({
        height:parseSXY.distanceNumber,
    })
    $line.find('.dot1').css({
        'offset-path':`path("M0 ${parseSXY.distanceNumber}, 0 0")`,
    })
    $line.find('#path1').attr({
        'd':`M0 ${parseSXY.distanceNumber}, 0 0`,
    })

    $line.find('.dot2').css({
        'offset-path':`path("M0 ${parseSXY.distanceNumber/2}, 0 0")`,
    })
    $line.find('#path2').attr({
        'd':`M0 ${parseSXY.distanceNumber}, 0 0`,
    })

    $line.find('.dot3').css({
        'offset-path':`path("M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0")`,
    })
    $line.find('#path3').attr({
        'd':`M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0`,
    })

    $line.find('.dot4').css({
        'offset-path':`path("M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}")`,
    })
    $line.find('#path4').attr({
        'd':`M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}`,
    })

}
/**
 * line样式
 */
Rotation3D.prototype.lineStyle = function($line, index, rotation) {
    var rotate = circleMath.parseRotate(rotation, this)
    //console.log("lineStyle=" + rotation + " index=" + index);

    $line.css({
        transform: 'rotate(' + rotate + 'deg)',
    })
    this.$lineList.css({
        // transform: `rotateX(${this.yRadius / 3}deg)`,
    })
}

/**
 * 旋转至index
 */
Rotation3D.prototype.goTo = function (index) {
    var self = this;
    this.currenIndex = index;
    //console.log('goTo currenIndex', index);
    /**
     * 1.计算floatIndex,用于控死amdiff
     */
    var itemsRotated = this.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI);
    var floatIndex = itemsRotated % this.length;
    if (floatIndex < 0) { floatIndex = floatIndex + this.length; }

    /**
     * 2.计算diff,判断方向正反
     */
    var diff = index - (floatIndex % this.length);
    if (2 * Math.abs(diff) > this.length) {
        diff -= (diff > 0) ? this.length : -this.length;
    }
    // 停止任何正在进行的旋转
    this.destRotation += (2 * Math.PI / this.length) * -diff;
    this.scheduleNextFrame();

}
/**
 * 定时器渐近旋转
 */
Rotation3D.prototype.scheduleNextFrame = function () {
    var self = this
    this.lastTime = time();
    // 暂停
    var pause = function () {
        cancelFrame ? cancelFrame(this.timer) : clearTimeout(self.timer);
        self.timer = 0;
    }
    // 渐进播放
    var playFrame = function () {
        var rem = self.destRotation - self.rotation;
        var now = time(), dt = (now - self.lastTime) * 0.002;
        self.lastTime = now;
        // console.log('rem',rem)

        if (Math.abs(rem) < 0.003) {
            self.rotation = self.destRotation;
            pause();
        } else {
            // 渐近地接近目的地
            self.rotation = self.destRotation - rem / (1 + (self.speed * dt));
            self.scheduleNextFrame();
        }
        self.render();
    }

    this.timer = cancelFrame ?
        requestFrame(playFrame) :
        setTimeout(playFrame, 1000 / this.fps);
}
/**
 * 更新
 */
Rotation3D.prototype.render = function () {
    var self=this;
    
    // 图形间隔：弧度
    var spacing = 2 * Math.PI / this.$item.length;
    var itemRotation = this.rotation;
    var lineRotation = this.rotation + (Math.PI/2);

    this.$item.each(function (index) {
        self.itemStyle($(this), index, itemRotation)
        itemRotation += spacing;
    })
    this.$line.each(function (index) {
        self.lineStyle($(this), index, lineRotation)
        lineRotation += spacing;
    })
}
/**
 * 自动播放
 */
Rotation3D.prototype.onAutoPlay = function () {
    var self = this;

    if (this.autoPlay) {
        this.autoPlayTimer = setInterval(function () {
            if (self.currenIndex < 0) {
                self.currenIndex = self.length - 1
            }
            //console.log("autoPlayTimer....");
            self.goTo(self.currenIndex);
            self.currenIndex--; //倒叙
        }, this.autoPlayDelay)
    }
}
/**
 * 拖拽
 */
Rotation3D.prototype.onDrag = function () {
    var self = this;
    var startX, startY, moveX, moveY, endX, endY;
    //console.log("onDrag....");
    // 拖拽：三个事件-按下 移动 抬起
    //按下
    this.$rotation.mousedown(function (e) {
        startX = e.pageX; startY = e.pageY;
        //console.log("mousedown....");
        // 移动
        $(document).mousemove(function (e) {
            // console.log('移动');
            endX = e.pageX; endY = e.pageY;
            moveX = endX - startX; moveY = endY - startY;
            // console.log('x,y',moveX,moveY);
        })
        // 抬起
        $(document).mouseup(function (e) {
            endX = e.pageX; endY = e.pageY;
            moveX = endX - startX; moveY = endY - startY;
            //console.log("mouseup....");
            // 每40旋转一步
            var moveIndex = parseInt(Math.abs(moveX) / 50)
            //console.log('moveIndex',moveIndex)
            if (moveIndex > 0) {
                // console.log(moveX<0 ? '向左' : '向右')
                if (moveX < 0) { //向左
                    self.currenIndex = self.currenIndex - moveIndex
                    play(moveIndex)
                } else { //向右
                    self.currenIndex = self.currenIndex + moveIndex
                    play(moveIndex)
                }
            }

            // 解绑
            $(document).unbind("mousemove");
            $(document).unbind("mouseup");
        })

    })

    function play() {
        if (self.currenIndex == 0) {
            self.currenIndex = self.length - 1
        }
        self.goTo(self.currenIndex % self.length);
    }

}