/**
 * 自由滚动容器
 * 滚动的内容加在view里面
 */
class FreeScroll extends FYGE.Container {
    constructor(viewWidth, viewHeight, maxWidth, maxHeight) {
        super()
        this.viewWidth = viewWidth
        this.viewHeight = viewHeight
        this.maxWidth = maxWidth
        this.maxHeight = maxHeight

        //鼠标事件捕捉用
        this.bg = this.addChild(new FYGE.Graphics())
            .beginFill(0x000000)
            .drawRect(0, 0, viewWidth, viewHeight)
            .endFill()
        this.bg.alpha = 0;
        //内容视图,滚动内容都加入这里
        this.view = this.addChild(new FYGE.Container());
        //x范围viewWidth-maxWidth到0，y范围viewHeight-maxHeight到0
        this.addEventListener(FYGE.MouseEvent.MOUSE_DOWN, (e) => {
            let offset = [e.stageX - this.view.x, e.stageY - this.view.y];
            //加移动事件
            this.addEventListener(FYGE.MouseEvent.MOUSE_MOVE, move, this)
            this.addEventListener(FYGE.MouseEvent.MOUSE_UP, up, this)
            this.addEventListener(FYGE.MouseEvent.MOUSE_OUT, up, this)
            //移动
            function move(me) {
                //赋值
                this.view.position.set(me.stageX - offset[0], me.stageY - offset[1])
                //x有限制
                if (this.view.x < this.viewWidth - this.maxWidth) this.view.x = this.viewWidth - this.maxWidth;
                if (this.view.x > 0) this.view.x = 0;
                //y限制
                if (this.view.y < this.viewHeight - this.maxHeight) this.view.y = this.viewHeight - this.maxHeight;
                if (this.view.y > 0) this.view.y = 0;
            }
            function up() {
                this.removeEventListener(FYGE.MouseEvent.MOUSE_MOVE, move, this);
                this.removeEventListener(FYGE.MouseEvent.MOUSE_UP, up, this);
                this.removeEventListener(FYGE.MouseEvent.MOUSE_OUT, up, this);
            }
        }, this)
    }
    scrollTo(x, y) {
        this.view.position.set(-x, -y);
        if (this.view.x < this.viewWidth - this.maxWidth) this.view.x = this.viewWidth - this.maxWidth;
        if (this.view.x > 0) this.view.x = 0;
        //y限制
        if (this.view.y < this.viewHeight - this.maxHeight) this.view.y = this.viewHeight - this.maxHeight;
        if (this.view.y > 0) this.view.y = 0;
    }
}

/**
 * fillStyle可自定义的文本
 */
class CusFillStyleText extends FYGE.TextField {
    set fillStyle(value) {
        if (this._fillStyle != value) {
            this._fillStyle = value;
            this.dirty = true;
        };
    }
    get fillStyle() {
        return this._fillStyle;
    }
    _fillStyle;
    _prepContext(ctx) {
        //@ts-ignore
        super._prepContext(ctx);
        if (this._fillStyle) ctx.fillStyle = this._fillStyle;
    }
}
//example
// var a = stage.addChild(new CusFillStyleText())
// a.text = "啊大苏打撒旦"
// a.fillStyle = FYGE.getGradientColor([0, 0, 300, 0], [
//     [0, "#ff0000", 1],
//     [0.5, "#00ff00", 1],
//     [1, "#0000ff", 1],
// ])
// a.y = 1000
// a.size = 50
class ShadowText extends FYGE.TextField {
    set shadowStyle(value) {
        this._shadowStyle = value;
        this.dirty = true;
    }
    get shadowStyle() {
        return this._shadowStyle;
    }
    _shadowStyle;
    _prepContext(ctx) {
        //@ts-ignore
        super._prepContext(ctx);
        if (this._shadowStyle) {
            ctx.shadowColor = this._shadowStyle.color;
            // 将阴影向右移动15px，向上移动10px
            ctx.shadowOffsetX = this._shadowStyle.x || 0;
            ctx.shadowOffsetY = this._shadowStyle.y || 0;
            // 轻微模糊阴影
            ctx.shadowBlur = this._shadowStyle.blur || 0;
        }
    }
}

/**
 * 背景光
 * var light = stage.addChild(new LightBg("#ff00ff"))
 */
class LightBg extends FYGE.Shape {
    /**
     * 背景光
     * @param {string} lightColor 光条颜色，默认#fffbb0
     * @param {number} lightRadius 光条半径，默认425
     * @param {number} lightNum 光条数量，默认18
     * @param {string} bgColor 背景光晕颜色，不传和lightColor相同
     * @param {number} bgRadius 背景光晕半径，不传为光条半径-25
     */
    constructor(
        lightColor = "#fffbb0",
        lightRadius = 425,
        autoRotate = false,
        lightNum = 18,
        bgColor = lightColor,
        bgRadius = lightRadius - 25
    ) {
        super();
        //最大值18，否则开放每个灯光角度
        lightNum = Math.floor(Math.min(18, lightNum));
        //底座的光晕
        this.beginGradientFill([0, 0, 0, 0, 0, bgRadius], [
            [0, bgColor, 1],
            // [0.3, "#fffbb0", 0.7],
            // [0.7, "#fffbb0", 0.3],
            [1, bgColor, 0],
        ]);
        this.drawCircle(0, 0, lightRadius)
        this.endFill()
        //径向的光
        this.beginGradientFill([0, 0, 0, 0, 0, lightRadius], [
            [0, lightColor, 1],
            [1, lightColor, 0]
        ]);
        var anglePer = Math.PI / 12;
        var delta = Math.PI * 2 / lightNum;
        for (var i = 0; i < lightNum; i++) {
            this.moveTo(0, 0)
            this.arc(0, 0, lightRadius, Math.PI * 1.5 - anglePer / 2 + delta * i, Math.PI * 1.5 + anglePer / 2 + delta * i)
        }
        this.endFill();
        if (autoRotate) {
            this.addEventListener(FYGE.Event.ENTER_FRAME, () => {
                this.rotation += 0.02
            }, this)
        }
    }
}

//纯canvas组件
class LightBgCanvas {
    constructor(
        lightColor = "#fffbb0",
        lightRadius = 425,
        autoRotate = false,
        lightNum = 18,
        bgColor = lightColor,
        bgRadius = lightRadius - 25
    ) {
        const canvas = document.createElement("canvas");
        canvas.width = canvas.height = lightRadius * 2;
        const x = lightRadius, y = x;
        const ctx = canvas.getContext("2d");
        //最大值18，否则开放每个灯光角度
        lightNum = Math.floor(Math.min(18, lightNum));
        //背景的光晕
        var colorObj = ctx.createRadialGradient(x, y, 0, x, y, bgRadius);
        colorObj.addColorStop(0, bgColor);
        colorObj.addColorStop(1, bgColor + "00");
        ctx.fillStyle = colorObj;
        ctx.beginPath();
        ctx.arc(x, y, lightRadius, 0, 2 * Math.PI)
        ctx.fill()
        //径向的光
        var colorObj = ctx.createRadialGradient(x, y, 0, x, y, lightRadius);
        colorObj.addColorStop(0, lightColor);
        colorObj.addColorStop(1, lightColor + "00");
        ctx.fillStyle = colorObj;
        ctx.beginPath();
        var anglePer = Math.PI / 12;
        var delta = Math.PI * 2 / lightNum;
        for (var i = 0; i < lightNum; i++) {
            ctx.moveTo(x, y)
            ctx.arc(x, y, lightRadius, Math.PI * 1.5 - anglePer / 2 + delta * i, Math.PI * 1.5 + anglePer / 2 + delta * i)
        }
        ctx.fill();
        if (autoRotate) {
            canvas.style.transition = "1000000000s linear"
            canvas.style["-webkit-transition"] = "1000000000s linear"
            setTimeout(() => {
                canvas.style.transform = 'rotate(36000000000deg)';
            })
        }
        return canvas
    }
}

/**
 * 文字一个一个出现
 */
export class ShowWord extends FYGE.TextField {
    /**
     * 
     * @param text 文本 例子：这里是生命值，闯关失败后\n都会扣除一点生命值
     * @param deltaTime 文字间隔时间，毫秒计
     * @param callback 播放完后的回调
     */
    playWords(text, deltaTime = 100, callback) {
        var spiltStrs = text.split("\n");
        //拆分文本
        let strs = []
        for (var i = 0; i < spiltStrs.length; i++) {
            var spiltStr = spiltStrs[i];
            var ori = "";
            var index = 0;
            while (index < i) {
                ori += spiltStrs[index];
                ori += "\n";
                index++;
            }
            for (var j = 0; j < spiltStr.length; j++) {
                var str = "" + ori;
                str += spiltStr.substring(0, j + 1)
                strs.push(str)
            }
        }
        // console.log(strs)
        //轮流替换文本
        for (let m = 0; m < strs.length; m++) {
            let str = strs[m];
            setTimeout(() => {
                this.text = str;
                if (m == strs.length - 1) {
                    callback && callback();
                }
            }, deltaTime * m)
        }
    }
}


/////////////uri解析基本用不到，考虑沉淀到其他地方后废弃decomposeDataUri
/**
 * Regexp for data URI.
 * Based on: {@link https://github.com/ragingwind/data-uri-regex}
 *
 * @static
 * @constant
 * @example data:image/png;base64
 */
const DATA_URI = /^\s*data:(?:([\w-]+)\/([\w+.-]+))?(?:;charset=([\w-]+))?(?:;(base64))?,(.*)/i;
/**
 * Split a data URI into components. Returns undefined if
 * parameter `dataUri` is not a valid data URI.
 *
 * @memberof utils
 * @function decomposeDataUri
 * @param {string} dataUri - the data URI to check
 * @return {utils~DecomposedDataUri|undefined} The decomposed data uri or undefined
 */
export function decomposeDataUri(dataUri) {
    const dataUriMatch = DATA_URI.exec(dataUri);
    if (dataUriMatch) {
        return {
            mediaType: dataUriMatch[1] ? dataUriMatch[1].toLowerCase() : undefined,
            subType: dataUriMatch[2] ? dataUriMatch[2].toLowerCase() : undefined,
            charset: dataUriMatch[3] ? dataUriMatch[3].toLowerCase() : undefined,
            encoding: dataUriMatch[4] ? dataUriMatch[4].toLowerCase() : undefined,
            data: dataUriMatch[5],
        };
    }
    return undefined;
}

//路劲后缀名解析基本用不到，考虑沉淀到其他地方后废弃getUrlFileExtension
/**
 * Regexp for image type by extension.
 *
 * @static
 * @constant
 * @type {RegExp|string}
 * @example `image.png`
 */
const URL_FILE_EXTENSION = /\.(\w{3,4})(?:$|\?|#)/i;
/**
 * 根据图片路径获取图片扩展名
 * @memberof utils
 * @function getUrlFileExtension
 * @param {string} url - the image path
 * @return {string|undefined} image extension
 */
export function getUrlFileExtension(url) {
    const extension = URL_FILE_EXTENSION.exec(url);
    if (extension) {
        return extension[1].toLowerCase();
    }
    return undefined;
}




var lastTime = Date.now(), count = 0, arr = [], requsetId;
(function aa() {
    count++;
    var time = Date.now();
    //每秒跑一次
    if (time >= lastTime + 1000) {
        var value = (count * 1000) / (time - lastTime);
        arr.push(value);
        lastTime = time;
        count = 0;
        //每分钟取平均上报一次
        if (arr.length > 60) {
            let avg = arr.reduce(function (pre, cur) {
                return pre + cur;
            }) / arr.length;
            arr.length = 0;
            //do something
            console.log(Math.round(avg))
        }
    }
    requsetId = requestAnimationFrame(aa)
})();


/**
 * 返回{ A: A, B: B }，A控制点数组，B控制点数组
 * @param points 点数组，格式[ { x: 0, y: 0 },{ x: 30, y: 0 },{ x: 30, y: -30 }],带x,y键值的对象就行
 */
export function bezierCurveControlPoint(points) {
    if (points.length > 2) {
        var A = [];
        var B = [];
        A[0] = { x: points[0].x + (points[1].x - points[0].x) / 4, y: points[0].y + (points[1].y - points[0].y) / 4 };
        B[0] = returnBControl(points, 0);
        A[points.length - 2] = returnAControl(points, points.length - 2);
        B[points.length - 2] = {
            x: points[points.length - 1].x - (points[points.length - 1].x - points[points.length - 2].x) / 4,
            y: points[points.length - 1].y - (points[points.length - 1].y - points[points.length - 2].y) / 4
        };
        for (var i = 1; i < points.length - 2; i++) {
            A[i] = returnAControl(points, i);
            B[i] = returnBControl(points, i);
        }
        return { A: A, B: B };
    }
}
function returnAControl(points, i) {
    var x = points[i].x + (points[i + 1].x - points[i - 1].x) / 4;
    var y = points[i].y + (points[i + 1].y - points[i - 1].y) / 4;
    return { x: x, y: y };
}
function returnBControl(points, i) {
    var x = points[i + 1].x - (points[i + 2].x - points[i].x) / 4;
    var y = points[i + 1].y - (points[i + 2].y - points[i].y) / 4;
    return { x: x, y: y };
}
//例子
function setPath(ctx, type) {
    var points = [
        { x: 0, y: 0 },
        { x: 30, y: 0 },
        { x: 30, y: -30 },
        { x: 60, y: -30 },
        { x: 60, y: 0 },
        { x: 90, y: 0 }];
    var AB, A, B;
    if (points.length > 2) {
        AB = bezierCurveControlPoint(points);
        A = AB.A;
        B = AB.B;
    }
    ctx.moveTo(points[0].x, points[0].y);
    for (var i = 1; i < points.length; i++) {
        if (points.length <= 2) {
            ctx.lineTo(points[i].x, points[i].y);
        } else {
            ctx.bezierCurveTo(A[i - 1].x, A[i - 1].y, B[i - 1].x, B[i - 1].y, points[i].x, points[i].y);
        }
    }
}

////////
/**
 * 判断一系列点的顺逆时针方向，以后有需要用吧
 * @see {@link https://stackoverflow.com/questions/1165647}
 * 1、向量首尾相连，计算所有相邻向量的叉乘的和，正号逆时针（右手定则）
 * 2、以(0,0)为原点，每两个点作为两个向量，叉乘的和就是面积的两倍，符号表示方向（同1）
 * 3、下面这种 (x2 − x1)(y2 + y1).看不懂原理，但是计算过是一致的，正号顺时针（与上两种相反）
 * @param {ArrayLike<number>} points 一维点序列，比如[0,0,1,1,0,2]
 * @param {boolean} closed 是否连回起始点,默认false
 * @returns true表示顺时针，false表示逆时针
 */
export function isPointsClockwise(points, closed = false) {
    let sum = 0;
    for (let i = 0; i < points.length - 2; i += 2) {
        sum += (points[i + 2] - points[i]) * (points[i + 3] + points[i + 1]);
    }
    //是否连回原点
    if (closed) sum += (points[0] - points[points.length - 2]) * (points[1] + points[points.length - 1]);

    // return sum > 0;
    //当前2d坐标系，y轴朝下为正，所以判断反下，
    return sum < 0;
}